diff --git a/src/Makefile.am b/src/Makefile.am
index 5942b2c899f3091ec2200940597b3ec246fd771f..e8d873e7390ff935839f913e6c06d7a128cf1b03 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -24,7 +24,7 @@ IM_LIBA=./im/libim.la
 IM_LIB=@EXPAT_LIBS@
 endif
 
-# Redefine the USE_IAX variable here, so that it could be used in managerimpl
+# Redefine the USE_IAX variable here, so that it could be used in manager
 if USE_IAX
 IAX_SUBDIR=iax
 IAX_CXXFLAG=-DUSE_IAX
@@ -104,7 +104,6 @@ libring_la_SOURCES = conference.cpp \
 		account_factory.cpp \
 		call_factory.cpp \
 		preferences.cpp \
-		managerimpl.cpp \
 		manager.cpp \
 		call.cpp \
 		account.cpp \
@@ -127,7 +126,6 @@ libring_la_SOURCES = conference.cpp \
 		account_factory.h \
 		call_factory.h \
 		preferences.h \
-		managerimpl.h \
 		manager.h \
 		account.h \
 		call.h \
diff --git a/src/manager.cpp b/src/manager.cpp
index e5c92b9692240c567265b1af32da5db4072f7d52..38b532fe836f6b6788dc44feffcb482d55a7319d 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -1,6 +1,13 @@
 /*
  *  Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
- *  Author : Tristan Matthews <tristan.matthews@savoirfairelinux.com>
+ *  Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
+ *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *  Author: Tristan Matthews <tristan.matthews@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,22 +35,2902 @@
  *  as that of the covered work.
  */
 
-#include "manager.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include "logger.h"
+#include "manager.h"
+#include "account_schema.h"
+#include "plugin_manager.h"
+
+#include "fileutils.h"
+#include "map_utils.h"
+#include "account.h"
+#include "string_utils.h"
+#if HAVE_DHT
+#include "ringdht/ringaccount.h"
+#endif
+
+#include "call_factory.h"
+
+#include "sip/sip_utils.h"
+
+#include "im/instant_messaging.h"
+
+#include "numbercleaner.h"
+#include "config/yamlparser.h"
+
+#if HAVE_ALSA
+#include "audio/alsa/alsalayer.h"
+#endif
+
+#include "audio/sound/tonelist.h"
+#include "audio/sound/audiofile.h"
+#include "audio/sound/dtmf.h"
+#include "audio/ringbufferpool.h"
+#include "manager.h"
+
+#ifdef RING_VIDEO
+#include "client/videomanager.h"
+#endif
+
+#include "conference.h"
+#include "ice_transport.h"
+
+#include "client/ring_signal.h"
+
+#if HAVE_TLS
+#include "gnutls_support.h"
+#endif
+
+#include "libav_utils.h"
+#include "video/sinkclient.h"
+
+#include <cerrno>
+#include <algorithm>
+#include <ctime>
+#include <cstdlib>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <sys/types.h> // mkdir(2)
+#include <sys/stat.h>  // mkdir(2)
+#include <memory>
+#include <mutex>
 
 namespace ring {
 
-ManagerImpl& Manager::instance()
+std::atomic_bool Manager::initialized = {false};
+
+static void
+copy_over(const std::string &srcPath, const std::string &destPath)
+{
+    std::ifstream src(srcPath.c_str());
+    std::ofstream dest(destPath.c_str());
+    dest << src.rdbuf();
+    src.close();
+    dest.close();
+}
+
+// Creates a backup of the file at "path" with a .bak suffix appended
+static void
+make_backup(const std::string &path)
+{
+    const std::string backup_path(path + ".bak");
+    copy_over(path, backup_path);
+}
+
+// Restore last backup of the configuration file
+static void
+restore_backup(const std::string &path)
+{
+    const std::string backup_path(path + ".bak");
+    copy_over(backup_path, path);
+}
+
+/**
+ * Set pjsip's log level based on the SIPLOGLEVEL environment variable.
+ * SIPLOGLEVEL = 0 minimum logging
+ * SIPLOGLEVEL = 6 maximum logging
+ */
+
+/** Environment variable used to set pjsip's logging level */
+static constexpr const char* SIPLOGLEVEL = "SIPLOGLEVEL";
+
+static void
+setSipLogLevel()
+{
+    char* envvar = getenv(SIPLOGLEVEL);
+    int level = 0;
+
+    if (envvar != nullptr) {
+        if (not (std::istringstream(envvar) >> level))
+            level = 0;
+
+        // From 0 (min) to 6 (max)
+        level = std::max(0, std::min(level, 6));
+    }
+
+    pj_log_set_level(level);
+}
+
+#if HAVE_TLS
+/**
+ * Set gnutls's log level based on the RING_TLS_LOGLEVEL environment variable.
+ * RING_TLS_LOGLEVEL = 0 minimum logging (default)
+ * RING_TLS_LOGLEVEL = 9 maximum logging
+ */
+
+static constexpr int RING_TLS_LOGLEVEL = 0;
+
+static void
+tls_print_logs(int level, const char* msg)
+{
+    RING_DBG("GnuTLS [%d]: %s", level, msg);
+}
+
+static void
+setGnuTlsLogLevel()
+{
+    char* envvar = getenv("RING_TLS_LOGLEVEL");
+    int level = RING_TLS_LOGLEVEL;
+
+    if (envvar != nullptr) {
+        int var_level;
+        if (std::istringstream(envvar) >> var_level)
+            level = var_level;
+
+        // From 0 (min) to 9 (max)
+        level = std::max(0, std::min(level, 9));
+    }
+
+    gnutls_global_set_log_level(level);
+    gnutls_global_set_log_function(tls_print_logs);
+}
+#endif // HAVE_TLS
+
+Manager&
+Manager::instance()
 {
     // Meyers singleton
-    static ManagerImpl instance_;
+    static Manager instance_;
 
     // This will give a warning that can be ignored the first time instance()
     // is called...subsequent warnings are more serious
-    if (not ManagerImpl::initialized)
+    if (not Manager::initialized)
         RING_WARN("Not initialized");
 
     return instance_;
 }
 
+void
+Manager::loadDefaultAccountMap()
+{
+    accountFactory_.initIP2IPAccount();
+}
+
+Manager::Manager() :
+    pluginManager_(new PluginManager)
+    , preferences(), voipPreferences(),
+    hookPreference(),  audioPreference(), shortcutPreferences(),
+    hasTriedToRegister_(false),
+    currentCallMutex_(), dtmfKey_(), dtmfBuf_(0, AudioFormat::MONO()),
+    toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(),
+    waitingCalls_(), waitingCallsMutex_(), path_()
+    , ringbufferpool_(new RingBufferPool)
+    , callFactory(), conferenceMap_()
+    , accountFactory_(), ice_tf_()
+    , gnutlGIG_ {tls::GnuTlsGlobalInit::make_guard()}
+{
+    // initialize random generator
+    // mt19937_64 should be seeded with 2 x 32 bits
+    std::random_device rdev;
+    std::seed_seq seed {rdev(), rdev()};
+    rand_.seed(seed);
+
+    ring::libav_utils::ring_avcodec_init();
+}
+
+Manager::~Manager()
+{}
+
+bool
+Manager::parseConfiguration()
+{
+    bool result = true;
+
+    try {
+        YAML::Node parsedFile = YAML::LoadFile(path_);
+        const int error_count = loadAccountMap(parsedFile);
+
+        if (error_count > 0) {
+            RING_WARN("Errors while parsing %s", path_.c_str());
+            result = false;
+        }
+    } catch (const YAML::BadFile &e) {
+        RING_WARN("Could not open config file: creating default account map");
+        loadDefaultAccountMap();
+    }
+
+    return result;
+}
+
+void
+Manager::init(const std::string &config_file)
+{
+    // FIXME: this is no good
+    initialized = true;
+
+#define PJSIP_TRY(ret) do {                                 \
+        if (ret != PJ_SUCCESS)                               \
+            throw std::runtime_error(#ret " failed");        \
+    } while (0)
+
+    srand(time(NULL)); // to get random number for RANDOM_PORT
+
+    // Initialize PJSIP (SIP and ICE implementation)
+    PJSIP_TRY(pj_init());
+    setSipLogLevel();
+    PJSIP_TRY(pjlib_util_init());
+    PJSIP_TRY(pjnath_init());
+#undef TRY
+
+    RING_DBG("pjsip version %s for %s initialized",
+             pj_get_version(), PJ_OS_NAME);
+
+#if HAVE_TLS
+    setGnuTlsLogLevel();
+    RING_DBG("GNU TLS version %s initialized", gnutls_check_version(nullptr));
+#endif
+
+    ice_tf_.reset(new IceTransportFactory());
+
+    path_ = config_file.empty() ? retrieveConfigPath() : config_file;
+    RING_DBG("Configuration file path: %s", path_.c_str());
+
+    bool no_errors = true;
+
+    // manager can restart without being recreated (android)
+    finished_ = false;
+
+    try {
+        no_errors = parseConfiguration();
+    } catch (const YAML::Exception &e) {
+        RING_ERR("%s", e.what());
+        no_errors = false;
+    }
+
+    // always back up last error-free configuration
+    if (no_errors) {
+        make_backup(path_);
+    } else {
+        // restore previous configuration
+        RING_WARN("Restoring last working configuration");
+
+        try {
+            // remove accounts from broken configuration
+            removeAccounts();
+            restore_backup(path_);
+            parseConfiguration();
+        } catch (const YAML::Exception &e) {
+            RING_ERR("%s", e.what());
+            RING_WARN("Restoring backup failed, creating default account map");
+            loadDefaultAccountMap();
+        }
+    }
+
+    initAudioDriver();
+
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        if (audiodriver_) {
+            {
+                std::lock_guard<std::mutex> toneLock(toneMutex_);
+                telephoneTone_.reset(new TelephoneTone(preferences.getZoneToneChoice(), audiodriver_->getSampleRate()));
+            }
+            dtmfKey_.reset(new DTMF(getRingBufferPool().getInternalSamplingRate()));
+        }
+    }
+
+    registerAccounts();
+}
+
+void
+Manager::setPath(const std::string&)
+{
+    // FIME: needed?
+}
+
+void
+Manager::finish() noexcept
+{
+    bool expected = false;
+    if (not finished_.compare_exchange_strong(expected, true))
+        return;
+
+    try {
+        // Forbid call creation
+        callFactory.forbid();
+
+        // Hangup all remaining active calls
+        RING_DBG("Hangup %zu remaining call(s)", callFactory.callCount());
+        for (const auto call : callFactory.getAllCalls())
+            hangupCall(call->getCallId());
+        callFactory.clear();
+
+        saveConfig();
+
+        // Disconnect accounts, close link stacks and free allocated ressources
+        unregisterAccounts();
+        accountFactory_.clear();
+
+        {
+            std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+            audiodriver_.reset();
+        }
+
+        ice_tf_.reset();
+        pj_shutdown();
+    } catch (const VoipLinkException &err) {
+        RING_ERR("%s", err.what());
+    }
+}
+
+bool
+Manager::isCurrentCall(const Call& call) const
+{
+    return currentCall_.get() == &call;
+}
+
+bool
+Manager::hasCurrentCall() const
+{
+    return static_cast<bool>(currentCall_);
+}
+
+std::shared_ptr<Call>
+Manager::getCurrentCall() const
+{
+    return currentCall_;
+}
+
+const std::string
+Manager::getCurrentCallId() const
+{
+    return currentCall_ ? currentCall_->getCallId() : "";
+}
+
+/**
+ * Set current call ID to empty string
+ */
+void
+Manager::unsetCurrentCall()
+{
+    currentCall_.reset();
+}
+
+/**
+ * Switch of current call id
+ * @param id The new callid
+ */
+void
+Manager::switchCall(std::shared_ptr<Call> call)
+{
+    std::lock_guard<std::mutex> m(currentCallMutex_);
+    RING_DBG("----- Switch current call id to '%s' -----",
+          call ? call->getCallId().c_str() : "<nullptr>");
+    currentCall_ = call;
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Management of events' IP-phone user
+///////////////////////////////////////////////////////////////////////////////
+/* Main Thread */
+
+std::string
+Manager::outgoingCall(const std::string& preferred_account_id,
+                          const std::string& to,
+                          const std::string& conf_id)
+{
+    std::string current_call_id(getCurrentCallId());
+    std::string prefix(hookPreference.getNumberAddPrefix());
+    std::string to_cleaned(NumberCleaner::clean(to, prefix));
+    std::shared_ptr<Call> call;
+
+    try {
+        /* RING_WARN: after this call the account_id is obsolete
+         * as the factory may decide to use another account (like IP2IP).
+         */
+        RING_DBG("New outgoing call to %s", to_cleaned.c_str());
+        call = newOutgoingCall(to_cleaned, preferred_account_id);
+    } catch (const std::exception &e) {
+        RING_ERR("%s", e.what());
+        return {};
+    }
+
+    if (not call)
+        return {};
+
+    auto call_id = call->getCallId();
+
+    stopTone();
+
+    // in any cases we have to detach from current communication
+    if (hasCurrentCall()) {
+        RING_DBG("Has current call (%s) put it onhold", current_call_id.c_str());
+
+        // if this is not a conference and this and is not a conference participant
+        if (not isConference(current_call_id) and not isConferenceParticipant(current_call_id))
+            onHoldCall(current_call_id);
+        else if (isConference(current_call_id) and not isConferenceParticipant(call_id))
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+    }
+
+    switchCall(call);
+    call->setConfId(conf_id);
+
+    return call_id;
+}
+
+//THREAD=Main : for outgoing Call
+bool
+Manager::answerCall(const std::string& call_id)
+{
+    bool result = true;
+
+    auto call = getCallFromCallID(call_id);
+    if (!call) {
+        RING_ERR("Call %s is NULL", call_id.c_str());
+        return false;
+    }
+
+    // If ring is ringing
+    stopTone();
+
+    // store the current call id
+    std::string current_call_id(getCurrentCallId());
+
+    // in any cases we have to detach from current communication
+    if (hasCurrentCall()) {
+
+        RING_DBG("Currently conversing with %s", current_call_id.c_str());
+
+        if (not isConference(current_call_id) and not isConferenceParticipant(current_call_id)) {
+            RING_DBG("Answer call: Put the current call (%s) on hold", current_call_id.c_str());
+            onHoldCall(current_call_id);
+        } else if (isConference(current_call_id) and not isConferenceParticipant(call_id)) {
+            // if we are talking to a conference and we are answering an incoming call
+            RING_DBG("Detach main participant from conference");
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+        }
+    }
+
+    try {
+        call->answer();
+    } catch (const std::runtime_error &e) {
+        RING_ERR("%s", e.what());
+        result = false;
+    }
+
+    // if it was waiting, it's waiting no more
+    removeWaitingCall(call_id);
+
+    // if we dragged this call into a conference already
+    if (isConferenceParticipant(call_id))
+        switchCall(callFactory.getCall(call->getConfId()));
+    else
+        switchCall(call);
+
+    // Connect streams
+    addStream(*call);
+
+    // Start recording if set in preference
+    if (audioPreference.getIsAlwaysRecording())
+        toggleRecordingCall(call_id);
+
+    //callStateChanged(call_id, "CURRENT");
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "CURRENT", 0);
+
+    return result;
+}
+
+void
+Manager::checkAudio()
+{
+    if (getCallList().empty()) {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+        if (audiodriver_)
+            audiodriver_->stopStream();
+    }
+}
+
+//THREAD=Main
+bool
+Manager::hangupCall(const std::string& callId)
+{
+    // store the current call id
+    std::string currentCallId(getCurrentCallId());
+
+    stopTone();
+
+    RING_DBG("Send call state change (HUNGUP) for id %s", callId.c_str());
+    emitSignal<DRing::CallSignal::StateChange>(callId, "HUNGUP", 0);
+
+    /* We often get here when the call was hungup before being created */
+    auto call = getCallFromCallID(callId);
+    if (not call) {
+        RING_WARN("Could not hang up non-existant call %s", callId.c_str());
+        checkAudio();
+        return false;
+    }
+
+    // Disconnect streams
+    removeStream(*call);
+
+    if (isConferenceParticipant(callId)) {
+        removeParticipant(callId);
+    } else {
+        // we are not participating in a conference, current call switched to ""
+        if (not isConference(currentCallId))
+            unsetCurrentCall();
+    }
+
+    try {
+        call->hangup(0);
+        checkAudio();
+    } catch (const VoipLinkException &e) {
+        RING_ERR("%s", e.what());
+        return false;
+    }
+
+    return true;
+}
+
+bool
+Manager::hangupConference(const std::string& id)
+{
+    RING_DBG("Hangup conference %s", id.c_str());
+
+    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
+
+    if (iter_conf != conferenceMap_.end()) {
+        auto conf = iter_conf->second;
+
+        if (conf) {
+            ParticipantSet participants(conf->getParticipantList());
+
+            for (const auto &item : participants)
+                hangupCall(item);
+        } else {
+            RING_ERR("No such conference %s", id.c_str());
+            return false;
+        }
+    }
+
+    unsetCurrentCall();
+
+    return true;
+}
+
+//THREAD=Main
+bool
+Manager::onHoldCall(const std::string& callId)
+{
+    bool result = true;
+
+    stopTone();
+
+    std::string current_call_id(getCurrentCallId());
+
+    if (auto call = getCallFromCallID(callId)) {
+        try {
+            call->onhold();
+            removeStream(*call); // Unbind calls in main buffer
+        } catch (const VoipLinkException &e) {
+            RING_ERR("%s", e.what());
+            result = false;
+        }
+    } else {
+        RING_DBG("CallID %s doesn't exist in call onHold", callId.c_str());
+        return false;
+    }
+
+    // Remove call from teh queue if it was still there
+    removeWaitingCall(callId);
+
+    // keeps current call id if the action is not holding this call or a new outgoing call
+    // this could happen in case of a conference
+    if (current_call_id == callId)
+        unsetCurrentCall();
+
+    emitSignal<DRing::CallSignal::StateChange>(callId, "HOLD", 0);
+
+    return result;
+}
+
+//THREAD=Main
+bool
+Manager::offHoldCall(const std::string& callId)
+{
+    bool result = true;
+
+    stopTone();
+
+    const std::string currentCallId(getCurrentCallId());
+
+    // Place current call on hold if it isn't
+    if (hasCurrentCall()) {
+        if (not isConference(currentCallId) and not isConferenceParticipant(currentCallId)) {
+            RING_DBG("Has current call (%s), put on hold", currentCallId.c_str());
+            //FIXME: ebail
+            // if 2 consecutive offHoldCall done, the second one should be ignored (already offhold)
+            // this call put the call onHold
+            onHoldCall(currentCallId);
+        } else if (isConference(currentCallId) && callId != currentCallId) {
+            holdConference(currentCallId);
+        } else if (isConference(currentCallId) and not isConferenceParticipant(callId))
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+    }
+
+    std::shared_ptr<Call> call;
+    try {
+        call = getCallFromCallID(callId);
+        if (call)
+            call->offhold();
+        else
+            result = false;
+    } catch (const VoipLinkException &e) {
+        RING_ERR("%s", e.what());
+        return false;
+    }
+
+    emitSignal<DRing::CallSignal::StateChange>(callId, "UNHOLD", 0);
+
+    if (isConferenceParticipant(callId))
+        switchCall(getCallFromCallID(call->getConfId()));
+    else
+        switchCall(call);
+
+    addStream(*call);
+
+    return result;
+}
+
+bool
+Manager::muteMediaCall(const std::string& callId, const std::string& mediaType, bool is_muted)
+{
+    if (auto call = getCallFromCallID(callId)) {
+        call->muteMedia(mediaType, is_muted);
+        return true;
+    } else {
+        RING_DBG("CallID %s doesn't exist in call muting", callId.c_str());
+        return false;
+    }
+}
+
+
+//THREAD=Main
+bool
+Manager::transferCall(const std::string& callId, const std::string& to)
+{
+    if (isConferenceParticipant(callId)) {
+        removeParticipant(callId);
+    } else if (not isConference(getCurrentCallId()))
+        unsetCurrentCall();
+
+    if (auto call = getCallFromCallID(callId))
+        call->transfer(to);
+    else
+        return false;
+
+    // remove waiting call in case we make transfer without even answer
+    removeWaitingCall(callId);
+
+    return true;
+}
+
+void
+Manager::transferFailed()
+{
+    emitSignal<DRing::CallSignal::TransferFailed>();
+}
+
+void
+Manager::transferSucceeded()
+{
+    transferSucceeded();
+}
+
+bool
+Manager::attendedTransfer(const std::string& transferID,
+                              const std::string& targetID)
+{
+    if (auto call = getCallFromCallID(transferID))
+        return call->attendedTransfer(targetID);
+
+    return false;
+}
+
+//THREAD=Main : Call:Incoming
+bool
+Manager::refuseCall(const std::string& id)
+{
+    auto call = getCallFromCallID(id);
+    if (!call)
+        return false;
+
+    stopTone();
+
+    if (getCallList().size() <= 1) {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+        audiodriver_->stopStream();
+    }
+
+    call->refuse();
+
+    checkAudio();
+
+    removeWaitingCall(id);
+
+    emitSignal<DRing::CallSignal::StateChange>(id, "HUNGUP", 0);
+
+    // Disconnect streams
+    removeStream(*call);
+
+    return true;
+}
+
+std::shared_ptr<Conference>
+Manager::createConference(const std::string& id1, const std::string& id2)
+{
+    RING_DBG("Create conference with call %s and %s", id1.c_str(), id2.c_str());
+
+    auto conf = std::make_shared<Conference>();
+
+    conf->add(id1);
+    conf->add(id2);
+
+    // Add conference to map
+    conferenceMap_.insert(std::make_pair(conf->getConfID(), conf));
+
+    emitSignal<DRing::CallSignal::ConferenceCreated>(conf->getConfID());
+
+    return conf;
+}
+
+void
+Manager::removeConference(const std::string& conference_id)
+{
+    RING_DBG("Remove conference %s", conference_id.c_str());
+    RING_DBG("number of participants: %u", conferenceMap_.size());
+    ConferenceMap::iterator iter = conferenceMap_.find(conference_id);
+
+    std::shared_ptr<Conference> conf;
+
+    if (iter != conferenceMap_.end())
+        conf = iter->second;
+
+    if (not conf) {
+        RING_ERR("Conference not found");
+        return;
+    }
+
+    emitSignal<DRing::CallSignal::ConferenceRemoved>(conference_id);
+
+    // We now need to bind the audio to the remain participant
+
+    // Unbind main participant audio from conference
+    getRingBufferPool().unBindAll(RingBufferPool::DEFAULT_ID);
+
+    ParticipantSet participants(conf->getParticipantList());
+
+    // bind main participant audio to remaining conference call
+    ParticipantSet::iterator iter_p = participants.begin();
+
+    if (iter_p != participants.end())
+        getRingBufferPool().bindCallID(*iter_p, RingBufferPool::DEFAULT_ID);
+
+    // Then remove the conference from the conference map
+    if (conferenceMap_.erase(conference_id))
+        RING_DBG("Conference %s removed successfully", conference_id.c_str());
+    else
+        RING_ERR("Cannot remove conference: %s", conference_id.c_str());
+}
+
+std::shared_ptr<Conference>
+Manager::getConferenceFromCallID(const std::string& call_id)
+{
+    auto call = getCallFromCallID(call_id);
+    if (!call)
+        return nullptr;
+
+    ConferenceMap::const_iterator iter(conferenceMap_.find(call->getConfId()));
+
+    if (iter != conferenceMap_.end())
+        return iter->second;
+    else
+        return nullptr;
+}
+
+bool
+Manager::holdConference(const std::string& id)
+{
+    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
+
+    if (iter_conf == conferenceMap_.end())
+        return false;
+
+    auto conf = iter_conf->second;
+
+    bool isRec = conf->getState() == Conference::ACTIVE_ATTACHED_REC or
+                 conf->getState() == Conference::ACTIVE_DETACHED_REC or
+                 conf->getState() == Conference::HOLD_REC;
+
+    ParticipantSet participants(conf->getParticipantList());
+
+    for (const auto &item : participants) {
+        switchCall(getCallFromCallID(item));
+        onHoldCall(item);
+    }
+
+    conf->setState(isRec ? Conference::HOLD_REC : Conference::HOLD);
+
+    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
+
+    return true;
+}
+
+bool
+Manager::unHoldConference(const std::string& id)
+{
+    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
+
+    if (iter_conf == conferenceMap_.end() or iter_conf->second == 0)
+        return false;
+
+    auto conf = iter_conf->second;
+
+    bool isRec = conf->getState() == Conference::ACTIVE_ATTACHED_REC or
+        conf->getState() == Conference::ACTIVE_DETACHED_REC or
+        conf->getState() == Conference::HOLD_REC;
+
+    ParticipantSet participants(conf->getParticipantList());
+
+    for (const auto &item : participants) {
+        if (auto call = getCallFromCallID(item)) {
+            // if one call is currently recording, the conference is in state recording
+            isRec |= call->isRecording();
+
+            switchCall(call);
+            offHoldCall(item);
+        }
+    }
+
+    conf->setState(isRec ? Conference::ACTIVE_ATTACHED_REC : Conference::ACTIVE_ATTACHED);
+
+    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
+
+    return true;
+}
+
+bool
+Manager::isConference(const std::string& id) const
+{
+    return conferenceMap_.find(id) != conferenceMap_.end();
+}
+
+bool
+Manager::isConferenceParticipant(const std::string& call_id)
+{
+    auto call = getCallFromCallID(call_id);
+    return call and not call->getConfId().empty();
+}
+
+bool
+Manager::addParticipant(const std::string& callId,
+                            const std::string& conferenceId)
+{
+    RING_DBG("Add participant %s to %s", callId.c_str(), conferenceId.c_str());
+    ConferenceMap::iterator iter = conferenceMap_.find(conferenceId);
+
+    if (iter == conferenceMap_.end()) {
+        RING_ERR("Conference id is not valid");
+        return false;
+    }
+
+    auto call = getCallFromCallID(callId);
+    if (!call) {
+        RING_ERR("Call id %s is not valid", callId.c_str());
+        return false;
+    }
+
+    // ensure that calls are only in one conference at a time
+    if (isConferenceParticipant(callId))
+        detachParticipant(callId);
+
+    // store the current call id (it will change in offHoldCall or in answerCall)
+    std::string current_call_id(getCurrentCallId());
+
+    // detach from prior communication and switch to this conference
+    if (current_call_id != callId) {
+        if (isConference(current_call_id))
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+        else
+            onHoldCall(current_call_id);
+    }
+
+    // TODO: remove this ugly hack => There should be different calls when double clicking
+    // a conference to add main participant to it, or (in this case) adding a participant
+    // toconference
+    unsetCurrentCall();
+
+    // Add main participant
+    addMainParticipant(conferenceId);
+
+    auto conf = iter->second;
+    switchCall(getCallFromCallID(conf->getConfID()));
+
+    // Add coresponding IDs in conf and call
+    call->setConfId(conf->getConfID());
+    conf->add(callId);
+
+    // Connect new audio streams together
+    getRingBufferPool().unBindAll(callId);
+
+    std::map<std::string, std::string> callDetails(getCallDetails(callId));
+    std::string callState(callDetails.find("CALL_STATE")->second);
+
+    if (callState == "HOLD") {
+        conf->bindParticipant(callId);
+        offHoldCall(callId);
+    } else if (callState == "INCOMING") {
+        conf->bindParticipant(callId);
+        answerCall(callId);
+    } else if (callState == "CURRENT")
+        conf->bindParticipant(callId);
+
+    ParticipantSet participants(conf->getParticipantList());
+
+    if (participants.empty())
+        RING_ERR("Participant list is empty for this conference");
+
+    // Connect stream
+    addStream(*call);
+    return true;
+}
+
+bool
+Manager::addMainParticipant(const std::string& conference_id)
+{
+    if (hasCurrentCall()) {
+        std::string current_call_id(getCurrentCallId());
+
+        if (isConference(current_call_id))
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+        else
+            onHoldCall(current_call_id);
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        ConferenceMap::const_iterator iter = conferenceMap_.find(conference_id);
+
+        if (iter == conferenceMap_.end() or iter->second == 0)
+            return false;
+
+        auto conf = iter->second;
+
+        ParticipantSet participants(conf->getParticipantList());
+
+        for (const auto &item_p : participants) {
+            getRingBufferPool().bindCallID(item_p, RingBufferPool::DEFAULT_ID);
+            // Reset ringbuffer's readpointers
+            getRingBufferPool().flush(item_p);
+        }
+
+        getRingBufferPool().flush(RingBufferPool::DEFAULT_ID);
+
+        if (conf->getState() == Conference::ACTIVE_DETACHED)
+            conf->setState(Conference::ACTIVE_ATTACHED);
+        else if (conf->getState() == Conference::ACTIVE_DETACHED_REC)
+            conf->setState(Conference::ACTIVE_ATTACHED_REC);
+        else
+            RING_WARN("Invalid conference state while adding main participant");
+
+        emitSignal<DRing::CallSignal::ConferenceChanged>(conference_id, conf->getStateStr());
+    }
+
+    switchCall(getCallFromCallID(conference_id));
+    return true;
+}
+
+std::shared_ptr<Call>
+Manager::getCallFromCallID(const std::string& callID)
+{
+    return callFactory.getCall(callID);
+}
+
+bool
+Manager::joinParticipant(const std::string& callId1,
+                             const std::string& callId2)
+{
+    if (callId1 == callId2) {
+        RING_ERR("Cannot join participant %s to itself", callId1.c_str());
+        return false;
+    }
+
+    // Set corresponding conference ids for call 1
+    auto call1 = getCallFromCallID(callId1);
+    if (!call1) {
+        RING_ERR("Could not find call %s", callId1.c_str());
+        return false;
+    }
+
+    // Set corresponding conderence details
+    auto call2 = getCallFromCallID(callId2);
+    if (!call2) {
+        RING_ERR("Could not find call %s", callId2.c_str());
+        return false;
+    }
+
+    // ensure that calls are only in one conference at a time
+    if (isConferenceParticipant(callId1))
+        detachParticipant(callId1);
+    if (isConferenceParticipant(callId2))
+        detachParticipant(callId2);
+
+    std::map<std::string, std::string> call1Details(getCallDetails(callId1));
+    std::map<std::string, std::string> call2Details(getCallDetails(callId2));
+
+    std::string current_call_id(getCurrentCallId());
+    RING_DBG("Current Call ID %s", current_call_id.c_str());
+
+    // detach from the conference and switch to this conference
+    if ((current_call_id != callId1) and (current_call_id != callId2)) {
+        // If currently in a conference
+        if (isConference(current_call_id))
+            detachParticipant(RingBufferPool::DEFAULT_ID);
+        else
+            onHoldCall(current_call_id); // currently in a call
+    }
+
+
+    auto conf = createConference(callId1, callId2);
+
+    call1->setConfId(conf->getConfID());
+    getRingBufferPool().unBindAll(callId1);
+
+    call2->setConfId(conf->getConfID());
+    getRingBufferPool().unBindAll(callId2);
+
+    // Process call1 according to its state
+    std::string call1_state_str(call1Details.find("CALL_STATE")->second);
+    RING_DBG("Process call %s state: %s", callId1.c_str(), call1_state_str.c_str());
+
+    if (call1_state_str == "HOLD") {
+        conf->bindParticipant(callId1);
+        offHoldCall(callId1);
+    } else if (call1_state_str == "INCOMING") {
+        conf->bindParticipant(callId1);
+        answerCall(callId1);
+    } else if (call1_state_str == "CURRENT") {
+        conf->bindParticipant(callId1);
+    } else if (call1_state_str == "INACTIVE") {
+        conf->bindParticipant(callId1);
+        answerCall(callId1);
+    } else
+        RING_WARN("Call state not recognized");
+
+    // Process call2 according to its state
+    std::string call2_state_str(call2Details.find("CALL_STATE")->second);
+    RING_DBG("Process call %s state: %s", callId2.c_str(), call2_state_str.c_str());
+
+    if (call2_state_str == "HOLD") {
+        conf->bindParticipant(callId2);
+        offHoldCall(callId2);
+    } else if (call2_state_str == "INCOMING") {
+        conf->bindParticipant(callId2);
+        answerCall(callId2);
+    } else if (call2_state_str == "CURRENT") {
+        conf->bindParticipant(callId2);
+    } else if (call2_state_str == "INACTIVE") {
+        conf->bindParticipant(callId2);
+        answerCall(callId2);
+    } else
+        RING_WARN("Call state not recognized");
+
+    // Switch current call id to this conference
+    switchCall(getCallFromCallID(conf->getConfID()));
+    conf->setState(Conference::ACTIVE_ATTACHED);
+
+    // set recording sampling rate
+    conf->setRecordingFormat(ringbufferpool_->getInternalAudioFormat());
+
+    return true;
+}
+
+void
+Manager::createConfFromParticipantList(const std::vector< std::string > &participantList)
+{
+    // we must at least have 2 participant for a conference
+    if (participantList.size() <= 1) {
+        RING_ERR("Participant number must be higher or equal to 2");
+        return;
+    }
+
+    auto conf = std::make_shared<Conference>();
+
+    int successCounter = 0;
+
+    for (const auto &p : participantList) {
+        std::string numberaccount(p);
+        std::string tostr(numberaccount.substr(0, numberaccount.find(",")));
+        std::string account(numberaccount.substr(numberaccount.find(",") + 1, numberaccount.size()));
+
+        unsetCurrentCall();
+
+        // Create call
+        auto call_id = outgoingCall(account, tostr, conf->getConfID());
+        if (call_id.empty())
+            continue;
+
+        // Manager methods may behave differently if the call id participates in a conference
+        conf->add(call_id);
+
+        emitSignal<DRing::CallSignal::NewCallCreated>(account, call_id, tostr);
+        successCounter++;
+    }
+
+    // Create the conference if and only if at least 2 calls have been successfully created
+    if (successCounter >= 2) {
+        conferenceMap_[conf->getConfID()] = conf;
+        emitSignal<DRing::CallSignal::ConferenceCreated>(conf->getConfID());
+        conf->setRecordingFormat(ringbufferpool_->getInternalAudioFormat());
+    }
+}
+
+bool
+Manager::detachParticipant(const std::string& call_id)
+{
+    const std::string current_call_id(getCurrentCallId());
+
+    if (call_id != RingBufferPool::DEFAULT_ID) {
+        auto call = getCallFromCallID(call_id);
+        if (!call) {
+            RING_ERR("Could not find call %s", call_id.c_str());
+            return false;
+        }
+
+        auto conf = getConferenceFromCallID(call_id);
+
+        if (conf == nullptr) {
+            RING_ERR("Call is not conferencing, cannot detach");
+            return false;
+        }
+
+        std::map<std::string, std::string> call_details(getCallDetails(call_id));
+        std::map<std::string, std::string>::iterator iter_details(call_details.find("CALL_STATE"));
+
+        if (iter_details == call_details.end()) {
+            RING_ERR("Could not find CALL_STATE");
+            return false;
+        }
+
+        // Don't hold ringing calls when detaching them from conferences
+        if (iter_details->second != "RINGING")
+            onHoldCall(call_id);
+
+        removeParticipant(call_id);
+
+    } else {
+        RING_DBG("Unbind main participant from conference %d");
+        getRingBufferPool().unBindAll(RingBufferPool::DEFAULT_ID);
+
+        if (not isConference(current_call_id)) {
+            RING_ERR("Current call id (%s) is not a conference", current_call_id.c_str());
+            return false;
+        }
+
+        ConferenceMap::iterator iter = conferenceMap_.find(current_call_id);
+
+        auto conf = iter->second;
+        if (iter == conferenceMap_.end() or conf == 0) {
+            RING_DBG("Conference is NULL");
+            return false;
+        }
+
+        if (conf->getState() == Conference::ACTIVE_ATTACHED)
+            conf->setState(Conference::ACTIVE_DETACHED);
+        else if (conf->getState() == Conference::ACTIVE_ATTACHED_REC)
+            conf->setState(Conference::ACTIVE_DETACHED_REC);
+        else
+            RING_WARN("Undefined behavior, invalid conference state in detach participant");
+
+        emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
+
+        unsetCurrentCall();
+    }
+
+    return true;
+}
+
+void
+Manager::removeParticipant(const std::string& call_id)
+{
+    RING_DBG("Remove participant %s", call_id.c_str());
+
+    // this call is no longer a conference participant
+    auto call = getCallFromCallID(call_id);
+    if (!call) {
+        RING_ERR("Call not found");
+        return;
+    }
+
+    ConferenceMap::const_iterator iter = conferenceMap_.find(call->getConfId());
+
+    auto conf = iter->second;
+    if (iter == conferenceMap_.end() or conf == 0) {
+        RING_ERR("No conference with id %s, cannot remove participant", call->getConfId().c_str());
+        return;
+    }
+
+    conf->remove(call_id);
+    call->setConfId("");
+
+    removeStream(*call);
+
+    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
+
+    processRemainingParticipants(*conf);
+}
+
+void
+Manager::processRemainingParticipants(Conference &conf)
+{
+    const std::string current_call_id(getCurrentCallId());
+    ParticipantSet participants(conf.getParticipantList());
+    const size_t n = participants.size();
+    RING_DBG("Process remaining %d participant(s) from conference %s",
+          n, conf.getConfID().c_str());
+
+    if (n > 1) {
+        // Reset ringbuffer's readpointers
+        for (const auto &p : participants)
+            getRingBufferPool().flush(p);
+
+        getRingBufferPool().flush(RingBufferPool::DEFAULT_ID);
+    } else if (n == 1) {
+        // this call is the last participant, hence
+        // the conference is over
+        ParticipantSet::iterator p = participants.begin();
+
+        if (auto call = getCallFromCallID(*p)) {
+            call->setConfId("");
+            // if we are not listening to this conference
+            if (current_call_id != conf.getConfID())
+                onHoldCall(call->getCallId());
+            else
+                switchCall(call);
+        }
+
+        RING_DBG("No remaining participants, remove conference");
+        removeConference(conf.getConfID());
+    } else {
+        RING_DBG("No remaining participants, remove conference");
+        removeConference(conf.getConfID());
+        unsetCurrentCall();
+    }
+}
+
+bool
+Manager::joinConference(const std::string& conf_id1,
+                            const std::string& conf_id2)
+{
+    if (conferenceMap_.find(conf_id1) == conferenceMap_.end()) {
+        RING_ERR("Not a valid conference ID: %s", conf_id1.c_str());
+        return false;
+    }
+
+    if (conferenceMap_.find(conf_id2) == conferenceMap_.end()) {
+        RING_ERR("Not a valid conference ID: %s", conf_id2.c_str());
+        return false;
+    }
+
+    auto conf = conferenceMap_.find(conf_id1)->second;
+    ParticipantSet participants(conf->getParticipantList());
+
+    for (const auto &p : participants)
+        addParticipant(p, conf_id2);
+
+    return true;
+}
+
+void
+Manager::addStream(Call& call)
+{
+    const auto call_id = call.getCallId();
+    RING_DBG("Add audio stream %s", call_id.c_str());
+
+    if (isConferenceParticipant(call_id)) {
+        RING_DBG("Add stream to conference");
+
+        // bind to conference participant
+        ConferenceMap::iterator iter = conferenceMap_.find(call_id);
+        if (iter != conferenceMap_.end() and iter->second) {
+            auto conf = iter->second;
+            conf->bindParticipant(call_id);
+        }
+    } else {
+        RING_DBG("Add stream to call");
+
+        // bind to main
+        getRingBufferPool().bindCallID(call_id, RingBufferPool::DEFAULT_ID);
+
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+        if (!audiodriver_) {
+            RING_ERR("Audio driver not initialized");
+            return;
+        }
+        audiodriver_->flushUrgent();
+        audiodriver_->flushMain();
+    }
+    startAudioDriverStream();
+}
+
+void
+Manager::removeStream(Call& call)
+{
+    const auto call_id = call.getCallId();
+    RING_DBG("Remove audio stream %s", call_id.c_str());
+    getRingBufferPool().unBindAll(call_id);
+}
+
+// Not thread-safe, SHOULD be called in same thread that run poolEvents()
+void
+Manager::registerEventHandler(uintptr_t handlerId, EventHandler handler)
+{
+    eventHandlerMap_[handlerId] = handler;
+}
+
+// Not thread-safe, SHOULD be called in same thread that run poolEvents()
+void
+Manager::unregisterEventHandler(uintptr_t handlerId)
+{
+    auto iter = eventHandlerMap_.find(handlerId);
+    if (iter != eventHandlerMap_.end()) {
+        if (iter == nextEventHandler_)
+            nextEventHandler_ = eventHandlerMap_.erase(iter);
+        else
+            eventHandlerMap_.erase(iter);
+    }
+}
+
+// Not thread-safe, SHOULD be called in same thread that run poolEvents()
+void
+Manager::addTask(const std::function<bool()>&& task)
+{
+    pendingTaskList_.emplace_back(task);
+}
+
+// Must be invoked periodically by a timer from the main event loop
+void Manager::pollEvents()
+{
+    //-- Handlers
+    {
+        auto iter = eventHandlerMap_.begin();
+        while (iter != eventHandlerMap_.end()) {
+            if (finished_)
+                return;
+
+            // WARN: following callback can do anything and typically
+            // calls (un)registerEventHandler.
+            // Think twice before modify this code.
+
+            nextEventHandler_ = std::next(iter);
+            iter->second();
+            iter = nextEventHandler_;
+        }
+    }
+
+    //-- Tasks
+    {
+        auto tmpList = std::move(pendingTaskList_);
+        pendingTaskList_.clear();
+        auto iter = std::begin(tmpList);
+        while (iter != tmpList.cend()) {
+            if (finished_)
+                return;
+
+            auto next = std::next(iter);
+            if (not (*iter)())
+                tmpList.erase(iter);
+            iter = next;
+        }
+        pendingTaskList_.splice(std::end(pendingTaskList_), tmpList);
+    }
+}
+
+//THREAD=Main
+void
+Manager::saveConfig()
+{
+    RING_DBG("Saving Configuration to XDG directory %s", path_.c_str());
+
+    if (audiodriver_) {
+        audioPreference.setVolumemic(audiodriver_->getCaptureGain());
+        audioPreference.setVolumespkr(audiodriver_->getPlaybackGain());
+        audioPreference.setCaptureMuted(audiodriver_->isCaptureMuted());
+        audioPreference.setPlaybackMuted(audiodriver_->isPlaybackMuted());
+    }
+
+    try {
+        YAML::Emitter out;
+
+        // FIXME maybe move this into accountFactory?
+        out << YAML::BeginMap << YAML::Key << "accounts";
+        out << YAML::Value << YAML::BeginSeq;
+
+        for (const auto& account : accountFactory_.getAllAccounts()) {
+            account->serialize(out);
+        }
+        out << YAML::EndSeq;
+
+        // FIXME: this is a hack until we get rid of accountOrder
+        preferences.verifyAccountOrder(getAccountList());
+        preferences.serialize(out);
+        voipPreferences.serialize(out);
+        hookPreference.serialize(out);
+        audioPreference.serialize(out);
+#ifdef RING_VIDEO
+        getVideoDeviceMonitor().serialize(out);
+#endif
+        shortcutPreferences.serialize(out);
+
+        std::ofstream fout(path_);
+        fout << out.c_str();
+    } catch (const YAML::Exception &e) {
+        RING_ERR("%s", e.what());
+    } catch (const std::runtime_error &e) {
+        RING_ERR("%s", e.what());
+    }
+}
+
+//THREAD=Main | VoIPLink
+void
+Manager::playDtmf(char code)
+{
+    stopTone();
+
+    if (not voipPreferences.getPlayDtmf()) {
+        RING_DBG("Do not have to play a tone...");
+        return;
+    }
+
+    // length in milliseconds
+    int pulselen = voipPreferences.getPulseLength();
+
+    if (pulselen == 0) {
+        RING_DBG("Pulse length is not set...");
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    // numbers of int = length in milliseconds / 1000 (number of seconds)
+    //                = number of seconds * SAMPLING_RATE by SECONDS
+
+    // fast return, no sound, so no dtmf
+    if (not audiodriver_ or not dtmfKey_) {
+        RING_DBG("No audio layer...");
+        return;
+    }
+
+    // number of data sampling in one pulselen depends on samplerate
+    // size (n sampling) = time_ms * sampling/s
+    //                     ---------------------
+    //                            ms/s
+    int size = (int)((pulselen * (float) audiodriver_->getSampleRate()) / 1000);
+    dtmfBuf_.resize(size);
+
+    // Handle dtmf
+    dtmfKey_->startTone(code);
+
+    // copy the sound
+    if (dtmfKey_->generateDTMF(*dtmfBuf_.getChannel(0))) {
+        // Put buffer to urgentRingBuffer
+        // put the size in bytes...
+        // so size * 1 channel (mono) * sizeof (bytes for the data)
+        // audiolayer->flushUrgent();
+        audiodriver_->startStream();
+
+        // FIXME: do real synchronization
+        int tries = 10;
+        while (not audiodriver_->isStarted() and tries--) {
+            RING_WARN("Audio layer not ready yet");
+            usleep(10000);
+        }
+        audiodriver_->putUrgent(dtmfBuf_);
+    }
+
+    // TODO Cache the DTMF
+}
+
+// Multi-thread
+bool
+Manager::incomingCallsWaiting()
+{
+    std::lock_guard<std::mutex> m(waitingCallsMutex_);
+    return not waitingCalls_.empty();
+}
+
+void
+Manager::addWaitingCall(const std::string& id)
+{
+    std::lock_guard<std::mutex> m(waitingCallsMutex_);
+    waitingCalls_.insert(id);
+}
+
+void
+Manager::removeWaitingCall(const std::string& id)
+{
+    std::lock_guard<std::mutex> m(waitingCallsMutex_);
+    waitingCalls_.erase(id);
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Management of event peer IP-phone
+////////////////////////////////////////////////////////////////////////////////
+// SipEvent Thread
+void
+Manager::incomingCall(Call &call, const std::string& accountId)
+{
+    stopTone();
+    const std::string callID(call.getCallId());
+
+    if (accountId.empty())
+        call.setIPToIP(true);
+    else {
+        // strip sip: which is not required and bring confusion with ip to ip calls
+        // when placing new call from history (if call is IAX, do nothing)
+        std::string peerNumber(call.getPeerNumber());
+
+        const char SIP_PREFIX[] = "sip:";
+        size_t startIndex = peerNumber.find(SIP_PREFIX);
+
+        if (startIndex != std::string::npos)
+            call.setPeerNumber(peerNumber.substr(startIndex + sizeof(SIP_PREFIX) - 1));
+    }
+
+    if (not hasCurrentCall()) {
+        call.setConnectionState(Call::RINGING);
+        playRingtone(accountId);
+    }
+
+    addWaitingCall(callID);
+
+    std::string number(call.getPeerNumber());
+
+    std::string from("<" + number + ">");
+
+    emitSignal<DRing::CallSignal::IncomingCall>(accountId, callID, call.getDisplayName() + " " + from);
+}
+
+//THREAD=VoIP
+#if HAVE_INSTANT_MESSAGING
+void
+Manager::incomingMessage(const std::string& callID,
+                             const std::string& from,
+                             const std::string& message)
+{
+    if (isConferenceParticipant(callID)) {
+        auto conf = getConferenceFromCallID(callID);
+
+        ParticipantSet participants(conf->getParticipantList());
+
+        for (const auto &item_p : participants) {
+
+            if (item_p == callID)
+                continue;
+
+            RING_DBG("Send message to %s", item_p.c_str());
+
+            if (auto call = getCallFromCallID(item_p)) {
+                call->sendTextMessage(message, from);
+            } else {
+                RING_ERR("Failed to get call while sending instant message");
+                return;
+            }
+        }
+
+        // in case of a conference we must notify client using conference id
+        emitSignal<DRing::CallSignal::IncomingMessage>(conf->getConfID(), from, message);
+    } else
+        emitSignal<DRing::CallSignal::IncomingMessage>(callID, from, message);
+}
+
+//THREAD=VoIP
+bool
+Manager::sendCallTextMessage(const std::string& callID,
+                             const std::string& message,
+                             const std::string& from)
+{
+    if (isConference(callID)) {
+        RING_DBG("Is a conference, send instant message to everyone");
+        ConferenceMap::iterator it = conferenceMap_.find(callID);
+
+        if (it == conferenceMap_.end())
+            return false;
+
+        auto conf = it->second;
+
+        if (!conf)
+            return false;
+
+        ParticipantSet participants(conf->getParticipantList());
+
+        for (const auto &participant_id : participants) {
+
+            if (auto call = getCallFromCallID(participant_id)) {
+                call->sendTextMessage(message, from);
+            } else {
+                RING_ERR("Failed to get call while sending instant message");
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+    if (isConferenceParticipant(callID)) {
+        RING_DBG("Call is participant in a conference, send instant message to everyone");
+        auto conf = getConferenceFromCallID(callID);
+
+        if (!conf)
+            return false;
+
+        ParticipantSet participants(conf->getParticipantList());
+
+        for (const auto &participant_id : participants) {
+
+            if (auto call = getCallFromCallID(participant_id)) {
+                call->sendTextMessage(message, from);
+            } else {
+                RING_ERR("Failed to get call while sending instant message");
+                return false;
+            }
+        }
+    } else {
+        if (auto call = getCallFromCallID(callID)) {
+            call->sendTextMessage(message, from);
+        } else {
+            RING_ERR("Failed to get call while sending instant message");
+            return false;
+        }
+    }
+    return true;
+}
+#endif // HAVE_INSTANT_MESSAGING
+
+//THREAD=VoIP CALL=Outgoing
+void
+Manager::peerAnsweredCall(Call& call)
+{
+    const auto call_id = call.getCallId();
+    RING_DBG("Peer answered call %s", call_id.c_str());
+
+    // The if statement is usefull only if we sent two calls at the same time.
+    if (isCurrentCall(call))
+        stopTone();
+
+    // Connect audio streams
+    addStream(call);
+
+    if (audiodriver_) {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+        audiodriver_->flushMain();
+        audiodriver_->flushUrgent();
+    }
+
+    if (audioPreference.getIsAlwaysRecording())
+        toggleRecordingCall(call_id);
+
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "CURRENT", 0);
+}
+
+//THREAD=VoIP Call=Outgoing
+void
+Manager::peerRingingCall(Call& call)
+{
+    const auto call_id = call.getCallId();
+    RING_DBG("Peer call %s ringing", call_id.c_str());
+
+    if (isCurrentCall(call))
+        ringback();
+
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "RINGING", 0);
+}
+
+//THREAD=VoIP Call=Outgoing/Ingoing
+void
+Manager::peerHungupCall(Call& call)
+{
+    const auto call_id = call.getCallId();
+    RING_DBG("Peer hungup call %s", call_id.c_str());
+
+    if (isConferenceParticipant(call_id)) {
+        removeParticipant(call_id);
+    } else if (isCurrentCall(call)) {
+        stopTone();
+        unsetCurrentCall();
+    }
+
+    call.peerHungup();
+
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "HUNGUP", 0);
+
+    checkAudio();
+    removeWaitingCall(call_id);
+    if (not incomingCallsWaiting())
+        stopTone();
+
+    removeStream(call);
+}
+
+//THREAD=VoIP
+void
+Manager::callBusy(Call& call)
+{
+    const auto call_id = call.getCallId();
+
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "BUSY", 0);
+
+    if (isCurrentCall(call)) {
+        playATone(Tone::TONE_BUSY);
+        unsetCurrentCall();
+    }
+
+    checkAudio();
+    removeWaitingCall(call_id);
+}
+
+//THREAD=VoIP
+void
+Manager::callFailure(Call& call, int code)
+{
+    const auto call_id = call.getCallId();
+
+    emitSignal<DRing::CallSignal::StateChange>(call_id, "FAILURE", code);
+
+    if (isCurrentCall(call)) {
+        playATone(Tone::TONE_BUSY);
+        unsetCurrentCall();
+    }
+
+    if (isConferenceParticipant(call_id)) {
+        RING_DBG("Call %s participating in a conference failed", call_id.c_str());
+        // remove this participant
+        removeParticipant(call_id);
+    }
+
+    checkAudio();
+    removeWaitingCall(call_id);
+}
+
+//THREAD=VoIP
+void
+Manager::startVoiceMessageNotification(const std::string& accountId,
+                                           int nb_msg)
+{
+    emitSignal<DRing::CallSignal::VoiceMailNotify>(accountId, nb_msg);
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::playATone(Tone::TONEID toneId)
+{
+    if (not voipPreferences.getPlayTones())
+        return;
+
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        if (not audiodriver_) {
+            RING_ERR("Audio layer not initialized");
+            return;
+        }
+
+        audiodriver_->flushUrgent();
+        audiodriver_->startStream();
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(toneMutex_);
+        if (telephoneTone_)
+            telephoneTone_->setCurrentTone(toneId);
+    }
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::stopTone()
+{
+    if (not voipPreferences.getPlayTones())
+        return;
+
+    std::lock_guard<std::mutex> lock(toneMutex_);
+    if (telephoneTone_)
+        telephoneTone_->setCurrentTone(Tone::TONE_NULL);
+
+    if (audiofile_) {
+        std::string filepath(audiofile_->getFilePath());
+
+        emitSignal<DRing::CallSignal::RecordPlaybackStopped>(filepath);
+        audiofile_.reset();
+    }
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::playTone()
+{
+    playATone(Tone::TONE_DIALTONE);
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::playToneWithMessage()
+{
+    playATone(Tone::TONE_CONGESTION);
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::congestion()
+{
+    playATone(Tone::TONE_CONGESTION);
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::ringback()
+{
+    playATone(Tone::TONE_RINGTONE);
+}
+
+// Caller must hold toneMutex
+void
+Manager::updateAudioFile(const std::string &file, int sampleRate)
+{
+    audiofile_.reset(new AudioFile(file, sampleRate));
+}
+
+/**
+ * Multi Thread
+ */
+void
+Manager::playRingtone(const std::string& accountID)
+{
+    const auto account = getAccount(accountID);
+
+    if (!account) {
+        RING_WARN("Invalid account in ringtone");
+        return;
+    }
+
+    if (!account->getRingtoneEnabled()) {
+        ringback();
+        return;
+    }
+
+    std::string ringchoice = account->getRingtonePath();
+
+    if (ringchoice.find(DIR_SEPARATOR_STR) == std::string::npos) {
+        // check inside global share directory
+        static const char * const RINGDIR = "ringtones";
+        ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR
+                     + RINGDIR + DIR_SEPARATOR_STR + ringchoice;
+    }
+
+    int audioLayerSmplr = 8000;
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        if (not audiodriver_) {
+            RING_ERR("no audio layer in ringtone");
+            return;
+        }
+
+        audioLayerSmplr = audiodriver_->getSampleRate();
+    }
+
+    bool doFallback = false;
+
+    {
+        std::lock_guard<std::mutex> m(toneMutex_);
+
+        if (audiofile_) {
+            emitSignal<DRing::CallSignal::RecordPlaybackStopped>(audiofile_->getFilePath());
+            audiofile_.reset();
+        }
+
+        try {
+            updateAudioFile(ringchoice, audioLayerSmplr);
+        } catch (const AudioFileException &e) {
+            RING_WARN("Ringtone error: %s", e.what());
+            doFallback = true; // do ringback once lock is out of scope
+        }
+    } // leave mutex
+
+    if (doFallback) {
+        ringback();
+        return;
+    }
+
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    // start audio if not started AND flush all buffers (main and urgent)
+    audiodriver_->startStream();
+}
+
+AudioLoop*
+Manager::getTelephoneTone()
+{
+    std::lock_guard<std::mutex> m(toneMutex_);
+    if (telephoneTone_)
+        return telephoneTone_->getCurrentTone();
+    else
+        return nullptr;
+}
+
+AudioLoop*
+Manager::getTelephoneFile()
+{
+    std::lock_guard<std::mutex> m(toneMutex_);
+    return audiofile_.get();
+}
+
+///////////////////////////////////////////////////////////////////////////////
+// Private functions
+///////////////////////////////////////////////////////////////////////////////
+/**
+ * Initialization: Main Thread
+ */
+std::string
+Manager::retrieveConfigPath() const
+{
+#ifdef __ANDROID__
+    std::string configdir = "/data/data/cx.ring";
+#elif __APPLE__
+    std::string configdir = fileutils::get_home_dir() + DIR_SEPARATOR_STR
+        + "Library" + DIR_SEPARATOR_STR + "Application Support"
+        + DIR_SEPARATOR_STR + PACKAGE;
+#else
+    std::string configdir = fileutils::get_home_dir() + DIR_SEPARATOR_STR +
+                            ".config" + DIR_SEPARATOR_STR + PACKAGE;
+#endif
+
+    const std::string xdg_env(XDG_CONFIG_HOME);
+    if (not xdg_env.empty())
+        configdir = xdg_env + DIR_SEPARATOR_STR + PACKAGE;
+
+#ifndef _WIN32
+    if (mkdir(configdir.data(), 0700) != 0) {
+#else
+    if (fileutils::recursive_mkdir(configdir.data()) != true) {
+#endif
+        // If directory creation failed
+        if (errno != EEXIST)
+            RING_DBG("Cannot create directory: %s!", configdir.c_str());
+    }
+
+    static const char * const PROGNAME = "dring";
+    return configdir + DIR_SEPARATOR_STR + PROGNAME + ".yml";
+}
+
+/**
+ * Set input audio plugin
+ */
+void
+Manager::setAudioPlugin(const std::string& audioPlugin)
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    audioPreference.setAlsaPlugin(audioPlugin);
+
+    bool wasStarted = audiodriver_->isStarted();
+
+    // Recreate audio driver with new settings
+    audiodriver_.reset(audioPreference.createAudioLayer());
+
+    if (audiodriver_ and wasStarted)
+        audiodriver_->startStream();
+    else
+        RING_ERR("No audio layer created, possibly built without audio support");
+}
+
+/**
+ * Set audio output device
+ */
+void
+Manager::setAudioDevice(int index, DeviceType type)
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    if (not audiodriver_) {
+        RING_ERR("Audio driver not initialized");
+        return ;
+    }
+
+    const bool wasStarted = audiodriver_->isStarted();
+    audiodriver_->updatePreference(audioPreference, index, type);
+
+    // Recreate audio driver with new settings
+    audiodriver_.reset(audioPreference.createAudioLayer());
+
+    if (audiodriver_ and wasStarted)
+        audiodriver_->startStream();
+}
+
+/**
+ * Get list of supported audio output device
+ */
+std::vector<std::string>
+Manager::getAudioOutputDeviceList()
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    return audiodriver_->getPlaybackDeviceList();
+}
+
+/**
+ * Get list of supported audio input device
+ */
+std::vector<std::string>
+Manager::getAudioInputDeviceList()
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    return audiodriver_->getCaptureDeviceList();
+}
+
+/**
+ * Get string array representing integer indexes of output and input device
+ */
+std::vector<std::string>
+Manager::getCurrentAudioDevicesIndex()
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    std::vector<std::string> v;
+
+    std::stringstream ssi, sso, ssr;
+    sso << audiodriver_->getIndexPlayback();
+    v.push_back(sso.str());
+    ssi << audiodriver_->getIndexCapture();
+    v.push_back(ssi.str());
+    ssr << audiodriver_->getIndexRingtone();
+    v.push_back(ssr.str());
+
+    return v;
+}
+
+bool
+Manager::switchInput(const std::string& call_id, const std::string& res)
+{
+    auto call = getCallFromCallID(call_id);
+    if (!call) {
+        RING_ERR("Call %s is NULL", call_id.c_str());
+        return false;
+    }
+    call->switchInput(res);
+    return true;
+}
+
+int
+Manager::isRingtoneEnabled(const std::string& id)
+{
+    const auto account = getAccount(id);
+
+    if (!account) {
+        RING_WARN("Invalid account in ringtone enabled");
+        return 0;
+    }
+
+    return account->getRingtoneEnabled();
+}
+
+void
+Manager::ringtoneEnabled(const std::string& id)
+{
+    const auto account = getAccount(id);
+
+    if (!account) {
+        RING_WARN("Invalid account in ringtone enabled");
+        return;
+    }
+
+    account->getRingtoneEnabled() ? account->setRingtoneEnabled(false) : account->setRingtoneEnabled(true);
+}
+
+bool
+Manager::getIsAlwaysRecording() const
+{
+    return audioPreference.getIsAlwaysRecording();
+}
+
+void
+Manager::setIsAlwaysRecording(bool isAlwaysRec)
+{
+    return audioPreference.setIsAlwaysRecording(isAlwaysRec);
+}
+
+bool
+Manager::toggleRecordingCall(const std::string& id)
+{
+    std::shared_ptr<Recordable> rec;
+
+    ConferenceMap::const_iterator it(conferenceMap_.find(id));
+    if (it == conferenceMap_.end()) {
+        RING_DBG("toggle recording for call %s", id.c_str());
+        rec = getCallFromCallID(id);
+    } else {
+        RING_DBG("toggle recording for conference %s", id.c_str());
+        auto conf = it->second;
+        if (conf) {
+            rec = conf;
+            if (conf->isRecording())
+                conf->setState(Conference::ACTIVE_ATTACHED);
+            else
+                conf->setState(Conference::ACTIVE_ATTACHED_REC);
+        }
+    }
+
+    if (!rec) {
+        RING_ERR("Could not find recordable instance %s", id.c_str());
+        return false;
+    }
+
+    const bool result = rec->toggleRecording();
+    emitSignal<DRing::CallSignal::RecordPlaybackFilepath>(id, rec->getFilename());
+    emitSignal<DRing::CallSignal::RecordingStateChanged>(id, result);
+    return result;
+}
+
+bool
+Manager::isRecording(const std::string& id)
+{
+    auto call = getCallFromCallID(id);
+    return call and (static_cast<Recordable*>(call.get()))->isRecording();
+}
+
+bool
+Manager::startRecordedFilePlayback(const std::string& filepath)
+{
+    RING_DBG("Start recorded file playback %s", filepath.c_str());
+
+    int sampleRate;
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        if (not audiodriver_) {
+            RING_ERR("No audio layer in start recorded file playback");
+            return false;
+        }
+
+        sampleRate = audiodriver_->getSampleRate();
+    }
+
+    {
+        std::lock_guard<std::mutex> m(toneMutex_);
+
+        if (audiofile_) {
+            emitSignal<DRing::CallSignal::RecordPlaybackStopped>(audiofile_->getFilePath());
+            audiofile_.reset();
+        }
+
+        try {
+            updateAudioFile(filepath, sampleRate);
+            if (not audiofile_)
+                return false;
+        } catch (const AudioFileException &e) {
+            RING_WARN("Audio file error: %s", e.what());
+            return false;
+        }
+    } // release toneMutex
+
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+        audiodriver_->startStream();
+    }
+
+    return true;
+}
+
+void Manager::recordingPlaybackSeek(const double value)
+{
+    std::lock_guard<std::mutex> m(toneMutex_);
+    if (audiofile_)
+        audiofile_.get()->seek(value);
+}
+
+void Manager::stopRecordedFilePlayback(const std::string& filepath)
+{
+    RING_DBG("Stop recorded file playback %s", filepath.c_str());
+
+    checkAudio();
+
+    {
+        std::lock_guard<std::mutex> m(toneMutex_);
+        audiofile_.reset();
+    }
+    emitSignal<DRing::CallSignal::RecordPlaybackStopped>(filepath);
+}
+
+void Manager::setHistoryLimit(int days)
+{
+    RING_DBG("Set history limit");
+    preferences.setHistoryLimit(days);
+    saveConfig();
+}
+
+int
+Manager::getHistoryLimit() const
+{
+    return preferences.getHistoryLimit();
+}
+
+bool
+Manager::setAudioManager(const std::string &api)
+{
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        if (not audiodriver_)
+            return false;
+
+        if (api == audioPreference.getAudioApi()) {
+            RING_DBG("Audio manager chosen already in use. No changes made. ");
+            return true;
+        }
+    }
+
+    {
+        std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+        bool wasStarted = audiodriver_->isStarted();
+        audioPreference.setAudioApi(api);
+        audiodriver_.reset(audioPreference.createAudioLayer());
+
+        if (audiodriver_ and wasStarted)
+            audiodriver_->startStream();
+    }
+
+    saveConfig();
+
+    // ensure that we completed the transition (i.e. no fallback was used)
+    return api == audioPreference.getAudioApi();
+}
+
+std::string
+Manager::getAudioManager() const
+{
+    return audioPreference.getAudioApi();
+}
+
+int
+Manager::getAudioInputDeviceIndex(const std::string &name)
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    if (not audiodriver_) {
+        RING_ERR("Audio layer not initialized");
+        return 0;
+    }
+
+    return audiodriver_->getAudioDeviceIndex(name, DeviceType::CAPTURE);
+}
+
+int
+Manager::getAudioOutputDeviceIndex(const std::string &name)
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+
+    if (not audiodriver_) {
+        RING_ERR("Audio layer not initialized");
+        return 0;
+    }
+
+    return audiodriver_->getAudioDeviceIndex(name, DeviceType::PLAYBACK);
+}
+
+std::string
+Manager::getCurrentAudioOutputPlugin() const
+{
+    return audioPreference.getAlsaPlugin();
+}
+
+bool
+Manager::getNoiseSuppressState() const
+{
+    return audioPreference.getNoiseReduce();
+}
+
+void
+Manager::setNoiseSuppressState(bool state)
+{
+    audioPreference.setNoiseReduce(state);
+}
+
+bool
+Manager::isAGCEnabled() const
+{
+    return audioPreference.isAGCEnabled();
+}
+
+void
+Manager::setAGCState(bool state)
+{
+    audioPreference.setAGCState(state);
+}
+
+/**
+ * Initialization: Main Thread
+ */
+void
+Manager::initAudioDriver()
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    audiodriver_.reset(audioPreference.createAudioLayer());
+}
+
+AudioFormat
+Manager::hardwareAudioFormatChanged(AudioFormat format)
+{
+    return audioFormatUsed(format);
+}
+
+AudioFormat
+Manager::audioFormatUsed(AudioFormat format)
+{
+    AudioFormat currentFormat = ringbufferpool_->getInternalAudioFormat();
+    format.nb_channels = std::max(currentFormat.nb_channels, std::min(format.nb_channels, 2u)); // max 2 channels.
+    format.sample_rate = std::max(currentFormat.sample_rate, format.sample_rate);
+
+    if (currentFormat == format)
+        return format;
+
+    RING_DBG("Audio format changed: %s -> %s", currentFormat.toString().c_str(), format.toString().c_str());
+
+    ringbufferpool_->setInternalAudioFormat(format);
+
+    {
+        std::lock_guard<std::mutex> toneLock(toneMutex_);
+        telephoneTone_.reset(new TelephoneTone(preferences.getZoneToneChoice(), format.sample_rate));
+    }
+    dtmfKey_.reset(new DTMF(format.sample_rate));
+    return format;
+}
+
+void
+Manager::setAccountsOrder(const std::string& order)
+{
+    RING_DBG("Set accounts order : %s", order.c_str());
+    // Set the new config
+
+    preferences.setAccountOrder(order);
+
+    saveConfig();
+}
+
+std::vector<std::string>
+Manager::getAccountList() const
+{
+    // TODO: this code looks weird. need further investigation!
+
+    using std::vector;
+    using std::string;
+    vector<string> account_order(loadAccountOrder());
+
+    // The IP2IP profile is always available, and first in the list
+
+    vector<string> v;
+
+    // Concatenate all account pointers in a single map
+    const auto& allAccounts = accountFactory_.getAllAccounts();
+
+    // If no order has been set, load the default one ie according to the creation date.
+    if (account_order.empty()) {
+        for (const auto &account : allAccounts) {
+            if (account->isIP2IP())
+                continue;
+            v.push_back(account->getAccountID());
+        }
+    } else {
+        const auto& ip2ipAccountID = getIP2IPAccount()->getAccountID();
+        for (const auto& id : account_order) {
+            if (id.empty() or id == ip2ipAccountID)
+                continue;
+
+            if (accountFactory_.hasAccount(id))
+                v.push_back(id);
+        }
+    }
+
+    if (const auto& account = getIP2IPAccount())
+        v.push_back(account->getAccountID());
+    else
+        RING_ERR("could not find IP2IP profile in getAccount list");
+
+    return v;
+}
+
+std::map<std::string, std::string>
+Manager::getAccountDetails(const std::string& accountID) const
+{
+    const auto account = getAccount(accountID);
+
+    if (account) {
+        return account->getAccountDetails();
+    } else {
+        RING_ERR("Could not get account details on a non-existing accountID %s", accountID.c_str());
+        // return an empty map since we can't throw an exception to D-Bus
+        return std::map<std::string, std::string>();
+    }
+}
+
+std::map<std::string, std::string>
+Manager::getVolatileAccountDetails(const std::string& accountID) const
+{
+    const auto account = getAccount(accountID);
+
+    if (account) {
+        return account->getVolatileAccountDetails();
+    } else {
+        RING_ERR("Could not get volatile account details on a non-existing accountID %s", accountID.c_str());
+        return {{}};
+    }
+}
+
+
+// method to reduce the if/else mess.
+// Even better, switch to XML !
+
+void
+Manager::setAccountDetails(const std::string& accountID,
+                               const std::map<std::string, std::string>& details)
+{
+    RING_DBG("Set account details for %s", accountID.c_str());
+
+    const auto account = getAccount(accountID);
+
+    if (account == nullptr) {
+        RING_ERR("Could not find account %s", accountID.c_str());
+        return;
+    }
+
+    // Ignore if nothing has changed
+    if (details == account->getAccountDetails())
+        return;
+
+    // Unregister before modifying any account information
+    // FIXME: inefficient api, don't pass details (not as ref nor copy)
+    // let client requiests them we needed.
+    account->doUnregister([&](bool /* transport_free */) {
+        account->setAccountDetails(details);
+        // Serialize configuration to disk once it is done
+        saveConfig();
+
+        if (account->isEnabled()) {
+            account->doRegister();
+        } else
+            account->doUnregister();
+
+        // Update account details to the client side
+        emitSignal<DRing::ConfigurationSignal::VolatileDetailsChanged>(accountID,
+                                                                       details);
+    });
+}
+
+std::string
+Manager::addAccount(const std::map<std::string, std::string>& details)
+{
+    /** @todo Deal with both the accountMap_ and the Configuration */
+    std::string newAccountID;
+    static std::uniform_int_distribution<uint64_t> rand_acc_id;
+
+    const std::vector<std::string> accountList(getAccountList());
+
+    do {
+        std::ostringstream accId;
+        accId << std::hex << rand_acc_id(rand_);
+        newAccountID = accId.str();
+    } while (std::find(accountList.begin(), accountList.end(), newAccountID)
+             != accountList.end());
+
+    // Get the type
+
+    const char* accountType;
+    if (details.find(Conf::CONFIG_ACCOUNT_TYPE) != details.end())
+        accountType = (*details.find(Conf::CONFIG_ACCOUNT_TYPE)).second.c_str();
+    else
+        accountType = AccountFactory::DEFAULT_ACCOUNT_TYPE;
+
+    RING_DBG("Adding account %s", newAccountID.c_str());
+
+    auto newAccount = accountFactory_.createAccount(accountType, newAccountID);
+    if (!newAccount) {
+        RING_ERR("Unknown %s param when calling addAccount(): %s",
+              Conf::CONFIG_ACCOUNT_TYPE, accountType);
+        return "";
+    }
+
+    newAccount->setAccountDetails(details);
+
+    preferences.addAccount(newAccountID);
+
+    newAccount->doRegister();
+
+    saveConfig();
+
+    emitSignal<DRing::ConfigurationSignal::AccountsChanged>();
+
+    return newAccountID;
+}
+
+void Manager::removeAccounts()
+{
+    for (const auto &acc : getAccountList())
+        removeAccount(acc);
+}
+
+void Manager::removeAccount(const std::string& accountID)
+{
+    // Get it down and dying
+    if (const auto& remAccount = getAccount(accountID)) {
+        remAccount->doUnregister();
+        accountFactory_.removeAccount(*remAccount);
+    }
+
+    preferences.removeAccount(accountID);
+
+    saveConfig();
+
+    emitSignal<DRing::ConfigurationSignal::AccountsChanged>();
+}
+
+bool
+Manager::isValidCall(const std::string& callID)
+{
+    return static_cast<bool>(getCallFromCallID(callID));
+}
+
+std::string
+Manager::getNewCallID()
+{
+    static std::uniform_int_distribution<uint64_t> rand_call_id;
+    std::ostringstream random_id;
+
+    // generate something like s7ea037947eb9fb2f
+    do {
+        random_id.clear();
+        random_id << rand_call_id(rand_);
+    } while (isValidCall(random_id.str()));
+
+    return random_id.str();
+}
+
+std::vector<std::string>
+Manager::loadAccountOrder() const
+{
+    return split_string(preferences.getAccountOrder(), '/');
+}
+
+void
+Manager::loadAccount(const YAML::Node &node, int &errorCount,
+                         const std::string &accountOrder)
+{
+    using yaml_utils::parseValue;
+
+    std::string accountType;
+    parseValue(node, "type", accountType);
+
+    std::string accountid;
+    parseValue(node, "id", accountid);
+
+    std::string accountAlias;
+    parseValue(node, "alias", accountAlias);
+    const auto inAccountOrder = [&](const std::string & id) {
+        return accountOrder.find(id + "/") != std::string::npos;
+    };
+
+    if (!accountid.empty() and !accountAlias.empty()) {
+        const auto& ip2ipAccountID = getIP2IPAccount()->getAccountID();
+        if (not inAccountOrder(accountid) and accountid != ip2ipAccountID) {
+            RING_WARN("Dropping account %s, which is not in account order", accountid.c_str());
+        } else if (accountFactory_.isSupportedType(accountType.c_str())) {
+            std::shared_ptr<Account> a;
+            if (accountid != ip2ipAccountID)
+                a = accountFactory_.createAccount(accountType.c_str(), accountid);
+            else
+                a = accountFactory_.getIP2IPAccount();
+            if (a) {
+                a->unserialize(node);
+            } else {
+                RING_ERR("Failed to create account type \"%s\"", accountType.c_str());
+                ++errorCount;
+            }
+        } else {
+            RING_WARN("Ignoring unknown account type \"%s\"", accountType.c_str());
+        }
+    }
+}
+
+int
+Manager::loadAccountMap(const YAML::Node &node)
+{
+    accountFactory_.initIP2IPAccount();
+
+    // build preferences
+    preferences.unserialize(node);
+    voipPreferences.unserialize(node);
+    hookPreference.unserialize(node);
+    audioPreference.unserialize(node);
+    shortcutPreferences.unserialize(node);
+
+    int errorCount = 0;
+    try {
+#ifdef RING_VIDEO
+        getVideoDeviceMonitor().unserialize(node);
+#endif
+    } catch (const YAML::Exception &e) {
+        RING_ERR("%s: No video node in config file", e.what());
+        ++errorCount;
+    }
+
+    const std::string accountOrder = preferences.getAccountOrder();
+
+    // load saved preferences for IP2IP account from configuration file
+    const auto &accountList = node["accounts"];
+
+    for (auto &a : accountList) {
+        loadAccount(a, errorCount, accountOrder);
+    }
+
+    return errorCount;
+}
+
+std::map<std::string, std::string>
+Manager::getCallDetails(const std::string &callID)
+{
+    if (auto call = getCallFromCallID(callID)) {
+        return call->getDetails();
+    } else {
+        RING_ERR("Call is NULL");
+        // FIXME: is this even useful?
+        return Call::getNullDetails();
+    }
+}
+
+std::vector<std::string>
+Manager::getCallList() const
+{
+    return callFactory.getCallIDs();
+}
+
+std::map<std::string, std::string>
+Manager::getConferenceDetails(
+    const std::string& confID) const
+{
+    std::map<std::string, std::string> conf_details;
+    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
+
+    if (iter_conf != conferenceMap_.end()) {
+        conf_details["CONFID"] = confID;
+        conf_details["CONF_STATE"] = iter_conf->second->getStateStr();
+    }
+
+    return conf_details;
+}
+
+std::vector<std::string>
+Manager::getConferenceList() const
+{
+    std::vector<std::string> v;
+    map_utils::vectorFromMapKeys(conferenceMap_, v);
+    return v;
+}
+
+std::vector<std::string>
+Manager::getDisplayNames(const std::string& confID) const
+{
+    std::vector<std::string> v;
+    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
+
+    if (iter_conf != conferenceMap_.end()) {
+        return iter_conf->second->getDisplayNames();
+    } else {
+        RING_WARN("Did not find conference %s", confID.c_str());
+    }
+
+    return v;
+}
+
+std::vector<std::string>
+Manager::getParticipantList(const std::string& confID) const
+{
+    std::vector<std::string> v;
+    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
+
+    if (iter_conf != conferenceMap_.end()) {
+        const ParticipantSet participants(iter_conf->second->getParticipantList());
+        std::copy(participants.begin(), participants.end(), std::back_inserter(v));;
+    } else
+        RING_WARN("Did not find conference %s", confID.c_str());
+
+    return v;
+}
+
+std::string
+Manager::getConferenceId(const std::string& callID)
+{
+    if (auto call = getCallFromCallID(callID))
+        return call->getConfId();
+
+    RING_ERR("Call is NULL");
+    return "";
+}
+
+void
+Manager::startAudioDriverStream()
+{
+    std::lock_guard<std::mutex> lock(audioLayerMutex_);
+    if (!audiodriver_) {
+        RING_ERR("Audio driver not initialized");
+        return;
+    }
+    audiodriver_->startStream();
+}
+
+void
+Manager::registerAccounts()
+{
+    auto allAccounts(getAccountList());
+
+    for (auto &item : allAccounts) {
+        const auto a = getAccount(item);
+
+        if (!a)
+            continue;
+
+        a->loadConfig();
+
+        if (a->isEnabled()) {
+            a->doRegister();
+        }
+    }
+}
+
+void
+Manager::unregisterAccounts()
+{
+    for (const auto& account : getAllAccounts()) {
+        if (account->isEnabled())
+            account->doUnregister();
+    }
+}
+
+void
+Manager::sendRegister(const std::string& accountID, bool enable)
+{
+    const auto acc = getAccount(accountID);
+    if (!acc)
+        return;
+
+    acc->setEnabled(enable);
+    acc->loadConfig();
+
+    Manager::instance().saveConfig();
+
+    if (acc->isEnabled()) {
+        acc->doRegister();
+    } else
+        acc->doUnregister();
+}
+
+void
+Manager::sendTextMessage(const std::string& accountID, const std::string& to, const std::string& message)
+{
+    const auto acc = getAccount(accountID);
+    if (!acc)
+        return;
+    acc->sendTextMessage(to, message);
+}
+
+std::shared_ptr<AudioLayer>
+Manager::getAudioDriver()
+{
+    return audiodriver_;
+}
+
+std::shared_ptr<Call>
+Manager::newOutgoingCall(const std::string& toUrl,
+                             const std::string& preferredAccountId)
+{
+    auto account = Manager::instance().getIP2IPAccount();
+    auto preferred = getAccount(preferredAccountId);
+    std::string finalToUrl = toUrl;
+
+#if HAVE_DHT
+    if (toUrl.find("ring:") != std::string::npos) {
+        if (preferred && preferred->getAccountType() == RingAccount::ACCOUNT_TYPE)
+            return preferred->newOutgoingCall(finalToUrl);
+        auto dhtAcc = getAllAccounts<RingAccount>();
+        for (const auto& acc : dhtAcc)
+            if (acc->isEnabled())
+                return acc->newOutgoingCall(finalToUrl);
+    }
+#endif
+
+    // FIXME: have a generic version to remove sip dependency
+    sip_utils::stripSipUriPrefix(finalToUrl);
+
+    if (!IpAddr::isValid(finalToUrl)) {
+        account = preferred;
+        if (account)
+            finalToUrl = toUrl;
+        else
+            RING_WARN("Preferred account %s doesn't exist, using IP2IP account",
+                 preferredAccountId.c_str());
+    } else
+        RING_WARN("IP Url detected, using IP2IP account");
+
+    if (!account) {
+        RING_ERR("No suitable account found to create outgoing call");
+        return nullptr;
+    }
+
+    return account->newOutgoingCall(finalToUrl);
+}
+
+#ifdef RING_VIDEO
+std::shared_ptr<video::SinkClient>
+Manager::createSinkClient(const std::string& id)
+{
+    const auto& iter = sinkMap_.find(id);
+    if (iter != std::end(sinkMap_)) {
+        if (iter->second.expired())
+            sinkMap_.erase(iter);
+        else
+            return nullptr;
+    }
+
+    auto sink = std::make_shared<video::SinkClient>(id);
+    sinkMap_.emplace(id, sink);
+    return sink;
+}
+
+std::shared_ptr<video::SinkClient>
+Manager::getSinkClient(const std::string& id)
+{
+    const auto& iter = sinkMap_.find(id);
+    if (iter != std::end(sinkMap_))
+        if (auto sink = iter->second.lock())
+            return sink;
+    return nullptr;
+}
+#endif // RING_VIDEO
+
 } // namespace ring
diff --git a/src/manager.h b/src/manager.h
index 476a4717e99fe9da0c78e90a23140154c98d6255..5b76f4513bc5bb8067cc8df80b5350268b96728d 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -1,7 +1,12 @@
 /*
  *  Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
- *  Author : Jean-Philippe Barrette-LaPierre
- *              <jean-philippe.barrette-lapierre@savoirfairelinux.com>
+ *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
+ *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
+ *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
+ *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@savoirfairelinux.com>
+ *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
+ *  Author: Tristan Matthews <tristan.matthews@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,18 +34,989 @@
  *  as that of the covered work.
  */
 
-#ifndef MANAGER_H_
-#define MANAGER_H_
+#pragma once
 
-// we could forward declare ManagerImpl BUT anyone who will call instance
-// will need this include.
-#include "managerimpl.h"
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
 
-namespace ring { namespace Manager {
+#include <string>
+#include <vector>
+#include <list>
+#include <map>
+#include <memory>
+#include <mutex>
+#include <random>
+#include <atomic>
+#include <functional>
 
-ManagerImpl& instance();
+#include "conference.h"
 
-}} // namespace ring::Manager
+#include "account_factory.h"
+#include "call_factory.h"
 
-#endif // MANAGER_H_
+#include "audio/audiolayer.h"
+#include "audio/sound/tone.h"  // for Tone::TONEID declaration
 
+#include "preferences.h"
+#include "noncopyable.h"
+
+namespace ring {
+
+namespace Conf {
+class YamlParser;
+class YamlEmitter;
+}
+
+namespace tls {
+class GnuTlsGlobalInit;
+}
+
+namespace video {
+class SinkClient;
+}
+
+class PluginManager;
+class AudioFile;
+class DTMF;
+class TelephoneTone;
+
+/** To send multiple string */
+typedef std::list<std::string> TokenList;
+
+/** To store conference objects by conference ids */
+typedef std::map<std::string, std::shared_ptr<Conference> > ConferenceMap;
+
+typedef std::set<std::string> CallIDSet;
+
+static const char * const default_conf = "conf";
+
+typedef std::set<std::string> CallIDSet;
+
+/** Manager (controller) of Ring daemon */
+class Manager {
+    private:
+        std::unique_ptr<PluginManager> pluginManager_;
+
+    public:
+        Manager();
+        ~Manager();
+
+        static Manager& instance();
+
+        /**
+         * General preferences configuration
+         */
+        Preferences preferences;
+
+        /**
+         * Voip related preferences
+         */
+        VoipPreference voipPreferences;
+
+        /**
+         * Hook preferences
+         */
+        HookPreference hookPreference;
+
+        /**
+         * Audio preferences
+         */
+        AudioPreference audioPreference;
+
+        /**
+         * Shortcut preferences
+         */
+        ShortcutPreferences shortcutPreferences;
+
+        // Manager should not be accessed until initialized.
+        // FIXME this is an evil hack!
+        static std::atomic_bool initialized;
+
+        /**
+         * Initialisation of thread (sound) and map.
+         * Init a new VoIPLink, audio codec and audio driver
+         */
+        void init(const std::string &config_file);
+
+        void setPath(const std::string &path);
+
+        /*
+         * Terminate all threads and exit DBus loop
+         */
+        void finish() noexcept;
+
+        /**
+         * Accessor to audiodriver.
+         * it's multi-thread and use mutex internally
+         * @return AudioLayer*  The audio layer object
+         */
+        std::shared_ptr<AudioLayer> getAudioDriver();
+
+        void startAudioDriverStream();
+
+        /**
+         * Functions which occur with a user's action
+         * Place a new call
+         * @param accountId	The account to make the call with
+         * @param to  The recipient of the call
+         * @param conf_id The conference identifier if any
+         * @return id The call ID on success, empty string otherwise
+         */
+        std::string outgoingCall(const std::string& accountId,
+                                 const std::string& to,
+                                 const std::string& conf_id = "");
+
+        /**
+         * Functions which occur with a user's action
+         * Answer the call
+         * @param id  The call identifier
+         */
+        bool answerCall(const std::string& id);
+
+        /**
+         * Functions which occur with a user's action
+         * Hangup the call
+         * @param id  The call identifier
+         */
+        bool hangupCall(const std::string& id);
+
+
+        /**
+         * Functions which occur with a user's action
+         * Hangup the conference (hangup every participants)
+         * @param id  The call identifier
+         */
+        bool hangupConference(const std::string& id);
+
+        /**
+         * Functions which occur with a user's action
+         * Put the call on hold
+         * @param id  The call identifier
+         */
+        bool onHoldCall(const std::string& id);
+
+        /**
+         * Functions which occur with a user's action
+         * Put the call off hold
+         * @param id  The call identifier
+         */
+        bool offHoldCall(const std::string& id);
+
+        /**
+         * Functions which occur with a user's action
+         * Put the media of a call on mute or unmute
+         * @param callID  The call identifier
+         * @param mediaType The media type; eg : AUDIO or VIDEO
+         * @param is_muted true to mute, false to unmute
+         */
+        bool muteMediaCall(const std::string& callId, const std::string& mediaType, bool is_muted);
+
+        /**
+         * Functions which occur with a user's action
+         * Transfer the call
+         * @param id  The call identifier
+         * @param to  The recipient of the transfer
+         */
+        bool transferCall(const std::string& id, const std::string& to);
+
+        /**
+         * Attended transfer
+         * @param The call id to be transfered
+         * @param The target
+         */
+        bool attendedTransfer(const std::string& transferID, const std::string& targetID);
+
+        /**
+         * Notify the client the transfer is successful
+         */
+        void transferSucceeded();
+
+        /**
+         * Notify the client that the transfer failed
+         */
+        void transferFailed();
+
+        /**
+         * Functions which occur with a user's action
+         * Refuse the call
+         * @param id  The call identifier
+         */
+        bool refuseCall(const std::string& id);
+
+        /**
+         * Create a new conference given two participant
+         * @param the first participant ID
+         * @param the second participant ID
+         */
+        std::shared_ptr<Conference>
+        createConference(const std::string& id1, const std::string& id2);
+
+        /**
+         * Delete this conference
+         * @param the conference ID
+         */
+        void removeConference(const std::string& conference_id);
+
+        /**
+         * Return the conference id for which this call is attached
+         * @ param the call id
+         */
+        std::shared_ptr<Conference>
+        getConferenceFromCallID(const std::string& call_id);
+
+        /**
+         * Hold every participant to a conference
+         * @param the conference id
+         */
+        bool holdConference(const std::string& conference_id);
+
+        /**
+         * Unhold all conference participants
+         * @param the conference id
+         */
+        bool unHoldConference(const std::string& conference_id);
+
+        /**
+         * Test if this id is a conference (usefull to test current call)
+         * @param the call id
+         */
+        bool isConference(const std::string& call_id) const;
+
+        /**
+         * Test if a call id corresponds to a conference participant
+         * @param the call id
+         */
+        bool isConferenceParticipant(const std::string& call_id);
+
+        /**
+         * Add a participant to a conference
+         * @param the call id
+         * @param the conference id
+         */
+        bool addParticipant(const std::string& call_id, const std::string& conference_id);
+
+        /**
+         * Bind the main participant to a conference (mainly called on a double click action)
+         * @param the conference id
+         */
+        bool addMainParticipant(const std::string& conference_id);
+
+        /**
+         * Join two participants to create a conference
+         * @param the fist call id
+         * @param the second call id
+         */
+        bool joinParticipant(const std::string& call_id1,
+                             const std::string& call_id2);
+
+        /**
+         * Create a conference from a list of participant
+         * @param A vector containing the list of participant
+         */
+        void createConfFromParticipantList(const std::vector< std::string > &);
+
+        /**
+         * Detach a participant from a conference, put the call on hold, do not hangup it
+         * @param call id
+         * @param the current call id
+         */
+        bool detachParticipant(const std::string& call_id);
+
+        /**
+         * Remove the conference participant from a conference
+         * @param call id
+         */
+        void removeParticipant(const std::string& call_id);
+
+        /**
+         * Join two conference together into one unique conference
+         */
+        bool joinConference(const std::string& conf_id1, const std::string& conf_id2);
+
+        void addStream(Call& call);
+
+        void removeStream(Call& call);
+
+        /**
+         * Save config to file
+         */
+        void saveConfig();
+
+        /**
+         * @return true if we tried to register once
+         */
+        bool hasTriedToRegister_;
+
+        /**
+         * Play a ringtone
+         */
+        void playTone();
+
+        /**
+         * Play a special ringtone ( BUSY ) if there's at least one message on the voice mail
+         */
+        void playToneWithMessage();
+
+        /**
+         * Acts on the audio streams and audio files
+         */
+        void stopTone();
+
+        /**
+         * Handle incoming call and notify user
+         * @param call A call pointer
+         * @param accountId an account id
+         */
+        void incomingCall(Call &call, const std::string& accountId);
+
+        /**
+         * Notify the user that the recipient of the call has answered and the put the
+         * call in Current state
+         * @param id  The call identifier
+         */
+        void peerAnsweredCall(Call& call);
+
+        /**
+         * Rings back because the outgoing call is ringing and the put the
+         * call in Ringing state
+         * @param id  The call identifier
+         */
+        void peerRingingCall(Call& call);
+
+        /**
+         * Put the call in Hungup state, remove the call from the list
+         * @param id  The call identifier
+         */
+        void peerHungupCall(Call& call);
+
+#if HAVE_INSTANT_MESSAGING
+        /**
+         * Notify the client with an incoming message
+         * @param accountId	The account identifier
+         * @param message The content of the message
+         */
+        void incomingMessage(const std::string& callID, const std::string& from, const std::string& message);
+
+
+        /**
+         * Send a new text message to the call, if participate to a conference, send to all participant.
+         * @param callID	The call to send the message
+         * @param message	The content of the message
+        * @param from	        The sender of this message (could be another participant of a conference)
+         */
+        bool sendCallTextMessage(const std::string& callID, const std::string& message, const std::string& from);
+#endif // HAVE_INSTANT_MESSAGING
+
+        /**
+         * Notify the client he has voice mails
+         * @param accountId	  The account identifier
+         * @param nb_msg The number of messages
+         */
+        void startVoiceMessageNotification(const std::string& accountId, int nb_msg);
+
+        /**
+         * ConfigurationManager - Send registration request
+         * @param accountId The account to register/unregister
+         * @param enable The flag for the type of registration
+         *		 false for unregistration request
+         *		 true for registration request
+         */
+        void sendRegister(const std::string& accountId, bool enable);
+
+        void sendTextMessage(const std::string& accountID, const std::string& to, const std::string& message);
+
+        /**
+         * Get account list
+         * @return std::vector<std::string> A list of accoundIDs
+         */
+        std::vector<std::string> getAccountList() const;
+
+        /**
+         * Set the account order in the config file
+         */
+        void setAccountsOrder(const std::string& order);
+
+        /**
+         * Retrieve details about a given account
+         * @param accountID	  The account identifier
+         * @return std::map< std::string, std::string > The account details
+         */
+        std::map<std::string, std::string> getAccountDetails(const std::string& accountID) const;
+
+        /**
+         * Retrieve volatile details such as recent registration errors
+         * @param accountID The account identifier
+         * @return std::map< std::string, std::string > The account volatile details
+         */
+        std::map<std::string, std::string> getVolatileAccountDetails(const std::string& accountID) const;
+
+        /**
+         * Retrieve details about a given call
+         * @param callID	  The account identifier
+         * @return std::map< std::string, std::string > The call details
+         */
+        std::map<std::string, std::string> getCallDetails(const std::string& callID);
+
+        /**
+         * Get call list
+         * @return std::vector<std::string> A list of call IDs
+         */
+        std::vector<std::string> getCallList() const;
+
+        /**
+         * Retrieve details about a given call
+         * @param callID	  The account identifier
+         * @return std::map< std::string, std::string > The call details
+         */
+        std::map<std::string, std::string> getConferenceDetails(const std::string& callID) const;
+
+        /**
+         * Get call list
+         * @return std::vector<std::string> A list of call IDs
+         */
+        std::vector<std::string> getConferenceList() const;
+
+
+        /**
+         * Get a list of participant to a conference
+         * @return std::vector<std::string> A list of call IDs
+         */
+        std::vector<std::string> getParticipantList(const std::string& confID) const;
+
+        /**
+         * Get a list of the display names for everyone in a conference
+         * @return std::vector<std::string> A list of display names
+         */
+        std::vector<std::string> getDisplayNames(const std::string& confID) const;
+
+        std::string getConferenceId(const std::string& callID);
+
+        /**
+         * Save the details of an existing account, given the account ID
+         * This will load the configuration map with the given data.
+         * It will also register/unregister links where the 'Enabled' switched.
+         * @param accountID	  The account identifier
+         * @param details	  The account parameters
+         */
+        void setAccountDetails(const std::string& accountID,
+                               const std::map<std::string, ::std::string > &details);
+
+        /**
+         * Add a new account, and give it a new account ID automatically
+         * @param details The new account parameters
+         * @return The account Id given to the new account
+         */
+        std::string addAccount(const std::map<std::string, std::string> &details);
+
+        /**
+         * Delete an existing account, unregister VoIPLink associated, and
+         * purge from configuration.
+         * @param accountID	The account unique ID
+         */
+        void removeAccount(const std::string& accountID);
+
+        /**
+         * Set input audio plugin
+         * @param audioPlugin The audio plugin
+         */
+        void setAudioPlugin(const std::string& audioPlugin);
+
+        /**
+             * Set audio device
+             * @param index The index of the soundcard
+             * @param the type of stream, either PLAYBACK, CAPTURE, RINGTONE
+             */
+        void setAudioDevice(int index, DeviceType streamType);
+
+        /**
+         * Get list of supported audio output device
+         * @return std::vector<std::string> A list of the audio devices supporting playback
+         */
+        std::vector<std::string> getAudioOutputDeviceList();
+
+        /**
+         * Get list of supported audio input device
+         * @return std::vector<std::string> A list of the audio devices supporting capture
+         */
+        std::vector<std::string> getAudioInputDeviceList();
+
+        /**
+         * Get string array representing integer indexes of output, input, and ringtone device
+         * @return std::vector<std::string> A list of the current audio devices
+         */
+        std::vector<std::string> getCurrentAudioDevicesIndex();
+
+        /**
+         * Get index of an audio device
+         * @param name The string description of an audio device
+         * @return int  His index
+         */
+        int getAudioInputDeviceIndex(const std::string &name);
+        int getAudioOutputDeviceIndex(const std::string &name);
+
+        /**
+         * Get current alsa plugin
+         * @return std::string  The Alsa plugin
+         */
+        std::string getCurrentAudioOutputPlugin() const;
+
+        /**
+         * Get the noise reduction engin state from
+         * the current audio layer.
+         */
+        bool getNoiseSuppressState() const;
+
+        /**
+         * Set the noise reduction engin state in the current
+         * audio layer.
+         */
+        void setNoiseSuppressState(bool state);
+
+        bool isAGCEnabled() const;
+        void setAGCState(bool enabled);
+
+        bool switchInput(const std::string& callid, const std::string& res);
+
+        /**
+         * Ringtone option.
+         * If ringtone is enabled, ringtone on incoming call use custom choice. If not, only standart tone.
+         * @return int	1 if enabled
+         *	        0 otherwise
+         */
+        int isRingtoneEnabled(const std::string& id);
+
+        /**
+         * Set the ringtone option
+         * Inverse current value
+         */
+        void ringtoneEnabled(const std::string& id);
+
+        /**
+         * Get is always recording functionality
+         */
+        bool getIsAlwaysRecording() const;
+
+        /**
+         * Set is always recording functionality, every calls will then be set in RECORDING mode
+         * once answered
+         */
+        void setIsAlwaysRecording(bool isAlwaysRec);
+
+        /**
+         * Set recording on / off
+         * Start recording
+         * @param id  The call identifier
+         * Returns true if the call was set to record
+         */
+        bool toggleRecordingCall(const std::string& id);
+
+        /**
+         * Return true if the call is currently recorded
+         */
+        bool isRecording(const std::string& id);
+
+        /**
+         * Start playback fo a recorded file if and only if audio layer is not already started.
+         * @param File path of the file to play
+             */
+        bool startRecordedFilePlayback(const std::string&);
+
+        void recordingPlaybackSeek(const double value);
+
+        /**
+         * Stop playback of recorded file
+         * @param File of the file to stop
+         */
+        void stopRecordedFilePlayback(const std::string&);
+
+        /**
+         * Set the maximum number of days to keep in the history
+         * @param calls The number of days
+         */
+        void setHistoryLimit(int days);
+
+        /**
+         * Get the maximum number of days to keep in the history
+         * @return double The number of days
+         */
+        int getHistoryLimit() const;
+
+        /**
+         * Configure the start-up option
+         * @return int	1 if Ring should start in the system tray
+         *	        0 otherwise
+         */
+        int isStartHidden();
+
+        /**
+         * Configure the start-up option
+         * At startup, Ring can be displayed or start hidden in the system tray
+         */
+        void startHidden();
+
+        /**
+         * Get the audio manager
+         * @return int The audio manager
+         *		    "alsa"
+         *		    "pulseaudio"
+         */
+        std::string getAudioManager() const;
+
+        /**
+         * Set the audio manager
+         * @return true if api is now in use, false otherwise
+         */
+        bool setAudioManager(const std::string &api);
+
+        /**
+         * Callback called when the audio layer initialised with its
+         * preferred format.
+         */
+        AudioFormat hardwareAudioFormatChanged(AudioFormat format);
+
+        /**
+         * Should be called by any component dealing with an external
+         * audio source, indicating the format used so the mixer format
+         * can be eventually adapted.
+         * @returns the new format used by the main buffer.
+         */
+        AudioFormat audioFormatUsed(AudioFormat format);
+
+        /**
+         * Handle audio sounds heard by a caller while they wait for their
+         * connection to a called party to be completed.
+         */
+        void ringback();
+
+        /**
+         * Handle played music when an incoming call occurs
+         */
+        void playRingtone(const std::string& accountID);
+
+        /**
+         * Handle played music when a congestion occurs
+         */
+        void congestion();
+
+        /**
+         * Play the dtmf-associated sound
+         * @param code  The pressed key
+         */
+        void playDtmf(char code);
+
+        /**
+         * Handle played sound when a call can not be conpleted because of a busy recipient
+         */
+        void callBusy(Call& call);
+
+        /**
+         * Handle played sound when a failure occurs
+         */
+        void callFailure(Call& call, int code=0);
+
+        /**
+         * Retrieve the current telephone tone
+         * @return AudioLoop*   The audio tone or 0 if no tone (init before calling this function)
+         */
+        AudioLoop* getTelephoneTone();
+
+        /**
+         * Retrieve the current telephone file
+         * @return AudioLoop* The audio file or 0 if the wav is stopped
+         */
+        AudioLoop* getTelephoneFile();
+
+        /**
+         * @return true is there is one or many incoming call waiting
+         * new call, not anwsered or refused
+         */
+        bool incomingCallsWaiting();
+
+        /**
+         * Return a new random callid that is not present in the list
+         * @return std::string A brand new callid
+         */
+        std::string getNewCallID();
+
+        /**
+         * Get the current call
+         * @return std::shared_ptr<Call> A call shared pointer (could be empty)
+         */
+        std::shared_ptr<Call> getCurrentCall() const;
+
+        /**
+         * Get the current call id
+         * @return std::string	The call id or ""
+         */
+        const std::string getCurrentCallId() const;
+
+        /**
+         * Check if a call is the current one
+         * @param call the new call
+         * @return bool True if the call is the current
+         */
+        bool isCurrentCall(const Call& call) const;
+
+        void initAudioDriver();
+
+        /**
+         * Load the accounts order set by the user from the dringrc config file
+         * @return std::vector<std::string> A vector containing the account ID's
+         */
+        std::vector<std::string> loadAccountOrder() const;
+
+
+    private:
+        void removeAccounts();
+
+        bool parseConfiguration();
+
+        // Set the ringtone or recorded call to be played
+        void updateAudioFile(const std::string &file, int sampleRate);
+
+        /**
+         * Get the Call referred to by callID. If the Call does not exist, return NULL
+         */
+        std::shared_ptr<Call> getCallFromCallID(const std::string &callID);
+
+        /**
+         * Process remaining participant given a conference and the current call id.
+         * Mainly called when a participant is detached or hagned up
+         * @param current call id
+         * @param conference pointer
+         */
+        void processRemainingParticipants(Conference &conf);
+
+        /**
+         * Create config directory in home user and return configuration file path
+         */
+        std::string retrieveConfigPath() const;
+
+        void unsetCurrentCall();
+
+        void switchCall(std::shared_ptr<Call> call);
+
+        /*
+         * Play one tone
+         * @return false if the driver is uninitialize
+         */
+        void playATone(Tone::TONEID toneId);
+
+        /** Current Call ID */
+        std::shared_ptr<Call> currentCall_ = nullptr;
+
+        /** Protected current call access */
+        std::mutex currentCallMutex_;
+
+        /** Audio layer */
+        std::shared_ptr<AudioLayer> audiodriver_{nullptr};
+
+        // Main thread
+        std::unique_ptr<DTMF> dtmfKey_;
+
+        /** Buffer to generate DTMF */
+        AudioBuffer dtmfBuf_;
+
+        /////////////////////
+        // Protected by Mutex
+        /////////////////////
+        std::mutex toneMutex_;
+        std::unique_ptr<TelephoneTone> telephoneTone_;
+        std::unique_ptr<AudioFile> audiofile_;
+
+        // To handle volume control
+        // short speakerVolume_;
+        // short micVolume_;
+        // End of sound variable
+
+        /**
+         * Mutex used to protect audio layer
+         */
+        std::mutex audioLayerMutex_;
+
+        /**
+         * Waiting Call Vectors
+         */
+        CallIDSet waitingCalls_;
+
+        /**
+         * Protect waiting call list, access by many voip/audio threads
+         */
+        std::mutex waitingCallsMutex_;
+
+        /**
+         * Add incoming callid to the waiting list
+         * @param id std::string to add
+         */
+        void addWaitingCall(const std::string& id);
+
+        /**
+         * Remove incoming callid to the waiting list
+         * @param id std::string to remove
+         */
+        void removeWaitingCall(const std::string& id);
+
+        /**
+         * Path of the ConfigFile
+         */
+        std::string path_;
+
+        /**
+         * Load the account map from configuration
+         */
+        int loadAccountMap(const YAML::Node &node);
+
+        /**
+         * Instance of the RingBufferPool for the whole application
+         *
+         * In order to send signal to other parts of the application, one must pass through the RingBufferMananger.
+         * Audio instances must be registered into the RingBufferMananger and bound together via the Manager.
+         *
+         */
+        std::unique_ptr<RingBufferPool> ringbufferpool_;
+
+    public:
+
+        /**
+         * Return a pointer to the instance of the RingBufferPool
+         */
+        RingBufferPool& getRingBufferPool() { return *ringbufferpool_; }
+
+        /**
+         * Tell if there is a current call processed
+         * @return bool True if there is a current call
+         */
+        bool hasCurrentCall() const;
+
+        /**
+         * Get an account pointer, looks for both SIP and IAX
+         * @param accountID account ID to get
+         * @return std::shared_ptr<Account> Shared pointer on an Account instance or nullptr if not found
+         */
+        template <class T=Account>
+        std::shared_ptr<T> getAccount(const std::string& accountID) const {
+            return accountFactory_.getAccount<T>(accountID);
+        }
+
+        template <class T=Account>
+        std::vector<std::shared_ptr<T> > getAllAccounts() const {
+            return accountFactory_.getAllAccounts<T>();
+        }
+
+        template <class T=Account>
+        bool accountCount() const {
+            return accountFactory_.accountCount<T>();
+        }
+
+        std::shared_ptr<Account> getIP2IPAccount() const {
+            return accountFactory_.getIP2IPAccount();
+        }
+
+        // only used by test framework
+        bool hasAccount(const std::string& accountID) {
+            return accountFactory_.hasAccount(accountID);
+        }
+
+        /**
+         * Send registration for all enabled accounts
+         */
+        void registerAccounts();
+
+        /**
+         * Suspends Ring's audio processing if no calls remain, allowing
+         * other applications to resume audio.
+         * See:
+         * https://projects.savoirfairelinux.com/issues/7037
+        */
+        void checkAudio();
+
+        /**
+         * Call periodically to poll for VoIP events */
+        void
+        pollEvents();
+
+        /**
+         * Create a new outgoing 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& toUrl,
+                                              const std::string& preferredAccountId);
+
+        CallFactory callFactory;
+
+        using EventHandler = std::function<void()>;
+
+        /**
+         * Install an event handler called periodically by pollEvents().
+         * @param handlerId an unique identifier for the handler.
+         * @param handler the event handler function.
+         */
+        void registerEventHandler(uintptr_t handlerId, EventHandler handler);
+
+        /**
+         * Remove a previously registered event handler.
+         * @param handlerId id of handler to remove.
+         */
+        void unregisterEventHandler(uintptr_t handlerId);
+
+        IceTransportFactory& getIceTransportFactory() { return *ice_tf_; }
+
+        void addTask(const std::function<bool()>&& task);
+
+#ifdef RING_VIDEO
+        std::shared_ptr<video::SinkClient> createSinkClient(const std::string& id="");
+
+        std::shared_ptr<video::SinkClient> getSinkClient(const std::string& id);
+#endif // RING_VIDEO
+
+    private:
+        NON_COPYABLE(Manager);
+
+        std::map<uintptr_t, EventHandler> eventHandlerMap_;
+        decltype(eventHandlerMap_)::iterator nextEventHandler_;
+
+        std::list<std::function<bool()>> pendingTaskList_;
+
+        /**
+         * Test if call is a valid call, i.e. have been created and stored in
+         * call-account map
+         * @param callID the std::string to be tested
+         * @return true if call is created and present in the call-account map
+         */
+        bool isValidCall(const std::string& callID);
+
+        /**
+         * Send unregister for all enabled accounts
+         */
+        void unregisterAccounts();
+
+
+        // Map containing conference pointers
+        ConferenceMap conferenceMap_;
+
+        std::atomic_bool finished_ {false};
+
+        AccountFactory accountFactory_;
+
+        std::mt19937_64 rand_;
+
+        void loadDefaultAccountMap();
+
+        void loadAccount(const YAML::Node &item, int &errorCount,
+                         const std::string &accountOrder);
+
+        /* ICE support */
+        std::unique_ptr<IceTransportFactory> ice_tf_;
+
+        std::unique_ptr<tls::GnuTlsGlobalInit> gnutlGIG_;
+
+        /* Sink ID mapping */
+        std::map<std::string, std::weak_ptr<video::SinkClient>> sinkMap_;
+};
+
+} // namespace ring
diff --git a/src/managerimpl.cpp b/src/managerimpl.cpp
deleted file mode 100644
index 4bad752d2f46aaf7aaa4694ca1ddf95d961ce3c1..0000000000000000000000000000000000000000
--- a/src/managerimpl.cpp
+++ /dev/null
@@ -1,2921 +0,0 @@
-/*
- *  Copyright (C) 2004-2015 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: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com>
- *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@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:
- *
- *  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.
- */
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include "logger.h"
-#include "managerimpl.h"
-#include "account_schema.h"
-#include "plugin_manager.h"
-
-#include "fileutils.h"
-#include "map_utils.h"
-#include "account.h"
-#include "string_utils.h"
-#if HAVE_DHT
-#include "ringdht/ringaccount.h"
-#endif
-
-#include "call_factory.h"
-
-#include "sip/sip_utils.h"
-
-#include "im/instant_messaging.h"
-
-#include "numbercleaner.h"
-#include "config/yamlparser.h"
-
-#if HAVE_ALSA
-#include "audio/alsa/alsalayer.h"
-#endif
-
-#include "audio/sound/tonelist.h"
-#include "audio/sound/audiofile.h"
-#include "audio/sound/dtmf.h"
-#include "audio/ringbufferpool.h"
-#include "manager.h"
-
-#ifdef RING_VIDEO
-#include "client/videomanager.h"
-#endif
-
-#include "conference.h"
-#include "ice_transport.h"
-
-#include "client/ring_signal.h"
-
-#if HAVE_TLS
-#include "gnutls_support.h"
-#endif
-
-#include "libav_utils.h"
-#include "video/sinkclient.h"
-
-#include <cerrno>
-#include <algorithm>
-#include <ctime>
-#include <cstdlib>
-#include <iostream>
-#include <fstream>
-#include <sstream>
-#include <sys/types.h> // mkdir(2)
-#include <sys/stat.h>  // mkdir(2)
-#include <memory>
-#include <mutex>
-
-namespace ring {
-
-std::atomic_bool ManagerImpl::initialized = {false};
-
-static void
-copy_over(const std::string &srcPath, const std::string &destPath)
-{
-    std::ifstream src(srcPath.c_str());
-    std::ofstream dest(destPath.c_str());
-    dest << src.rdbuf();
-    src.close();
-    dest.close();
-}
-
-// Creates a backup of the file at "path" with a .bak suffix appended
-static void
-make_backup(const std::string &path)
-{
-    const std::string backup_path(path + ".bak");
-    copy_over(path, backup_path);
-}
-
-// Restore last backup of the configuration file
-static void
-restore_backup(const std::string &path)
-{
-    const std::string backup_path(path + ".bak");
-    copy_over(backup_path, path);
-}
-
-/**
- * Set pjsip's log level based on the SIPLOGLEVEL environment variable.
- * SIPLOGLEVEL = 0 minimum logging
- * SIPLOGLEVEL = 6 maximum logging
- */
-
-/** Environment variable used to set pjsip's logging level */
-static constexpr const char* SIPLOGLEVEL = "SIPLOGLEVEL";
-
-static void
-setSipLogLevel()
-{
-    char* envvar = getenv(SIPLOGLEVEL);
-    int level = 0;
-
-    if (envvar != nullptr) {
-        if (not (std::istringstream(envvar) >> level))
-            level = 0;
-
-        // From 0 (min) to 6 (max)
-        level = std::max(0, std::min(level, 6));
-    }
-
-    pj_log_set_level(level);
-}
-
-#if HAVE_TLS
-/**
- * Set gnutls's log level based on the RING_TLS_LOGLEVEL environment variable.
- * RING_TLS_LOGLEVEL = 0 minimum logging (default)
- * RING_TLS_LOGLEVEL = 9 maximum logging
- */
-
-static constexpr int RING_TLS_LOGLEVEL = 0;
-
-static void
-tls_print_logs(int level, const char* msg)
-{
-    RING_DBG("GnuTLS [%d]: %s", level, msg);
-}
-
-static void
-setGnuTlsLogLevel()
-{
-    char* envvar = getenv("RING_TLS_LOGLEVEL");
-    int level = RING_TLS_LOGLEVEL;
-
-    if (envvar != nullptr) {
-        int var_level;
-        if (std::istringstream(envvar) >> var_level)
-            level = var_level;
-
-        // From 0 (min) to 9 (max)
-        level = std::max(0, std::min(level, 9));
-    }
-
-    gnutls_global_set_log_level(level);
-    gnutls_global_set_log_function(tls_print_logs);
-}
-#endif // HAVE_TLS
-
-void
-ManagerImpl::loadDefaultAccountMap()
-{
-    accountFactory_.initIP2IPAccount();
-}
-
-ManagerImpl::ManagerImpl() :
-    pluginManager_(new PluginManager)
-    , preferences(), voipPreferences(),
-    hookPreference(),  audioPreference(), shortcutPreferences(),
-    hasTriedToRegister_(false),
-    currentCallMutex_(), dtmfKey_(), dtmfBuf_(0, AudioFormat::MONO()),
-    toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(),
-    waitingCalls_(), waitingCallsMutex_(), path_()
-    , ringbufferpool_(new RingBufferPool)
-    , callFactory(), conferenceMap_()
-    , accountFactory_(), ice_tf_()
-    , gnutlGIG_ {tls::GnuTlsGlobalInit::make_guard()}
-{
-    // initialize random generator
-    // mt19937_64 should be seeded with 2 x 32 bits
-    std::random_device rdev;
-    std::seed_seq seed {rdev(), rdev()};
-    rand_.seed(seed);
-
-    ring::libav_utils::ring_avcodec_init();
-}
-
-ManagerImpl::~ManagerImpl()
-{}
-
-bool
-ManagerImpl::parseConfiguration()
-{
-    bool result = true;
-
-    try {
-        YAML::Node parsedFile = YAML::LoadFile(path_);
-        const int error_count = loadAccountMap(parsedFile);
-
-        if (error_count > 0) {
-            RING_WARN("Errors while parsing %s", path_.c_str());
-            result = false;
-        }
-    } catch (const YAML::BadFile &e) {
-        RING_WARN("Could not open config file: creating default account map");
-        loadDefaultAccountMap();
-    }
-
-    return result;
-}
-
-void
-ManagerImpl::init(const std::string &config_file)
-{
-    // FIXME: this is no good
-    initialized = true;
-
-#define PJSIP_TRY(ret) do {                                 \
-        if (ret != PJ_SUCCESS)                               \
-            throw std::runtime_error(#ret " failed");        \
-    } while (0)
-
-    srand(time(NULL)); // to get random number for RANDOM_PORT
-
-    // Initialize PJSIP (SIP and ICE implementation)
-    PJSIP_TRY(pj_init());
-    setSipLogLevel();
-    PJSIP_TRY(pjlib_util_init());
-    PJSIP_TRY(pjnath_init());
-#undef TRY
-
-    RING_DBG("pjsip version %s for %s initialized",
-             pj_get_version(), PJ_OS_NAME);
-
-#if HAVE_TLS
-    setGnuTlsLogLevel();
-    RING_DBG("GNU TLS version %s initialized", gnutls_check_version(nullptr));
-#endif
-
-    ice_tf_.reset(new IceTransportFactory());
-
-    path_ = config_file.empty() ? retrieveConfigPath() : config_file;
-    RING_DBG("Configuration file path: %s", path_.c_str());
-
-    bool no_errors = true;
-
-    // manager can restart without being recreated (android)
-    finished_ = false;
-
-    try {
-        no_errors = parseConfiguration();
-    } catch (const YAML::Exception &e) {
-        RING_ERR("%s", e.what());
-        no_errors = false;
-    }
-
-    // always back up last error-free configuration
-    if (no_errors) {
-        make_backup(path_);
-    } else {
-        // restore previous configuration
-        RING_WARN("Restoring last working configuration");
-
-        try {
-            // remove accounts from broken configuration
-            removeAccounts();
-            restore_backup(path_);
-            parseConfiguration();
-        } catch (const YAML::Exception &e) {
-            RING_ERR("%s", e.what());
-            RING_WARN("Restoring backup failed, creating default account map");
-            loadDefaultAccountMap();
-        }
-    }
-
-    initAudioDriver();
-
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (audiodriver_) {
-            {
-                std::lock_guard<std::mutex> toneLock(toneMutex_);
-                telephoneTone_.reset(new TelephoneTone(preferences.getZoneToneChoice(), audiodriver_->getSampleRate()));
-            }
-            dtmfKey_.reset(new DTMF(getRingBufferPool().getInternalSamplingRate()));
-        }
-    }
-
-    registerAccounts();
-}
-
-void
-ManagerImpl::setPath(const std::string&)
-{
-    // FIME: needed?
-}
-
-void
-ManagerImpl::finish() noexcept
-{
-    bool expected = false;
-    if (not finished_.compare_exchange_strong(expected, true))
-        return;
-
-    try {
-        // Forbid call creation
-        callFactory.forbid();
-
-        // Hangup all remaining active calls
-        RING_DBG("Hangup %zu remaining call(s)", callFactory.callCount());
-        for (const auto call : callFactory.getAllCalls())
-            hangupCall(call->getCallId());
-        callFactory.clear();
-
-        saveConfig();
-
-        // Disconnect accounts, close link stacks and free allocated ressources
-        unregisterAccounts();
-        accountFactory_.clear();
-
-        {
-            std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-            audiodriver_.reset();
-        }
-
-        ice_tf_.reset();
-        pj_shutdown();
-    } catch (const VoipLinkException &err) {
-        RING_ERR("%s", err.what());
-    }
-}
-
-bool
-ManagerImpl::isCurrentCall(const Call& call) const
-{
-    return currentCall_.get() == &call;
-}
-
-bool
-ManagerImpl::hasCurrentCall() const
-{
-    return static_cast<bool>(currentCall_);
-}
-
-std::shared_ptr<Call>
-ManagerImpl::getCurrentCall() const
-{
-    return currentCall_;
-}
-
-const std::string
-ManagerImpl::getCurrentCallId() const
-{
-    return currentCall_ ? currentCall_->getCallId() : "";
-}
-
-/**
- * Set current call ID to empty string
- */
-void
-ManagerImpl::unsetCurrentCall()
-{
-    currentCall_.reset();
-}
-
-/**
- * Switch of current call id
- * @param id The new callid
- */
-void
-ManagerImpl::switchCall(std::shared_ptr<Call> call)
-{
-    std::lock_guard<std::mutex> m(currentCallMutex_);
-    RING_DBG("----- Switch current call id to '%s' -----",
-          call ? call->getCallId().c_str() : "<nullptr>");
-    currentCall_ = call;
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Management of events' IP-phone user
-///////////////////////////////////////////////////////////////////////////////
-/* Main Thread */
-
-std::string
-ManagerImpl::outgoingCall(const std::string& preferred_account_id,
-                          const std::string& to,
-                          const std::string& conf_id)
-{
-    std::string current_call_id(getCurrentCallId());
-    std::string prefix(hookPreference.getNumberAddPrefix());
-    std::string to_cleaned(NumberCleaner::clean(to, prefix));
-    std::shared_ptr<Call> call;
-
-    try {
-        /* RING_WARN: after this call the account_id is obsolete
-         * as the factory may decide to use another account (like IP2IP).
-         */
-        RING_DBG("New outgoing call to %s", to_cleaned.c_str());
-        call = newOutgoingCall(to_cleaned, preferred_account_id);
-    } catch (const std::exception &e) {
-        RING_ERR("%s", e.what());
-        return {};
-    }
-
-    if (not call)
-        return {};
-
-    auto call_id = call->getCallId();
-
-    stopTone();
-
-    // in any cases we have to detach from current communication
-    if (hasCurrentCall()) {
-        RING_DBG("Has current call (%s) put it onhold", current_call_id.c_str());
-
-        // if this is not a conference and this and is not a conference participant
-        if (not isConference(current_call_id) and not isConferenceParticipant(current_call_id))
-            onHoldCall(current_call_id);
-        else if (isConference(current_call_id) and not isConferenceParticipant(call_id))
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-    }
-
-    switchCall(call);
-    call->setConfId(conf_id);
-
-    return call_id;
-}
-
-//THREAD=Main : for outgoing Call
-bool
-ManagerImpl::answerCall(const std::string& call_id)
-{
-    bool result = true;
-
-    auto call = getCallFromCallID(call_id);
-    if (!call) {
-        RING_ERR("Call %s is NULL", call_id.c_str());
-        return false;
-    }
-
-    // If ring is ringing
-    stopTone();
-
-    // store the current call id
-    std::string current_call_id(getCurrentCallId());
-
-    // in any cases we have to detach from current communication
-    if (hasCurrentCall()) {
-
-        RING_DBG("Currently conversing with %s", current_call_id.c_str());
-
-        if (not isConference(current_call_id) and not isConferenceParticipant(current_call_id)) {
-            RING_DBG("Answer call: Put the current call (%s) on hold", current_call_id.c_str());
-            onHoldCall(current_call_id);
-        } else if (isConference(current_call_id) and not isConferenceParticipant(call_id)) {
-            // if we are talking to a conference and we are answering an incoming call
-            RING_DBG("Detach main participant from conference");
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-        }
-    }
-
-    try {
-        call->answer();
-    } catch (const std::runtime_error &e) {
-        RING_ERR("%s", e.what());
-        result = false;
-    }
-
-    // if it was waiting, it's waiting no more
-    removeWaitingCall(call_id);
-
-    // if we dragged this call into a conference already
-    if (isConferenceParticipant(call_id))
-        switchCall(callFactory.getCall(call->getConfId()));
-    else
-        switchCall(call);
-
-    // Connect streams
-    addStream(*call);
-
-    // Start recording if set in preference
-    if (audioPreference.getIsAlwaysRecording())
-        toggleRecordingCall(call_id);
-
-    //callStateChanged(call_id, "CURRENT");
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "CURRENT", 0);
-
-    return result;
-}
-
-void
-ManagerImpl::checkAudio()
-{
-    if (getCallList().empty()) {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-        if (audiodriver_)
-            audiodriver_->stopStream();
-    }
-}
-
-//THREAD=Main
-bool
-ManagerImpl::hangupCall(const std::string& callId)
-{
-    // store the current call id
-    std::string currentCallId(getCurrentCallId());
-
-    stopTone();
-
-    RING_DBG("Send call state change (HUNGUP) for id %s", callId.c_str());
-    emitSignal<DRing::CallSignal::StateChange>(callId, "HUNGUP", 0);
-
-    /* We often get here when the call was hungup before being created */
-    auto call = getCallFromCallID(callId);
-    if (not call) {
-        RING_WARN("Could not hang up non-existant call %s", callId.c_str());
-        checkAudio();
-        return false;
-    }
-
-    // Disconnect streams
-    removeStream(*call);
-
-    if (isConferenceParticipant(callId)) {
-        removeParticipant(callId);
-    } else {
-        // we are not participating in a conference, current call switched to ""
-        if (not isConference(currentCallId))
-            unsetCurrentCall();
-    }
-
-    try {
-        call->hangup(0);
-        checkAudio();
-    } catch (const VoipLinkException &e) {
-        RING_ERR("%s", e.what());
-        return false;
-    }
-
-    return true;
-}
-
-bool
-ManagerImpl::hangupConference(const std::string& id)
-{
-    RING_DBG("Hangup conference %s", id.c_str());
-
-    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
-
-    if (iter_conf != conferenceMap_.end()) {
-        auto conf = iter_conf->second;
-
-        if (conf) {
-            ParticipantSet participants(conf->getParticipantList());
-
-            for (const auto &item : participants)
-                hangupCall(item);
-        } else {
-            RING_ERR("No such conference %s", id.c_str());
-            return false;
-        }
-    }
-
-    unsetCurrentCall();
-
-    return true;
-}
-
-//THREAD=Main
-bool
-ManagerImpl::onHoldCall(const std::string& callId)
-{
-    bool result = true;
-
-    stopTone();
-
-    std::string current_call_id(getCurrentCallId());
-
-    if (auto call = getCallFromCallID(callId)) {
-        try {
-            call->onhold();
-            removeStream(*call); // Unbind calls in main buffer
-        } catch (const VoipLinkException &e) {
-            RING_ERR("%s", e.what());
-            result = false;
-        }
-    } else {
-        RING_DBG("CallID %s doesn't exist in call onHold", callId.c_str());
-        return false;
-    }
-
-    // Remove call from teh queue if it was still there
-    removeWaitingCall(callId);
-
-    // keeps current call id if the action is not holding this call or a new outgoing call
-    // this could happen in case of a conference
-    if (current_call_id == callId)
-        unsetCurrentCall();
-
-    emitSignal<DRing::CallSignal::StateChange>(callId, "HOLD", 0);
-
-    return result;
-}
-
-//THREAD=Main
-bool
-ManagerImpl::offHoldCall(const std::string& callId)
-{
-    bool result = true;
-
-    stopTone();
-
-    const std::string currentCallId(getCurrentCallId());
-
-    // Place current call on hold if it isn't
-    if (hasCurrentCall()) {
-        if (not isConference(currentCallId) and not isConferenceParticipant(currentCallId)) {
-            RING_DBG("Has current call (%s), put on hold", currentCallId.c_str());
-            //FIXME: ebail
-            // if 2 consecutive offHoldCall done, the second one should be ignored (already offhold)
-            // this call put the call onHold
-            onHoldCall(currentCallId);
-        } else if (isConference(currentCallId) && callId != currentCallId) {
-            holdConference(currentCallId);
-        } else if (isConference(currentCallId) and not isConferenceParticipant(callId))
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-    }
-
-    std::shared_ptr<Call> call;
-    try {
-        call = getCallFromCallID(callId);
-        if (call)
-            call->offhold();
-        else
-            result = false;
-    } catch (const VoipLinkException &e) {
-        RING_ERR("%s", e.what());
-        return false;
-    }
-
-    emitSignal<DRing::CallSignal::StateChange>(callId, "UNHOLD", 0);
-
-    if (isConferenceParticipant(callId))
-        switchCall(getCallFromCallID(call->getConfId()));
-    else
-        switchCall(call);
-
-    addStream(*call);
-
-    return result;
-}
-
-bool
-ManagerImpl::muteMediaCall(const std::string& callId, const std::string& mediaType, bool is_muted)
-{
-    if (auto call = getCallFromCallID(callId)) {
-        call->muteMedia(mediaType, is_muted);
-        return true;
-    } else {
-        RING_DBG("CallID %s doesn't exist in call muting", callId.c_str());
-        return false;
-    }
-}
-
-
-//THREAD=Main
-bool
-ManagerImpl::transferCall(const std::string& callId, const std::string& to)
-{
-    if (isConferenceParticipant(callId)) {
-        removeParticipant(callId);
-    } else if (not isConference(getCurrentCallId()))
-        unsetCurrentCall();
-
-    if (auto call = getCallFromCallID(callId))
-        call->transfer(to);
-    else
-        return false;
-
-    // remove waiting call in case we make transfer without even answer
-    removeWaitingCall(callId);
-
-    return true;
-}
-
-void
-ManagerImpl::transferFailed()
-{
-    emitSignal<DRing::CallSignal::TransferFailed>();
-}
-
-void
-ManagerImpl::transferSucceeded()
-{
-    transferSucceeded();
-}
-
-bool
-ManagerImpl::attendedTransfer(const std::string& transferID,
-                              const std::string& targetID)
-{
-    if (auto call = getCallFromCallID(transferID))
-        return call->attendedTransfer(targetID);
-
-    return false;
-}
-
-//THREAD=Main : Call:Incoming
-bool
-ManagerImpl::refuseCall(const std::string& id)
-{
-    auto call = getCallFromCallID(id);
-    if (!call)
-        return false;
-
-    stopTone();
-
-    if (getCallList().size() <= 1) {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-        audiodriver_->stopStream();
-    }
-
-    call->refuse();
-
-    checkAudio();
-
-    removeWaitingCall(id);
-
-    emitSignal<DRing::CallSignal::StateChange>(id, "HUNGUP", 0);
-
-    // Disconnect streams
-    removeStream(*call);
-
-    return true;
-}
-
-std::shared_ptr<Conference>
-ManagerImpl::createConference(const std::string& id1, const std::string& id2)
-{
-    RING_DBG("Create conference with call %s and %s", id1.c_str(), id2.c_str());
-
-    auto conf = std::make_shared<Conference>();
-
-    conf->add(id1);
-    conf->add(id2);
-
-    // Add conference to map
-    conferenceMap_.insert(std::make_pair(conf->getConfID(), conf));
-
-    emitSignal<DRing::CallSignal::ConferenceCreated>(conf->getConfID());
-
-    return conf;
-}
-
-void
-ManagerImpl::removeConference(const std::string& conference_id)
-{
-    RING_DBG("Remove conference %s", conference_id.c_str());
-    RING_DBG("number of participants: %u", conferenceMap_.size());
-    ConferenceMap::iterator iter = conferenceMap_.find(conference_id);
-
-    std::shared_ptr<Conference> conf;
-
-    if (iter != conferenceMap_.end())
-        conf = iter->second;
-
-    if (not conf) {
-        RING_ERR("Conference not found");
-        return;
-    }
-
-    emitSignal<DRing::CallSignal::ConferenceRemoved>(conference_id);
-
-    // We now need to bind the audio to the remain participant
-
-    // Unbind main participant audio from conference
-    getRingBufferPool().unBindAll(RingBufferPool::DEFAULT_ID);
-
-    ParticipantSet participants(conf->getParticipantList());
-
-    // bind main participant audio to remaining conference call
-    ParticipantSet::iterator iter_p = participants.begin();
-
-    if (iter_p != participants.end())
-        getRingBufferPool().bindCallID(*iter_p, RingBufferPool::DEFAULT_ID);
-
-    // Then remove the conference from the conference map
-    if (conferenceMap_.erase(conference_id))
-        RING_DBG("Conference %s removed successfully", conference_id.c_str());
-    else
-        RING_ERR("Cannot remove conference: %s", conference_id.c_str());
-}
-
-std::shared_ptr<Conference>
-ManagerImpl::getConferenceFromCallID(const std::string& call_id)
-{
-    auto call = getCallFromCallID(call_id);
-    if (!call)
-        return nullptr;
-
-    ConferenceMap::const_iterator iter(conferenceMap_.find(call->getConfId()));
-
-    if (iter != conferenceMap_.end())
-        return iter->second;
-    else
-        return nullptr;
-}
-
-bool
-ManagerImpl::holdConference(const std::string& id)
-{
-    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
-
-    if (iter_conf == conferenceMap_.end())
-        return false;
-
-    auto conf = iter_conf->second;
-
-    bool isRec = conf->getState() == Conference::ACTIVE_ATTACHED_REC or
-                 conf->getState() == Conference::ACTIVE_DETACHED_REC or
-                 conf->getState() == Conference::HOLD_REC;
-
-    ParticipantSet participants(conf->getParticipantList());
-
-    for (const auto &item : participants) {
-        switchCall(getCallFromCallID(item));
-        onHoldCall(item);
-    }
-
-    conf->setState(isRec ? Conference::HOLD_REC : Conference::HOLD);
-
-    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
-
-    return true;
-}
-
-bool
-ManagerImpl::unHoldConference(const std::string& id)
-{
-    ConferenceMap::iterator iter_conf = conferenceMap_.find(id);
-
-    if (iter_conf == conferenceMap_.end() or iter_conf->second == 0)
-        return false;
-
-    auto conf = iter_conf->second;
-
-    bool isRec = conf->getState() == Conference::ACTIVE_ATTACHED_REC or
-        conf->getState() == Conference::ACTIVE_DETACHED_REC or
-        conf->getState() == Conference::HOLD_REC;
-
-    ParticipantSet participants(conf->getParticipantList());
-
-    for (const auto &item : participants) {
-        if (auto call = getCallFromCallID(item)) {
-            // if one call is currently recording, the conference is in state recording
-            isRec |= call->isRecording();
-
-            switchCall(call);
-            offHoldCall(item);
-        }
-    }
-
-    conf->setState(isRec ? Conference::ACTIVE_ATTACHED_REC : Conference::ACTIVE_ATTACHED);
-
-    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
-
-    return true;
-}
-
-bool
-ManagerImpl::isConference(const std::string& id) const
-{
-    return conferenceMap_.find(id) != conferenceMap_.end();
-}
-
-bool
-ManagerImpl::isConferenceParticipant(const std::string& call_id)
-{
-    auto call = getCallFromCallID(call_id);
-    return call and not call->getConfId().empty();
-}
-
-bool
-ManagerImpl::addParticipant(const std::string& callId,
-                            const std::string& conferenceId)
-{
-    RING_DBG("Add participant %s to %s", callId.c_str(), conferenceId.c_str());
-    ConferenceMap::iterator iter = conferenceMap_.find(conferenceId);
-
-    if (iter == conferenceMap_.end()) {
-        RING_ERR("Conference id is not valid");
-        return false;
-    }
-
-    auto call = getCallFromCallID(callId);
-    if (!call) {
-        RING_ERR("Call id %s is not valid", callId.c_str());
-        return false;
-    }
-
-    // ensure that calls are only in one conference at a time
-    if (isConferenceParticipant(callId))
-        detachParticipant(callId);
-
-    // store the current call id (it will change in offHoldCall or in answerCall)
-    std::string current_call_id(getCurrentCallId());
-
-    // detach from prior communication and switch to this conference
-    if (current_call_id != callId) {
-        if (isConference(current_call_id))
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-        else
-            onHoldCall(current_call_id);
-    }
-
-    // TODO: remove this ugly hack => There should be different calls when double clicking
-    // a conference to add main participant to it, or (in this case) adding a participant
-    // toconference
-    unsetCurrentCall();
-
-    // Add main participant
-    addMainParticipant(conferenceId);
-
-    auto conf = iter->second;
-    switchCall(getCallFromCallID(conf->getConfID()));
-
-    // Add coresponding IDs in conf and call
-    call->setConfId(conf->getConfID());
-    conf->add(callId);
-
-    // Connect new audio streams together
-    getRingBufferPool().unBindAll(callId);
-
-    std::map<std::string, std::string> callDetails(getCallDetails(callId));
-    std::string callState(callDetails.find("CALL_STATE")->second);
-
-    if (callState == "HOLD") {
-        conf->bindParticipant(callId);
-        offHoldCall(callId);
-    } else if (callState == "INCOMING") {
-        conf->bindParticipant(callId);
-        answerCall(callId);
-    } else if (callState == "CURRENT")
-        conf->bindParticipant(callId);
-
-    ParticipantSet participants(conf->getParticipantList());
-
-    if (participants.empty())
-        RING_ERR("Participant list is empty for this conference");
-
-    // Connect stream
-    addStream(*call);
-    return true;
-}
-
-bool
-ManagerImpl::addMainParticipant(const std::string& conference_id)
-{
-    if (hasCurrentCall()) {
-        std::string current_call_id(getCurrentCallId());
-
-        if (isConference(current_call_id))
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-        else
-            onHoldCall(current_call_id);
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        ConferenceMap::const_iterator iter = conferenceMap_.find(conference_id);
-
-        if (iter == conferenceMap_.end() or iter->second == 0)
-            return false;
-
-        auto conf = iter->second;
-
-        ParticipantSet participants(conf->getParticipantList());
-
-        for (const auto &item_p : participants) {
-            getRingBufferPool().bindCallID(item_p, RingBufferPool::DEFAULT_ID);
-            // Reset ringbuffer's readpointers
-            getRingBufferPool().flush(item_p);
-        }
-
-        getRingBufferPool().flush(RingBufferPool::DEFAULT_ID);
-
-        if (conf->getState() == Conference::ACTIVE_DETACHED)
-            conf->setState(Conference::ACTIVE_ATTACHED);
-        else if (conf->getState() == Conference::ACTIVE_DETACHED_REC)
-            conf->setState(Conference::ACTIVE_ATTACHED_REC);
-        else
-            RING_WARN("Invalid conference state while adding main participant");
-
-        emitSignal<DRing::CallSignal::ConferenceChanged>(conference_id, conf->getStateStr());
-    }
-
-    switchCall(getCallFromCallID(conference_id));
-    return true;
-}
-
-std::shared_ptr<Call>
-ManagerImpl::getCallFromCallID(const std::string& callID)
-{
-    return callFactory.getCall(callID);
-}
-
-bool
-ManagerImpl::joinParticipant(const std::string& callId1,
-                             const std::string& callId2)
-{
-    if (callId1 == callId2) {
-        RING_ERR("Cannot join participant %s to itself", callId1.c_str());
-        return false;
-    }
-
-    // Set corresponding conference ids for call 1
-    auto call1 = getCallFromCallID(callId1);
-    if (!call1) {
-        RING_ERR("Could not find call %s", callId1.c_str());
-        return false;
-    }
-
-    // Set corresponding conderence details
-    auto call2 = getCallFromCallID(callId2);
-    if (!call2) {
-        RING_ERR("Could not find call %s", callId2.c_str());
-        return false;
-    }
-
-    // ensure that calls are only in one conference at a time
-    if (isConferenceParticipant(callId1))
-        detachParticipant(callId1);
-    if (isConferenceParticipant(callId2))
-        detachParticipant(callId2);
-
-    std::map<std::string, std::string> call1Details(getCallDetails(callId1));
-    std::map<std::string, std::string> call2Details(getCallDetails(callId2));
-
-    std::string current_call_id(getCurrentCallId());
-    RING_DBG("Current Call ID %s", current_call_id.c_str());
-
-    // detach from the conference and switch to this conference
-    if ((current_call_id != callId1) and (current_call_id != callId2)) {
-        // If currently in a conference
-        if (isConference(current_call_id))
-            detachParticipant(RingBufferPool::DEFAULT_ID);
-        else
-            onHoldCall(current_call_id); // currently in a call
-    }
-
-
-    auto conf = createConference(callId1, callId2);
-
-    call1->setConfId(conf->getConfID());
-    getRingBufferPool().unBindAll(callId1);
-
-    call2->setConfId(conf->getConfID());
-    getRingBufferPool().unBindAll(callId2);
-
-    // Process call1 according to its state
-    std::string call1_state_str(call1Details.find("CALL_STATE")->second);
-    RING_DBG("Process call %s state: %s", callId1.c_str(), call1_state_str.c_str());
-
-    if (call1_state_str == "HOLD") {
-        conf->bindParticipant(callId1);
-        offHoldCall(callId1);
-    } else if (call1_state_str == "INCOMING") {
-        conf->bindParticipant(callId1);
-        answerCall(callId1);
-    } else if (call1_state_str == "CURRENT") {
-        conf->bindParticipant(callId1);
-    } else if (call1_state_str == "INACTIVE") {
-        conf->bindParticipant(callId1);
-        answerCall(callId1);
-    } else
-        RING_WARN("Call state not recognized");
-
-    // Process call2 according to its state
-    std::string call2_state_str(call2Details.find("CALL_STATE")->second);
-    RING_DBG("Process call %s state: %s", callId2.c_str(), call2_state_str.c_str());
-
-    if (call2_state_str == "HOLD") {
-        conf->bindParticipant(callId2);
-        offHoldCall(callId2);
-    } else if (call2_state_str == "INCOMING") {
-        conf->bindParticipant(callId2);
-        answerCall(callId2);
-    } else if (call2_state_str == "CURRENT") {
-        conf->bindParticipant(callId2);
-    } else if (call2_state_str == "INACTIVE") {
-        conf->bindParticipant(callId2);
-        answerCall(callId2);
-    } else
-        RING_WARN("Call state not recognized");
-
-    // Switch current call id to this conference
-    switchCall(getCallFromCallID(conf->getConfID()));
-    conf->setState(Conference::ACTIVE_ATTACHED);
-
-    // set recording sampling rate
-    conf->setRecordingFormat(ringbufferpool_->getInternalAudioFormat());
-
-    return true;
-}
-
-void
-ManagerImpl::createConfFromParticipantList(const std::vector< std::string > &participantList)
-{
-    // we must at least have 2 participant for a conference
-    if (participantList.size() <= 1) {
-        RING_ERR("Participant number must be higher or equal to 2");
-        return;
-    }
-
-    auto conf = std::make_shared<Conference>();
-
-    int successCounter = 0;
-
-    for (const auto &p : participantList) {
-        std::string numberaccount(p);
-        std::string tostr(numberaccount.substr(0, numberaccount.find(",")));
-        std::string account(numberaccount.substr(numberaccount.find(",") + 1, numberaccount.size()));
-
-        unsetCurrentCall();
-
-        // Create call
-        auto call_id = outgoingCall(account, tostr, conf->getConfID());
-        if (call_id.empty())
-            continue;
-
-        // Manager methods may behave differently if the call id participates in a conference
-        conf->add(call_id);
-
-        emitSignal<DRing::CallSignal::NewCallCreated>(account, call_id, tostr);
-        successCounter++;
-    }
-
-    // Create the conference if and only if at least 2 calls have been successfully created
-    if (successCounter >= 2) {
-        conferenceMap_[conf->getConfID()] = conf;
-        emitSignal<DRing::CallSignal::ConferenceCreated>(conf->getConfID());
-        conf->setRecordingFormat(ringbufferpool_->getInternalAudioFormat());
-    }
-}
-
-bool
-ManagerImpl::detachParticipant(const std::string& call_id)
-{
-    const std::string current_call_id(getCurrentCallId());
-
-    if (call_id != RingBufferPool::DEFAULT_ID) {
-        auto call = getCallFromCallID(call_id);
-        if (!call) {
-            RING_ERR("Could not find call %s", call_id.c_str());
-            return false;
-        }
-
-        auto conf = getConferenceFromCallID(call_id);
-
-        if (conf == nullptr) {
-            RING_ERR("Call is not conferencing, cannot detach");
-            return false;
-        }
-
-        std::map<std::string, std::string> call_details(getCallDetails(call_id));
-        std::map<std::string, std::string>::iterator iter_details(call_details.find("CALL_STATE"));
-
-        if (iter_details == call_details.end()) {
-            RING_ERR("Could not find CALL_STATE");
-            return false;
-        }
-
-        // Don't hold ringing calls when detaching them from conferences
-        if (iter_details->second != "RINGING")
-            onHoldCall(call_id);
-
-        removeParticipant(call_id);
-
-    } else {
-        RING_DBG("Unbind main participant from conference %d");
-        getRingBufferPool().unBindAll(RingBufferPool::DEFAULT_ID);
-
-        if (not isConference(current_call_id)) {
-            RING_ERR("Current call id (%s) is not a conference", current_call_id.c_str());
-            return false;
-        }
-
-        ConferenceMap::iterator iter = conferenceMap_.find(current_call_id);
-
-        auto conf = iter->second;
-        if (iter == conferenceMap_.end() or conf == 0) {
-            RING_DBG("Conference is NULL");
-            return false;
-        }
-
-        if (conf->getState() == Conference::ACTIVE_ATTACHED)
-            conf->setState(Conference::ACTIVE_DETACHED);
-        else if (conf->getState() == Conference::ACTIVE_ATTACHED_REC)
-            conf->setState(Conference::ACTIVE_DETACHED_REC);
-        else
-            RING_WARN("Undefined behavior, invalid conference state in detach participant");
-
-        emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
-
-        unsetCurrentCall();
-    }
-
-    return true;
-}
-
-void
-ManagerImpl::removeParticipant(const std::string& call_id)
-{
-    RING_DBG("Remove participant %s", call_id.c_str());
-
-    // this call is no longer a conference participant
-    auto call = getCallFromCallID(call_id);
-    if (!call) {
-        RING_ERR("Call not found");
-        return;
-    }
-
-    ConferenceMap::const_iterator iter = conferenceMap_.find(call->getConfId());
-
-    auto conf = iter->second;
-    if (iter == conferenceMap_.end() or conf == 0) {
-        RING_ERR("No conference with id %s, cannot remove participant", call->getConfId().c_str());
-        return;
-    }
-
-    conf->remove(call_id);
-    call->setConfId("");
-
-    removeStream(*call);
-
-    emitSignal<DRing::CallSignal::ConferenceChanged>(conf->getConfID(), conf->getStateStr());
-
-    processRemainingParticipants(*conf);
-}
-
-void
-ManagerImpl::processRemainingParticipants(Conference &conf)
-{
-    const std::string current_call_id(getCurrentCallId());
-    ParticipantSet participants(conf.getParticipantList());
-    const size_t n = participants.size();
-    RING_DBG("Process remaining %d participant(s) from conference %s",
-          n, conf.getConfID().c_str());
-
-    if (n > 1) {
-        // Reset ringbuffer's readpointers
-        for (const auto &p : participants)
-            getRingBufferPool().flush(p);
-
-        getRingBufferPool().flush(RingBufferPool::DEFAULT_ID);
-    } else if (n == 1) {
-        // this call is the last participant, hence
-        // the conference is over
-        ParticipantSet::iterator p = participants.begin();
-
-        if (auto call = getCallFromCallID(*p)) {
-            call->setConfId("");
-            // if we are not listening to this conference
-            if (current_call_id != conf.getConfID())
-                onHoldCall(call->getCallId());
-            else
-                switchCall(call);
-        }
-
-        RING_DBG("No remaining participants, remove conference");
-        removeConference(conf.getConfID());
-    } else {
-        RING_DBG("No remaining participants, remove conference");
-        removeConference(conf.getConfID());
-        unsetCurrentCall();
-    }
-}
-
-bool
-ManagerImpl::joinConference(const std::string& conf_id1,
-                            const std::string& conf_id2)
-{
-    if (conferenceMap_.find(conf_id1) == conferenceMap_.end()) {
-        RING_ERR("Not a valid conference ID: %s", conf_id1.c_str());
-        return false;
-    }
-
-    if (conferenceMap_.find(conf_id2) == conferenceMap_.end()) {
-        RING_ERR("Not a valid conference ID: %s", conf_id2.c_str());
-        return false;
-    }
-
-    auto conf = conferenceMap_.find(conf_id1)->second;
-    ParticipantSet participants(conf->getParticipantList());
-
-    for (const auto &p : participants)
-        addParticipant(p, conf_id2);
-
-    return true;
-}
-
-void
-ManagerImpl::addStream(Call& call)
-{
-    const auto call_id = call.getCallId();
-    RING_DBG("Add audio stream %s", call_id.c_str());
-
-    if (isConferenceParticipant(call_id)) {
-        RING_DBG("Add stream to conference");
-
-        // bind to conference participant
-        ConferenceMap::iterator iter = conferenceMap_.find(call_id);
-        if (iter != conferenceMap_.end() and iter->second) {
-            auto conf = iter->second;
-            conf->bindParticipant(call_id);
-        }
-    } else {
-        RING_DBG("Add stream to call");
-
-        // bind to main
-        getRingBufferPool().bindCallID(call_id, RingBufferPool::DEFAULT_ID);
-
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-        if (!audiodriver_) {
-            RING_ERR("Audio driver not initialized");
-            return;
-        }
-        audiodriver_->flushUrgent();
-        audiodriver_->flushMain();
-    }
-    startAudioDriverStream();
-}
-
-void
-ManagerImpl::removeStream(Call& call)
-{
-    const auto call_id = call.getCallId();
-    RING_DBG("Remove audio stream %s", call_id.c_str());
-    getRingBufferPool().unBindAll(call_id);
-}
-
-// Not thread-safe, SHOULD be called in same thread that run poolEvents()
-void
-ManagerImpl::registerEventHandler(uintptr_t handlerId, EventHandler handler)
-{
-    eventHandlerMap_[handlerId] = handler;
-}
-
-// Not thread-safe, SHOULD be called in same thread that run poolEvents()
-void
-ManagerImpl::unregisterEventHandler(uintptr_t handlerId)
-{
-    auto iter = eventHandlerMap_.find(handlerId);
-    if (iter != eventHandlerMap_.end()) {
-        if (iter == nextEventHandler_)
-            nextEventHandler_ = eventHandlerMap_.erase(iter);
-        else
-            eventHandlerMap_.erase(iter);
-    }
-}
-
-// Not thread-safe, SHOULD be called in same thread that run poolEvents()
-void
-ManagerImpl::addTask(const std::function<bool()>&& task)
-{
-    pendingTaskList_.emplace_back(task);
-}
-
-// Must be invoked periodically by a timer from the main event loop
-void ManagerImpl::pollEvents()
-{
-    //-- Handlers
-    {
-        auto iter = eventHandlerMap_.begin();
-        while (iter != eventHandlerMap_.end()) {
-            if (finished_)
-                return;
-
-            // WARN: following callback can do anything and typically
-            // calls (un)registerEventHandler.
-            // Think twice before modify this code.
-
-            nextEventHandler_ = std::next(iter);
-            iter->second();
-            iter = nextEventHandler_;
-        }
-    }
-
-    //-- Tasks
-    {
-        auto tmpList = std::move(pendingTaskList_);
-        pendingTaskList_.clear();
-        auto iter = std::begin(tmpList);
-        while (iter != tmpList.cend()) {
-            if (finished_)
-                return;
-
-            auto next = std::next(iter);
-            if (not (*iter)())
-                tmpList.erase(iter);
-            iter = next;
-        }
-        pendingTaskList_.splice(std::end(pendingTaskList_), tmpList);
-    }
-}
-
-//THREAD=Main
-void
-ManagerImpl::saveConfig()
-{
-    RING_DBG("Saving Configuration to XDG directory %s", path_.c_str());
-
-    if (audiodriver_) {
-        audioPreference.setVolumemic(audiodriver_->getCaptureGain());
-        audioPreference.setVolumespkr(audiodriver_->getPlaybackGain());
-        audioPreference.setCaptureMuted(audiodriver_->isCaptureMuted());
-        audioPreference.setPlaybackMuted(audiodriver_->isPlaybackMuted());
-    }
-
-    try {
-        YAML::Emitter out;
-
-        // FIXME maybe move this into accountFactory?
-        out << YAML::BeginMap << YAML::Key << "accounts";
-        out << YAML::Value << YAML::BeginSeq;
-
-        for (const auto& account : accountFactory_.getAllAccounts()) {
-            account->serialize(out);
-        }
-        out << YAML::EndSeq;
-
-        // FIXME: this is a hack until we get rid of accountOrder
-        preferences.verifyAccountOrder(getAccountList());
-        preferences.serialize(out);
-        voipPreferences.serialize(out);
-        hookPreference.serialize(out);
-        audioPreference.serialize(out);
-#ifdef RING_VIDEO
-        getVideoDeviceMonitor().serialize(out);
-#endif
-        shortcutPreferences.serialize(out);
-
-        std::ofstream fout(path_);
-        fout << out.c_str();
-    } catch (const YAML::Exception &e) {
-        RING_ERR("%s", e.what());
-    } catch (const std::runtime_error &e) {
-        RING_ERR("%s", e.what());
-    }
-}
-
-//THREAD=Main | VoIPLink
-void
-ManagerImpl::playDtmf(char code)
-{
-    stopTone();
-
-    if (not voipPreferences.getPlayDtmf()) {
-        RING_DBG("Do not have to play a tone...");
-        return;
-    }
-
-    // length in milliseconds
-    int pulselen = voipPreferences.getPulseLength();
-
-    if (pulselen == 0) {
-        RING_DBG("Pulse length is not set...");
-        return;
-    }
-
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    // numbers of int = length in milliseconds / 1000 (number of seconds)
-    //                = number of seconds * SAMPLING_RATE by SECONDS
-
-    // fast return, no sound, so no dtmf
-    if (not audiodriver_ or not dtmfKey_) {
-        RING_DBG("No audio layer...");
-        return;
-    }
-
-    // number of data sampling in one pulselen depends on samplerate
-    // size (n sampling) = time_ms * sampling/s
-    //                     ---------------------
-    //                            ms/s
-    int size = (int)((pulselen * (float) audiodriver_->getSampleRate()) / 1000);
-    dtmfBuf_.resize(size);
-
-    // Handle dtmf
-    dtmfKey_->startTone(code);
-
-    // copy the sound
-    if (dtmfKey_->generateDTMF(*dtmfBuf_.getChannel(0))) {
-        // Put buffer to urgentRingBuffer
-        // put the size in bytes...
-        // so size * 1 channel (mono) * sizeof (bytes for the data)
-        // audiolayer->flushUrgent();
-        audiodriver_->startStream();
-
-        // FIXME: do real synchronization
-        int tries = 10;
-        while (not audiodriver_->isStarted() and tries--) {
-            RING_WARN("Audio layer not ready yet");
-            usleep(10000);
-        }
-        audiodriver_->putUrgent(dtmfBuf_);
-    }
-
-    // TODO Cache the DTMF
-}
-
-// Multi-thread
-bool
-ManagerImpl::incomingCallsWaiting()
-{
-    std::lock_guard<std::mutex> m(waitingCallsMutex_);
-    return not waitingCalls_.empty();
-}
-
-void
-ManagerImpl::addWaitingCall(const std::string& id)
-{
-    std::lock_guard<std::mutex> m(waitingCallsMutex_);
-    waitingCalls_.insert(id);
-}
-
-void
-ManagerImpl::removeWaitingCall(const std::string& id)
-{
-    std::lock_guard<std::mutex> m(waitingCallsMutex_);
-    waitingCalls_.erase(id);
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Management of event peer IP-phone
-////////////////////////////////////////////////////////////////////////////////
-// SipEvent Thread
-void
-ManagerImpl::incomingCall(Call &call, const std::string& accountId)
-{
-    stopTone();
-    const std::string callID(call.getCallId());
-
-    if (accountId.empty())
-        call.setIPToIP(true);
-    else {
-        // strip sip: which is not required and bring confusion with ip to ip calls
-        // when placing new call from history (if call is IAX, do nothing)
-        std::string peerNumber(call.getPeerNumber());
-
-        const char SIP_PREFIX[] = "sip:";
-        size_t startIndex = peerNumber.find(SIP_PREFIX);
-
-        if (startIndex != std::string::npos)
-            call.setPeerNumber(peerNumber.substr(startIndex + sizeof(SIP_PREFIX) - 1));
-    }
-
-    if (not hasCurrentCall()) {
-        call.setConnectionState(Call::RINGING);
-        playRingtone(accountId);
-    }
-
-    addWaitingCall(callID);
-
-    std::string number(call.getPeerNumber());
-
-    std::string from("<" + number + ">");
-
-    emitSignal<DRing::CallSignal::IncomingCall>(accountId, callID, call.getDisplayName() + " " + from);
-}
-
-//THREAD=VoIP
-#if HAVE_INSTANT_MESSAGING
-void
-ManagerImpl::incomingMessage(const std::string& callID,
-                             const std::string& from,
-                             const std::string& message)
-{
-    if (isConferenceParticipant(callID)) {
-        auto conf = getConferenceFromCallID(callID);
-
-        ParticipantSet participants(conf->getParticipantList());
-
-        for (const auto &item_p : participants) {
-
-            if (item_p == callID)
-                continue;
-
-            RING_DBG("Send message to %s", item_p.c_str());
-
-            if (auto call = getCallFromCallID(item_p)) {
-                call->sendTextMessage(message, from);
-            } else {
-                RING_ERR("Failed to get call while sending instant message");
-                return;
-            }
-        }
-
-        // in case of a conference we must notify client using conference id
-        emitSignal<DRing::CallSignal::IncomingMessage>(conf->getConfID(), from, message);
-    } else
-        emitSignal<DRing::CallSignal::IncomingMessage>(callID, from, message);
-}
-
-//THREAD=VoIP
-bool
-ManagerImpl::sendCallTextMessage(const std::string& callID,
-                             const std::string& message,
-                             const std::string& from)
-{
-    if (isConference(callID)) {
-        RING_DBG("Is a conference, send instant message to everyone");
-        ConferenceMap::iterator it = conferenceMap_.find(callID);
-
-        if (it == conferenceMap_.end())
-            return false;
-
-        auto conf = it->second;
-
-        if (!conf)
-            return false;
-
-        ParticipantSet participants(conf->getParticipantList());
-
-        for (const auto &participant_id : participants) {
-
-            if (auto call = getCallFromCallID(participant_id)) {
-                call->sendTextMessage(message, from);
-            } else {
-                RING_ERR("Failed to get call while sending instant message");
-                return false;
-            }
-        }
-
-        return true;
-    }
-
-    if (isConferenceParticipant(callID)) {
-        RING_DBG("Call is participant in a conference, send instant message to everyone");
-        auto conf = getConferenceFromCallID(callID);
-
-        if (!conf)
-            return false;
-
-        ParticipantSet participants(conf->getParticipantList());
-
-        for (const auto &participant_id : participants) {
-
-            if (auto call = getCallFromCallID(participant_id)) {
-                call->sendTextMessage(message, from);
-            } else {
-                RING_ERR("Failed to get call while sending instant message");
-                return false;
-            }
-        }
-    } else {
-        if (auto call = getCallFromCallID(callID)) {
-            call->sendTextMessage(message, from);
-        } else {
-            RING_ERR("Failed to get call while sending instant message");
-            return false;
-        }
-    }
-    return true;
-}
-#endif // HAVE_INSTANT_MESSAGING
-
-//THREAD=VoIP CALL=Outgoing
-void
-ManagerImpl::peerAnsweredCall(Call& call)
-{
-    const auto call_id = call.getCallId();
-    RING_DBG("Peer answered call %s", call_id.c_str());
-
-    // The if statement is usefull only if we sent two calls at the same time.
-    if (isCurrentCall(call))
-        stopTone();
-
-    // Connect audio streams
-    addStream(call);
-
-    if (audiodriver_) {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-        audiodriver_->flushMain();
-        audiodriver_->flushUrgent();
-    }
-
-    if (audioPreference.getIsAlwaysRecording())
-        toggleRecordingCall(call_id);
-
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "CURRENT", 0);
-}
-
-//THREAD=VoIP Call=Outgoing
-void
-ManagerImpl::peerRingingCall(Call& call)
-{
-    const auto call_id = call.getCallId();
-    RING_DBG("Peer call %s ringing", call_id.c_str());
-
-    if (isCurrentCall(call))
-        ringback();
-
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "RINGING", 0);
-}
-
-//THREAD=VoIP Call=Outgoing/Ingoing
-void
-ManagerImpl::peerHungupCall(Call& call)
-{
-    const auto call_id = call.getCallId();
-    RING_DBG("Peer hungup call %s", call_id.c_str());
-
-    if (isConferenceParticipant(call_id)) {
-        removeParticipant(call_id);
-    } else if (isCurrentCall(call)) {
-        stopTone();
-        unsetCurrentCall();
-    }
-
-    call.peerHungup();
-
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "HUNGUP", 0);
-
-    checkAudio();
-    removeWaitingCall(call_id);
-    if (not incomingCallsWaiting())
-        stopTone();
-
-    removeStream(call);
-}
-
-//THREAD=VoIP
-void
-ManagerImpl::callBusy(Call& call)
-{
-    const auto call_id = call.getCallId();
-
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "BUSY", 0);
-
-    if (isCurrentCall(call)) {
-        playATone(Tone::TONE_BUSY);
-        unsetCurrentCall();
-    }
-
-    checkAudio();
-    removeWaitingCall(call_id);
-}
-
-//THREAD=VoIP
-void
-ManagerImpl::callFailure(Call& call, int code)
-{
-    const auto call_id = call.getCallId();
-
-    emitSignal<DRing::CallSignal::StateChange>(call_id, "FAILURE", code);
-
-    if (isCurrentCall(call)) {
-        playATone(Tone::TONE_BUSY);
-        unsetCurrentCall();
-    }
-
-    if (isConferenceParticipant(call_id)) {
-        RING_DBG("Call %s participating in a conference failed", call_id.c_str());
-        // remove this participant
-        removeParticipant(call_id);
-    }
-
-    checkAudio();
-    removeWaitingCall(call_id);
-}
-
-//THREAD=VoIP
-void
-ManagerImpl::startVoiceMessageNotification(const std::string& accountId,
-                                           int nb_msg)
-{
-    emitSignal<DRing::CallSignal::VoiceMailNotify>(accountId, nb_msg);
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::playATone(Tone::TONEID toneId)
-{
-    if (not voipPreferences.getPlayTones())
-        return;
-
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (not audiodriver_) {
-            RING_ERR("Audio layer not initialized");
-            return;
-        }
-
-        audiodriver_->flushUrgent();
-        audiodriver_->startStream();
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(toneMutex_);
-        if (telephoneTone_)
-            telephoneTone_->setCurrentTone(toneId);
-    }
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::stopTone()
-{
-    if (not voipPreferences.getPlayTones())
-        return;
-
-    std::lock_guard<std::mutex> lock(toneMutex_);
-    if (telephoneTone_)
-        telephoneTone_->setCurrentTone(Tone::TONE_NULL);
-
-    if (audiofile_) {
-        std::string filepath(audiofile_->getFilePath());
-
-        emitSignal<DRing::CallSignal::RecordPlaybackStopped>(filepath);
-        audiofile_.reset();
-    }
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::playTone()
-{
-    playATone(Tone::TONE_DIALTONE);
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::playToneWithMessage()
-{
-    playATone(Tone::TONE_CONGESTION);
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::congestion()
-{
-    playATone(Tone::TONE_CONGESTION);
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::ringback()
-{
-    playATone(Tone::TONE_RINGTONE);
-}
-
-// Caller must hold toneMutex
-void
-ManagerImpl::updateAudioFile(const std::string &file, int sampleRate)
-{
-    audiofile_.reset(new AudioFile(file, sampleRate));
-}
-
-/**
- * Multi Thread
- */
-void
-ManagerImpl::playRingtone(const std::string& accountID)
-{
-    const auto account = getAccount(accountID);
-
-    if (!account) {
-        RING_WARN("Invalid account in ringtone");
-        return;
-    }
-
-    if (!account->getRingtoneEnabled()) {
-        ringback();
-        return;
-    }
-
-    std::string ringchoice = account->getRingtonePath();
-
-    if (ringchoice.find(DIR_SEPARATOR_STR) == std::string::npos) {
-        // check inside global share directory
-        static const char * const RINGDIR = "ringtones";
-        ringchoice = std::string(PROGSHAREDIR) + DIR_SEPARATOR_STR
-                     + RINGDIR + DIR_SEPARATOR_STR + ringchoice;
-    }
-
-    int audioLayerSmplr = 8000;
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (not audiodriver_) {
-            RING_ERR("no audio layer in ringtone");
-            return;
-        }
-
-        audioLayerSmplr = audiodriver_->getSampleRate();
-    }
-
-    bool doFallback = false;
-
-    {
-        std::lock_guard<std::mutex> m(toneMutex_);
-
-        if (audiofile_) {
-            emitSignal<DRing::CallSignal::RecordPlaybackStopped>(audiofile_->getFilePath());
-            audiofile_.reset();
-        }
-
-        try {
-            updateAudioFile(ringchoice, audioLayerSmplr);
-        } catch (const AudioFileException &e) {
-            RING_WARN("Ringtone error: %s", e.what());
-            doFallback = true; // do ringback once lock is out of scope
-        }
-    } // leave mutex
-
-    if (doFallback) {
-        ringback();
-        return;
-    }
-
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-    // start audio if not started AND flush all buffers (main and urgent)
-    audiodriver_->startStream();
-}
-
-AudioLoop*
-ManagerImpl::getTelephoneTone()
-{
-    std::lock_guard<std::mutex> m(toneMutex_);
-    if (telephoneTone_)
-        return telephoneTone_->getCurrentTone();
-    else
-        return nullptr;
-}
-
-AudioLoop*
-ManagerImpl::getTelephoneFile()
-{
-    std::lock_guard<std::mutex> m(toneMutex_);
-    return audiofile_.get();
-}
-
-///////////////////////////////////////////////////////////////////////////////
-// Private functions
-///////////////////////////////////////////////////////////////////////////////
-/**
- * Initialization: Main Thread
- */
-std::string
-ManagerImpl::retrieveConfigPath() const
-{
-#ifdef __ANDROID__
-    std::string configdir = "/data/data/cx.ring";
-#elif __APPLE__
-    std::string configdir = fileutils::get_home_dir() + DIR_SEPARATOR_STR
-        + "Library" + DIR_SEPARATOR_STR + "Application Support"
-        + DIR_SEPARATOR_STR + PACKAGE;
-#else
-    std::string configdir = fileutils::get_home_dir() + DIR_SEPARATOR_STR +
-                            ".config" + DIR_SEPARATOR_STR + PACKAGE;
-#endif
-
-    const std::string xdg_env(XDG_CONFIG_HOME);
-    if (not xdg_env.empty())
-        configdir = xdg_env + DIR_SEPARATOR_STR + PACKAGE;
-
-#ifndef _WIN32
-    if (mkdir(configdir.data(), 0700) != 0) {
-#else
-    if (fileutils::recursive_mkdir(configdir.data()) != true) {
-#endif
-        // If directory creation failed
-        if (errno != EEXIST)
-            RING_DBG("Cannot create directory: %s!", configdir.c_str());
-    }
-
-    static const char * const PROGNAME = "dring";
-    return configdir + DIR_SEPARATOR_STR + PROGNAME + ".yml";
-}
-
-/**
- * Set input audio plugin
- */
-void
-ManagerImpl::setAudioPlugin(const std::string& audioPlugin)
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    audioPreference.setAlsaPlugin(audioPlugin);
-
-    bool wasStarted = audiodriver_->isStarted();
-
-    // Recreate audio driver with new settings
-    audiodriver_.reset(audioPreference.createAudioLayer());
-
-    if (audiodriver_ and wasStarted)
-        audiodriver_->startStream();
-    else
-        RING_ERR("No audio layer created, possibly built without audio support");
-}
-
-/**
- * Set audio output device
- */
-void
-ManagerImpl::setAudioDevice(int index, DeviceType type)
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    if (not audiodriver_) {
-        RING_ERR("Audio driver not initialized");
-        return ;
-    }
-
-    const bool wasStarted = audiodriver_->isStarted();
-    audiodriver_->updatePreference(audioPreference, index, type);
-
-    // Recreate audio driver with new settings
-    audiodriver_.reset(audioPreference.createAudioLayer());
-
-    if (audiodriver_ and wasStarted)
-        audiodriver_->startStream();
-}
-
-/**
- * Get list of supported audio output device
- */
-std::vector<std::string>
-ManagerImpl::getAudioOutputDeviceList()
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-    return audiodriver_->getPlaybackDeviceList();
-}
-
-/**
- * Get list of supported audio input device
- */
-std::vector<std::string>
-ManagerImpl::getAudioInputDeviceList()
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-    return audiodriver_->getCaptureDeviceList();
-}
-
-/**
- * Get string array representing integer indexes of output and input device
- */
-std::vector<std::string>
-ManagerImpl::getCurrentAudioDevicesIndex()
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    std::vector<std::string> v;
-
-    std::stringstream ssi, sso, ssr;
-    sso << audiodriver_->getIndexPlayback();
-    v.push_back(sso.str());
-    ssi << audiodriver_->getIndexCapture();
-    v.push_back(ssi.str());
-    ssr << audiodriver_->getIndexRingtone();
-    v.push_back(ssr.str());
-
-    return v;
-}
-
-bool
-ManagerImpl::switchInput(const std::string& call_id, const std::string& res)
-{
-    auto call = getCallFromCallID(call_id);
-    if (!call) {
-        RING_ERR("Call %s is NULL", call_id.c_str());
-        return false;
-    }
-    call->switchInput(res);
-    return true;
-}
-
-int
-ManagerImpl::isRingtoneEnabled(const std::string& id)
-{
-    const auto account = getAccount(id);
-
-    if (!account) {
-        RING_WARN("Invalid account in ringtone enabled");
-        return 0;
-    }
-
-    return account->getRingtoneEnabled();
-}
-
-void
-ManagerImpl::ringtoneEnabled(const std::string& id)
-{
-    const auto account = getAccount(id);
-
-    if (!account) {
-        RING_WARN("Invalid account in ringtone enabled");
-        return;
-    }
-
-    account->getRingtoneEnabled() ? account->setRingtoneEnabled(false) : account->setRingtoneEnabled(true);
-}
-
-bool
-ManagerImpl::getIsAlwaysRecording() const
-{
-    return audioPreference.getIsAlwaysRecording();
-}
-
-void
-ManagerImpl::setIsAlwaysRecording(bool isAlwaysRec)
-{
-    return audioPreference.setIsAlwaysRecording(isAlwaysRec);
-}
-
-bool
-ManagerImpl::toggleRecordingCall(const std::string& id)
-{
-    std::shared_ptr<Recordable> rec;
-
-    ConferenceMap::const_iterator it(conferenceMap_.find(id));
-    if (it == conferenceMap_.end()) {
-        RING_DBG("toggle recording for call %s", id.c_str());
-        rec = getCallFromCallID(id);
-    } else {
-        RING_DBG("toggle recording for conference %s", id.c_str());
-        auto conf = it->second;
-        if (conf) {
-            rec = conf;
-            if (conf->isRecording())
-                conf->setState(Conference::ACTIVE_ATTACHED);
-            else
-                conf->setState(Conference::ACTIVE_ATTACHED_REC);
-        }
-    }
-
-    if (!rec) {
-        RING_ERR("Could not find recordable instance %s", id.c_str());
-        return false;
-    }
-
-    const bool result = rec->toggleRecording();
-    emitSignal<DRing::CallSignal::RecordPlaybackFilepath>(id, rec->getFilename());
-    emitSignal<DRing::CallSignal::RecordingStateChanged>(id, result);
-    return result;
-}
-
-bool
-ManagerImpl::isRecording(const std::string& id)
-{
-    auto call = getCallFromCallID(id);
-    return call and (static_cast<Recordable*>(call.get()))->isRecording();
-}
-
-bool
-ManagerImpl::startRecordedFilePlayback(const std::string& filepath)
-{
-    RING_DBG("Start recorded file playback %s", filepath.c_str());
-
-    int sampleRate;
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (not audiodriver_) {
-            RING_ERR("No audio layer in start recorded file playback");
-            return false;
-        }
-
-        sampleRate = audiodriver_->getSampleRate();
-    }
-
-    {
-        std::lock_guard<std::mutex> m(toneMutex_);
-
-        if (audiofile_) {
-            emitSignal<DRing::CallSignal::RecordPlaybackStopped>(audiofile_->getFilePath());
-            audiofile_.reset();
-        }
-
-        try {
-            updateAudioFile(filepath, sampleRate);
-            if (not audiofile_)
-                return false;
-        } catch (const AudioFileException &e) {
-            RING_WARN("Audio file error: %s", e.what());
-            return false;
-        }
-    } // release toneMutex
-
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-        audiodriver_->startStream();
-    }
-
-    return true;
-}
-
-void ManagerImpl::recordingPlaybackSeek(const double value)
-{
-    std::lock_guard<std::mutex> m(toneMutex_);
-    if (audiofile_)
-        audiofile_.get()->seek(value);
-}
-
-void ManagerImpl::stopRecordedFilePlayback(const std::string& filepath)
-{
-    RING_DBG("Stop recorded file playback %s", filepath.c_str());
-
-    checkAudio();
-
-    {
-        std::lock_guard<std::mutex> m(toneMutex_);
-        audiofile_.reset();
-    }
-    emitSignal<DRing::CallSignal::RecordPlaybackStopped>(filepath);
-}
-
-void ManagerImpl::setHistoryLimit(int days)
-{
-    RING_DBG("Set history limit");
-    preferences.setHistoryLimit(days);
-    saveConfig();
-}
-
-int
-ManagerImpl::getHistoryLimit() const
-{
-    return preferences.getHistoryLimit();
-}
-
-bool
-ManagerImpl::setAudioManager(const std::string &api)
-{
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        if (not audiodriver_)
-            return false;
-
-        if (api == audioPreference.getAudioApi()) {
-            RING_DBG("Audio manager chosen already in use. No changes made. ");
-            return true;
-        }
-    }
-
-    {
-        std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-        bool wasStarted = audiodriver_->isStarted();
-        audioPreference.setAudioApi(api);
-        audiodriver_.reset(audioPreference.createAudioLayer());
-
-        if (audiodriver_ and wasStarted)
-            audiodriver_->startStream();
-    }
-
-    saveConfig();
-
-    // ensure that we completed the transition (i.e. no fallback was used)
-    return api == audioPreference.getAudioApi();
-}
-
-std::string
-ManagerImpl::getAudioManager() const
-{
-    return audioPreference.getAudioApi();
-}
-
-int
-ManagerImpl::getAudioInputDeviceIndex(const std::string &name)
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    if (not audiodriver_) {
-        RING_ERR("Audio layer not initialized");
-        return 0;
-    }
-
-    return audiodriver_->getAudioDeviceIndex(name, DeviceType::CAPTURE);
-}
-
-int
-ManagerImpl::getAudioOutputDeviceIndex(const std::string &name)
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-
-    if (not audiodriver_) {
-        RING_ERR("Audio layer not initialized");
-        return 0;
-    }
-
-    return audiodriver_->getAudioDeviceIndex(name, DeviceType::PLAYBACK);
-}
-
-std::string
-ManagerImpl::getCurrentAudioOutputPlugin() const
-{
-    return audioPreference.getAlsaPlugin();
-}
-
-bool
-ManagerImpl::getNoiseSuppressState() const
-{
-    return audioPreference.getNoiseReduce();
-}
-
-void
-ManagerImpl::setNoiseSuppressState(bool state)
-{
-    audioPreference.setNoiseReduce(state);
-}
-
-bool
-ManagerImpl::isAGCEnabled() const
-{
-    return audioPreference.isAGCEnabled();
-}
-
-void
-ManagerImpl::setAGCState(bool state)
-{
-    audioPreference.setAGCState(state);
-}
-
-/**
- * Initialization: Main Thread
- */
-void
-ManagerImpl::initAudioDriver()
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-    audiodriver_.reset(audioPreference.createAudioLayer());
-}
-
-AudioFormat
-ManagerImpl::hardwareAudioFormatChanged(AudioFormat format)
-{
-    return audioFormatUsed(format);
-}
-
-AudioFormat
-ManagerImpl::audioFormatUsed(AudioFormat format)
-{
-    AudioFormat currentFormat = ringbufferpool_->getInternalAudioFormat();
-    format.nb_channels = std::max(currentFormat.nb_channels, std::min(format.nb_channels, 2u)); // max 2 channels.
-    format.sample_rate = std::max(currentFormat.sample_rate, format.sample_rate);
-
-    if (currentFormat == format)
-        return format;
-
-    RING_DBG("Audio format changed: %s -> %s", currentFormat.toString().c_str(), format.toString().c_str());
-
-    ringbufferpool_->setInternalAudioFormat(format);
-
-    {
-        std::lock_guard<std::mutex> toneLock(toneMutex_);
-        telephoneTone_.reset(new TelephoneTone(preferences.getZoneToneChoice(), format.sample_rate));
-    }
-    dtmfKey_.reset(new DTMF(format.sample_rate));
-    return format;
-}
-
-void
-ManagerImpl::setAccountsOrder(const std::string& order)
-{
-    RING_DBG("Set accounts order : %s", order.c_str());
-    // Set the new config
-
-    preferences.setAccountOrder(order);
-
-    saveConfig();
-}
-
-std::vector<std::string>
-ManagerImpl::getAccountList() const
-{
-    // TODO: this code looks weird. need further investigation!
-
-    using std::vector;
-    using std::string;
-    vector<string> account_order(loadAccountOrder());
-
-    // The IP2IP profile is always available, and first in the list
-
-    vector<string> v;
-
-    // Concatenate all account pointers in a single map
-    const auto& allAccounts = accountFactory_.getAllAccounts();
-
-    // If no order has been set, load the default one ie according to the creation date.
-    if (account_order.empty()) {
-        for (const auto &account : allAccounts) {
-            if (account->isIP2IP())
-                continue;
-            v.push_back(account->getAccountID());
-        }
-    } else {
-        const auto& ip2ipAccountID = getIP2IPAccount()->getAccountID();
-        for (const auto& id : account_order) {
-            if (id.empty() or id == ip2ipAccountID)
-                continue;
-
-            if (accountFactory_.hasAccount(id))
-                v.push_back(id);
-        }
-    }
-
-    if (const auto& account = getIP2IPAccount())
-        v.push_back(account->getAccountID());
-    else
-        RING_ERR("could not find IP2IP profile in getAccount list");
-
-    return v;
-}
-
-std::map<std::string, std::string>
-ManagerImpl::getAccountDetails(const std::string& accountID) const
-{
-    const auto account = getAccount(accountID);
-
-    if (account) {
-        return account->getAccountDetails();
-    } else {
-        RING_ERR("Could not get account details on a non-existing accountID %s", accountID.c_str());
-        // return an empty map since we can't throw an exception to D-Bus
-        return std::map<std::string, std::string>();
-    }
-}
-
-std::map<std::string, std::string>
-ManagerImpl::getVolatileAccountDetails(const std::string& accountID) const
-{
-    const auto account = getAccount(accountID);
-
-    if (account) {
-        return account->getVolatileAccountDetails();
-    } else {
-        RING_ERR("Could not get volatile account details on a non-existing accountID %s", accountID.c_str());
-        return {{}};
-    }
-}
-
-
-// method to reduce the if/else mess.
-// Even better, switch to XML !
-
-void
-ManagerImpl::setAccountDetails(const std::string& accountID,
-                               const std::map<std::string, std::string>& details)
-{
-    RING_DBG("Set account details for %s", accountID.c_str());
-
-    const auto account = getAccount(accountID);
-
-    if (account == nullptr) {
-        RING_ERR("Could not find account %s", accountID.c_str());
-        return;
-    }
-
-    // Ignore if nothing has changed
-    if (details == account->getAccountDetails())
-        return;
-
-    // Unregister before modifying any account information
-    // FIXME: inefficient api, don't pass details (not as ref nor copy)
-    // let client requiests them we needed.
-    account->doUnregister([&](bool /* transport_free */) {
-        account->setAccountDetails(details);
-        // Serialize configuration to disk once it is done
-        saveConfig();
-
-        if (account->isEnabled()) {
-            account->doRegister();
-        } else
-            account->doUnregister();
-
-        // Update account details to the client side
-        emitSignal<DRing::ConfigurationSignal::VolatileDetailsChanged>(accountID,
-                                                                       details);
-    });
-}
-
-std::string
-ManagerImpl::addAccount(const std::map<std::string, std::string>& details)
-{
-    /** @todo Deal with both the accountMap_ and the Configuration */
-    std::string newAccountID;
-    static std::uniform_int_distribution<uint64_t> rand_acc_id;
-
-    const std::vector<std::string> accountList(getAccountList());
-
-    do {
-        std::ostringstream accId;
-        accId << std::hex << rand_acc_id(rand_);
-        newAccountID = accId.str();
-    } while (std::find(accountList.begin(), accountList.end(), newAccountID)
-             != accountList.end());
-
-    // Get the type
-
-    const char* accountType;
-    if (details.find(Conf::CONFIG_ACCOUNT_TYPE) != details.end())
-        accountType = (*details.find(Conf::CONFIG_ACCOUNT_TYPE)).second.c_str();
-    else
-        accountType = AccountFactory::DEFAULT_ACCOUNT_TYPE;
-
-    RING_DBG("Adding account %s", newAccountID.c_str());
-
-    auto newAccount = accountFactory_.createAccount(accountType, newAccountID);
-    if (!newAccount) {
-        RING_ERR("Unknown %s param when calling addAccount(): %s",
-              Conf::CONFIG_ACCOUNT_TYPE, accountType);
-        return "";
-    }
-
-    newAccount->setAccountDetails(details);
-
-    preferences.addAccount(newAccountID);
-
-    newAccount->doRegister();
-
-    saveConfig();
-
-    emitSignal<DRing::ConfigurationSignal::AccountsChanged>();
-
-    return newAccountID;
-}
-
-void ManagerImpl::removeAccounts()
-{
-    for (const auto &acc : getAccountList())
-        removeAccount(acc);
-}
-
-void ManagerImpl::removeAccount(const std::string& accountID)
-{
-    // Get it down and dying
-    if (const auto& remAccount = getAccount(accountID)) {
-        remAccount->doUnregister();
-        accountFactory_.removeAccount(*remAccount);
-    }
-
-    preferences.removeAccount(accountID);
-
-    saveConfig();
-
-    emitSignal<DRing::ConfigurationSignal::AccountsChanged>();
-}
-
-bool
-ManagerImpl::isValidCall(const std::string& callID)
-{
-    return static_cast<bool>(getCallFromCallID(callID));
-}
-
-std::string
-ManagerImpl::getNewCallID()
-{
-    static std::uniform_int_distribution<uint64_t> rand_call_id;
-    std::ostringstream random_id;
-
-    // generate something like s7ea037947eb9fb2f
-    do {
-        random_id.clear();
-        random_id << rand_call_id(rand_);
-    } while (isValidCall(random_id.str()));
-
-    return random_id.str();
-}
-
-std::vector<std::string>
-ManagerImpl::loadAccountOrder() const
-{
-    return split_string(preferences.getAccountOrder(), '/');
-}
-
-void
-ManagerImpl::loadAccount(const YAML::Node &node, int &errorCount,
-                         const std::string &accountOrder)
-{
-    using yaml_utils::parseValue;
-
-    std::string accountType;
-    parseValue(node, "type", accountType);
-
-    std::string accountid;
-    parseValue(node, "id", accountid);
-
-    std::string accountAlias;
-    parseValue(node, "alias", accountAlias);
-    const auto inAccountOrder = [&](const std::string & id) {
-        return accountOrder.find(id + "/") != std::string::npos;
-    };
-
-    if (!accountid.empty() and !accountAlias.empty()) {
-        const auto& ip2ipAccountID = getIP2IPAccount()->getAccountID();
-        if (not inAccountOrder(accountid) and accountid != ip2ipAccountID) {
-            RING_WARN("Dropping account %s, which is not in account order", accountid.c_str());
-        } else if (accountFactory_.isSupportedType(accountType.c_str())) {
-            std::shared_ptr<Account> a;
-            if (accountid != ip2ipAccountID)
-                a = accountFactory_.createAccount(accountType.c_str(), accountid);
-            else
-                a = accountFactory_.getIP2IPAccount();
-            if (a) {
-                a->unserialize(node);
-            } else {
-                RING_ERR("Failed to create account type \"%s\"", accountType.c_str());
-                ++errorCount;
-            }
-        } else {
-            RING_WARN("Ignoring unknown account type \"%s\"", accountType.c_str());
-        }
-    }
-}
-
-int
-ManagerImpl::loadAccountMap(const YAML::Node &node)
-{
-    accountFactory_.initIP2IPAccount();
-
-    // build preferences
-    preferences.unserialize(node);
-    voipPreferences.unserialize(node);
-    hookPreference.unserialize(node);
-    audioPreference.unserialize(node);
-    shortcutPreferences.unserialize(node);
-
-    int errorCount = 0;
-    try {
-#ifdef RING_VIDEO
-        getVideoDeviceMonitor().unserialize(node);
-#endif
-    } catch (const YAML::Exception &e) {
-        RING_ERR("%s: No video node in config file", e.what());
-        ++errorCount;
-    }
-
-    const std::string accountOrder = preferences.getAccountOrder();
-
-    // load saved preferences for IP2IP account from configuration file
-    const auto &accountList = node["accounts"];
-
-    for (auto &a : accountList) {
-        loadAccount(a, errorCount, accountOrder);
-    }
-
-    return errorCount;
-}
-
-std::map<std::string, std::string>
-ManagerImpl::getCallDetails(const std::string &callID)
-{
-    if (auto call = getCallFromCallID(callID)) {
-        return call->getDetails();
-    } else {
-        RING_ERR("Call is NULL");
-        // FIXME: is this even useful?
-        return Call::getNullDetails();
-    }
-}
-
-std::vector<std::string>
-ManagerImpl::getCallList() const
-{
-    return callFactory.getCallIDs();
-}
-
-std::map<std::string, std::string>
-ManagerImpl::getConferenceDetails(
-    const std::string& confID) const
-{
-    std::map<std::string, std::string> conf_details;
-    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
-
-    if (iter_conf != conferenceMap_.end()) {
-        conf_details["CONFID"] = confID;
-        conf_details["CONF_STATE"] = iter_conf->second->getStateStr();
-    }
-
-    return conf_details;
-}
-
-std::vector<std::string>
-ManagerImpl::getConferenceList() const
-{
-    std::vector<std::string> v;
-    map_utils::vectorFromMapKeys(conferenceMap_, v);
-    return v;
-}
-
-std::vector<std::string>
-ManagerImpl::getDisplayNames(const std::string& confID) const
-{
-    std::vector<std::string> v;
-    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
-
-    if (iter_conf != conferenceMap_.end()) {
-        return iter_conf->second->getDisplayNames();
-    } else {
-        RING_WARN("Did not find conference %s", confID.c_str());
-    }
-
-    return v;
-}
-
-std::vector<std::string>
-ManagerImpl::getParticipantList(const std::string& confID) const
-{
-    std::vector<std::string> v;
-    ConferenceMap::const_iterator iter_conf = conferenceMap_.find(confID);
-
-    if (iter_conf != conferenceMap_.end()) {
-        const ParticipantSet participants(iter_conf->second->getParticipantList());
-        std::copy(participants.begin(), participants.end(), std::back_inserter(v));;
-    } else
-        RING_WARN("Did not find conference %s", confID.c_str());
-
-    return v;
-}
-
-std::string
-ManagerImpl::getConferenceId(const std::string& callID)
-{
-    if (auto call = getCallFromCallID(callID))
-        return call->getConfId();
-
-    RING_ERR("Call is NULL");
-    return "";
-}
-
-void
-ManagerImpl::startAudioDriverStream()
-{
-    std::lock_guard<std::mutex> lock(audioLayerMutex_);
-    if (!audiodriver_) {
-        RING_ERR("Audio driver not initialized");
-        return;
-    }
-    audiodriver_->startStream();
-}
-
-void
-ManagerImpl::registerAccounts()
-{
-    auto allAccounts(getAccountList());
-
-    for (auto &item : allAccounts) {
-        const auto a = getAccount(item);
-
-        if (!a)
-            continue;
-
-        a->loadConfig();
-
-        if (a->isEnabled()) {
-            a->doRegister();
-        }
-    }
-}
-
-void
-ManagerImpl::unregisterAccounts()
-{
-    for (const auto& account : getAllAccounts()) {
-        if (account->isEnabled())
-            account->doUnregister();
-    }
-}
-
-void
-ManagerImpl::sendRegister(const std::string& accountID, bool enable)
-{
-    const auto acc = getAccount(accountID);
-    if (!acc)
-        return;
-
-    acc->setEnabled(enable);
-    acc->loadConfig();
-
-    Manager::instance().saveConfig();
-
-    if (acc->isEnabled()) {
-        acc->doRegister();
-    } else
-        acc->doUnregister();
-}
-
-void
-ManagerImpl::sendTextMessage(const std::string& accountID, const std::string& to, const std::string& message)
-{
-    const auto acc = getAccount(accountID);
-    if (!acc)
-        return;
-    acc->sendTextMessage(to, message);
-}
-
-std::shared_ptr<AudioLayer>
-ManagerImpl::getAudioDriver()
-{
-    return audiodriver_;
-}
-
-std::shared_ptr<Call>
-ManagerImpl::newOutgoingCall(const std::string& toUrl,
-                             const std::string& preferredAccountId)
-{
-    auto account = Manager::instance().getIP2IPAccount();
-    auto preferred = getAccount(preferredAccountId);
-    std::string finalToUrl = toUrl;
-
-#if HAVE_DHT
-    if (toUrl.find("ring:") != std::string::npos) {
-        if (preferred && preferred->getAccountType() == RingAccount::ACCOUNT_TYPE)
-            return preferred->newOutgoingCall(finalToUrl);
-        auto dhtAcc = getAllAccounts<RingAccount>();
-        for (const auto& acc : dhtAcc)
-            if (acc->isEnabled())
-                return acc->newOutgoingCall(finalToUrl);
-    }
-#endif
-
-    // FIXME: have a generic version to remove sip dependency
-    sip_utils::stripSipUriPrefix(finalToUrl);
-
-    if (!IpAddr::isValid(finalToUrl)) {
-        account = preferred;
-        if (account)
-            finalToUrl = toUrl;
-        else
-            RING_WARN("Preferred account %s doesn't exist, using IP2IP account",
-                 preferredAccountId.c_str());
-    } else
-        RING_WARN("IP Url detected, using IP2IP account");
-
-    if (!account) {
-        RING_ERR("No suitable account found to create outgoing call");
-        return nullptr;
-    }
-
-    return account->newOutgoingCall(finalToUrl);
-}
-
-#ifdef RING_VIDEO
-std::shared_ptr<video::SinkClient>
-ManagerImpl::createSinkClient(const std::string& id)
-{
-    const auto& iter = sinkMap_.find(id);
-    if (iter != std::end(sinkMap_)) {
-        if (iter->second.expired())
-            sinkMap_.erase(iter);
-        else
-            return nullptr;
-    }
-
-    auto sink = std::make_shared<video::SinkClient>(id);
-    sinkMap_.emplace(id, sink);
-    return sink;
-}
-
-std::shared_ptr<video::SinkClient>
-ManagerImpl::getSinkClient(const std::string& id)
-{
-    const auto& iter = sinkMap_.find(id);
-    if (iter != std::end(sinkMap_))
-        if (auto sink = iter->second.lock())
-            return sink;
-    return nullptr;
-}
-#endif // RING_VIDEO
-
-} // namespace ring
diff --git a/src/managerimpl.h b/src/managerimpl.h
deleted file mode 100644
index c3ad40e94faa194360dd9b9dbc725e789ad2997d..0000000000000000000000000000000000000000
--- a/src/managerimpl.h
+++ /dev/null
@@ -1,1022 +0,0 @@
-/*
- *  Copyright (C) 2004-2015 Savoir-Faire Linux Inc.
- *  Author: Yan Morin <yan.morin@savoirfairelinux.com>
- *  Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
- *  Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
- *  Author: Guillaume Carmel-Archambault <guillaume.carmel-archambault@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
- *  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 MANAGER_IMPL_H_
-#define MANAGER_IMPL_H_
-
-#ifdef HAVE_CONFIG_H
-#include "config.h"
-#endif
-
-#include <string>
-#include <vector>
-#include <list>
-#include <map>
-#include <memory>
-#include <mutex>
-#include <random>
-#include <atomic>
-#include <functional>
-
-#include "conference.h"
-
-#include "account_factory.h"
-#include "call_factory.h"
-
-#include "audio/audiolayer.h"
-#include "audio/sound/tone.h"  // for Tone::TONEID declaration
-
-#include "preferences.h"
-#include "noncopyable.h"
-
-namespace ring {
-
-namespace Conf {
-class YamlParser;
-class YamlEmitter;
-}
-
-namespace tls {
-class GnuTlsGlobalInit;
-}
-
-namespace video {
-class SinkClient;
-}
-
-class PluginManager;
-class AudioFile;
-class DTMF;
-class TelephoneTone;
-
-/** To send multiple string */
-typedef std::list<std::string> TokenList;
-
-/** To store conference objects by conference ids */
-typedef std::map<std::string, std::shared_ptr<Conference> > ConferenceMap;
-
-typedef std::set<std::string> CallIDSet;
-
-static const char * const default_conf = "conf";
-
-typedef std::set<std::string> CallIDSet;
-
-/** Manager (controller) of Ring daemon */
-class ManagerImpl {
-    private:
-        std::unique_ptr<PluginManager> pluginManager_;
-
-    public:
-        ManagerImpl();
-        ~ManagerImpl();
-
-        /**
-         * General preferences configuration
-         */
-        Preferences preferences;
-
-        /**
-         * Voip related preferences
-         */
-        VoipPreference voipPreferences;
-
-        /**
-         * Hook preferences
-         */
-        HookPreference hookPreference;
-
-        /**
-         * Audio preferences
-         */
-        AudioPreference audioPreference;
-
-        /**
-         * Shortcut preferences
-         */
-        ShortcutPreferences shortcutPreferences;
-
-        // Manager should not be accessed until initialized.
-        // FIXME this is an evil hack!
-        static std::atomic_bool initialized;
-
-        /**
-         * Initialisation of thread (sound) and map.
-         * Init a new VoIPLink, audio codec and audio driver
-         */
-        void init(const std::string &config_file);
-
-        void setPath(const std::string &path);
-
-        /*
-         * Terminate all threads and exit DBus loop
-         */
-        void finish() noexcept;
-
-        /**
-         * Accessor to audiodriver.
-         * it's multi-thread and use mutex internally
-         * @return AudioLayer*  The audio layer object
-         */
-        std::shared_ptr<AudioLayer> getAudioDriver();
-
-        void startAudioDriverStream();
-
-        /**
-         * Functions which occur with a user's action
-         * Place a new call
-         * @param accountId	The account to make the call with
-         * @param to  The recipient of the call
-         * @param conf_id The conference identifier if any
-         * @return id The call ID on success, empty string otherwise
-         */
-        std::string outgoingCall(const std::string& accountId,
-                                 const std::string& to,
-                                 const std::string& conf_id = "");
-
-        /**
-         * Functions which occur with a user's action
-         * Answer the call
-         * @param id  The call identifier
-         */
-        bool answerCall(const std::string& id);
-
-        /**
-         * Functions which occur with a user's action
-         * Hangup the call
-         * @param id  The call identifier
-         */
-        bool hangupCall(const std::string& id);
-
-
-        /**
-         * Functions which occur with a user's action
-         * Hangup the conference (hangup every participants)
-         * @param id  The call identifier
-         */
-        bool hangupConference(const std::string& id);
-
-        /**
-         * Functions which occur with a user's action
-         * Put the call on hold
-         * @param id  The call identifier
-         */
-        bool onHoldCall(const std::string& id);
-
-        /**
-         * Functions which occur with a user's action
-         * Put the call off hold
-         * @param id  The call identifier
-         */
-        bool offHoldCall(const std::string& id);
-
-        /**
-         * Functions which occur with a user's action
-         * Put the media of a call on mute or unmute
-         * @param callID  The call identifier
-         * @param mediaType The media type; eg : AUDIO or VIDEO
-         * @param is_muted true to mute, false to unmute
-         */
-        bool muteMediaCall(const std::string& callId, const std::string& mediaType, bool is_muted);
-
-        /**
-         * Functions which occur with a user's action
-         * Transfer the call
-         * @param id  The call identifier
-         * @param to  The recipient of the transfer
-         */
-        bool transferCall(const std::string& id, const std::string& to);
-
-        /**
-         * Attended transfer
-         * @param The call id to be transfered
-         * @param The target
-         */
-        bool attendedTransfer(const std::string& transferID, const std::string& targetID);
-
-        /**
-         * Notify the client the transfer is successful
-         */
-        void transferSucceeded();
-
-        /**
-         * Notify the client that the transfer failed
-         */
-        void transferFailed();
-
-        /**
-         * Functions which occur with a user's action
-         * Refuse the call
-         * @param id  The call identifier
-         */
-        bool refuseCall(const std::string& id);
-
-        /**
-         * Create a new conference given two participant
-         * @param the first participant ID
-         * @param the second participant ID
-         */
-        std::shared_ptr<Conference>
-        createConference(const std::string& id1, const std::string& id2);
-
-        /**
-         * Delete this conference
-         * @param the conference ID
-         */
-        void removeConference(const std::string& conference_id);
-
-        /**
-         * Return the conference id for which this call is attached
-         * @ param the call id
-         */
-        std::shared_ptr<Conference>
-        getConferenceFromCallID(const std::string& call_id);
-
-        /**
-         * Hold every participant to a conference
-         * @param the conference id
-         */
-        bool holdConference(const std::string& conference_id);
-
-        /**
-         * Unhold all conference participants
-         * @param the conference id
-         */
-        bool unHoldConference(const std::string& conference_id);
-
-        /**
-         * Test if this id is a conference (usefull to test current call)
-         * @param the call id
-         */
-        bool isConference(const std::string& call_id) const;
-
-        /**
-         * Test if a call id corresponds to a conference participant
-         * @param the call id
-         */
-        bool isConferenceParticipant(const std::string& call_id);
-
-        /**
-         * Add a participant to a conference
-         * @param the call id
-         * @param the conference id
-         */
-        bool addParticipant(const std::string& call_id, const std::string& conference_id);
-
-        /**
-         * Bind the main participant to a conference (mainly called on a double click action)
-         * @param the conference id
-         */
-        bool addMainParticipant(const std::string& conference_id);
-
-        /**
-         * Join two participants to create a conference
-         * @param the fist call id
-         * @param the second call id
-         */
-        bool joinParticipant(const std::string& call_id1,
-                             const std::string& call_id2);
-
-        /**
-         * Create a conference from a list of participant
-         * @param A vector containing the list of participant
-         */
-        void createConfFromParticipantList(const std::vector< std::string > &);
-
-        /**
-         * Detach a participant from a conference, put the call on hold, do not hangup it
-         * @param call id
-         * @param the current call id
-         */
-        bool detachParticipant(const std::string& call_id);
-
-        /**
-         * Remove the conference participant from a conference
-         * @param call id
-         */
-        void removeParticipant(const std::string& call_id);
-
-        /**
-         * Join two conference together into one unique conference
-         */
-        bool joinConference(const std::string& conf_id1, const std::string& conf_id2);
-
-        void addStream(Call& call);
-
-        void removeStream(Call& call);
-
-        /**
-         * Save config to file
-         */
-        void saveConfig();
-
-        /**
-         * @return true if we tried to register once
-         */
-        bool hasTriedToRegister_;
-
-        /**
-         * Play a ringtone
-         */
-        void playTone();
-
-        /**
-         * Play a special ringtone ( BUSY ) if there's at least one message on the voice mail
-         */
-        void playToneWithMessage();
-
-        /**
-         * Acts on the audio streams and audio files
-         */
-        void stopTone();
-
-        /**
-         * Handle incoming call and notify user
-         * @param call A call pointer
-         * @param accountId an account id
-         */
-        void incomingCall(Call &call, const std::string& accountId);
-
-        /**
-         * Notify the user that the recipient of the call has answered and the put the
-         * call in Current state
-         * @param id  The call identifier
-         */
-        void peerAnsweredCall(Call& call);
-
-        /**
-         * Rings back because the outgoing call is ringing and the put the
-         * call in Ringing state
-         * @param id  The call identifier
-         */
-        void peerRingingCall(Call& call);
-
-        /**
-         * Put the call in Hungup state, remove the call from the list
-         * @param id  The call identifier
-         */
-        void peerHungupCall(Call& call);
-
-#if HAVE_INSTANT_MESSAGING
-        /**
-         * Notify the client with an incoming message
-         * @param accountId	The account identifier
-         * @param message The content of the message
-         */
-        void incomingMessage(const std::string& callID, const std::string& from, const std::string& message);
-
-
-        /**
-         * Send a new text message to the call, if participate to a conference, send to all participant.
-         * @param callID	The call to send the message
-         * @param message	The content of the message
-        * @param from	        The sender of this message (could be another participant of a conference)
-         */
-        bool sendCallTextMessage(const std::string& callID, const std::string& message, const std::string& from);
-#endif // HAVE_INSTANT_MESSAGING
-
-        /**
-         * Notify the client he has voice mails
-         * @param accountId	  The account identifier
-         * @param nb_msg The number of messages
-         */
-        void startVoiceMessageNotification(const std::string& accountId, int nb_msg);
-
-        /**
-         * ConfigurationManager - Send registration request
-         * @param accountId The account to register/unregister
-         * @param enable The flag for the type of registration
-         *		 false for unregistration request
-         *		 true for registration request
-         */
-        void sendRegister(const std::string& accountId, bool enable);
-
-        void sendTextMessage(const std::string& accountID, const std::string& to, const std::string& message);
-
-        /**
-         * Get account list
-         * @return std::vector<std::string> A list of accoundIDs
-         */
-        std::vector<std::string> getAccountList() const;
-
-        /**
-         * Set the account order in the config file
-         */
-        void setAccountsOrder(const std::string& order);
-
-        /**
-         * Retrieve details about a given account
-         * @param accountID	  The account identifier
-         * @return std::map< std::string, std::string > The account details
-         */
-        std::map<std::string, std::string> getAccountDetails(const std::string& accountID) const;
-
-        /**
-         * Retrieve volatile details such as recent registration errors
-         * @param accountID The account identifier
-         * @return std::map< std::string, std::string > The account volatile details
-         */
-        std::map<std::string, std::string> getVolatileAccountDetails(const std::string& accountID) const;
-
-        /**
-         * Retrieve details about a given call
-         * @param callID	  The account identifier
-         * @return std::map< std::string, std::string > The call details
-         */
-        std::map<std::string, std::string> getCallDetails(const std::string& callID);
-
-        /**
-         * Get call list
-         * @return std::vector<std::string> A list of call IDs
-         */
-        std::vector<std::string> getCallList() const;
-
-        /**
-         * Retrieve details about a given call
-         * @param callID	  The account identifier
-         * @return std::map< std::string, std::string > The call details
-         */
-        std::map<std::string, std::string> getConferenceDetails(const std::string& callID) const;
-
-        /**
-         * Get call list
-         * @return std::vector<std::string> A list of call IDs
-         */
-        std::vector<std::string> getConferenceList() const;
-
-
-        /**
-         * Get a list of participant to a conference
-         * @return std::vector<std::string> A list of call IDs
-         */
-        std::vector<std::string> getParticipantList(const std::string& confID) const;
-
-        /**
-         * Get a list of the display names for everyone in a conference
-         * @return std::vector<std::string> A list of display names
-         */
-        std::vector<std::string> getDisplayNames(const std::string& confID) const;
-
-        std::string getConferenceId(const std::string& callID);
-
-        /**
-         * Save the details of an existing account, given the account ID
-         * This will load the configuration map with the given data.
-         * It will also register/unregister links where the 'Enabled' switched.
-         * @param accountID	  The account identifier
-         * @param details	  The account parameters
-         */
-        void setAccountDetails(const std::string& accountID,
-                               const std::map<std::string, ::std::string > &details);
-
-        /**
-         * Add a new account, and give it a new account ID automatically
-         * @param details The new account parameters
-         * @return The account Id given to the new account
-         */
-        std::string addAccount(const std::map<std::string, std::string> &details);
-
-        /**
-         * Delete an existing account, unregister VoIPLink associated, and
-         * purge from configuration.
-         * @param accountID	The account unique ID
-         */
-        void removeAccount(const std::string& accountID);
-
-        /**
-         * Set input audio plugin
-         * @param audioPlugin The audio plugin
-         */
-        void setAudioPlugin(const std::string& audioPlugin);
-
-        /**
-             * Set audio device
-             * @param index The index of the soundcard
-             * @param the type of stream, either PLAYBACK, CAPTURE, RINGTONE
-             */
-        void setAudioDevice(int index, DeviceType streamType);
-
-        /**
-         * Get list of supported audio output device
-         * @return std::vector<std::string> A list of the audio devices supporting playback
-         */
-        std::vector<std::string> getAudioOutputDeviceList();
-
-        /**
-         * Get list of supported audio input device
-         * @return std::vector<std::string> A list of the audio devices supporting capture
-         */
-        std::vector<std::string> getAudioInputDeviceList();
-
-        /**
-         * Get string array representing integer indexes of output, input, and ringtone device
-         * @return std::vector<std::string> A list of the current audio devices
-         */
-        std::vector<std::string> getCurrentAudioDevicesIndex();
-
-        /**
-         * Get index of an audio device
-         * @param name The string description of an audio device
-         * @return int  His index
-         */
-        int getAudioInputDeviceIndex(const std::string &name);
-        int getAudioOutputDeviceIndex(const std::string &name);
-
-        /**
-         * Get current alsa plugin
-         * @return std::string  The Alsa plugin
-         */
-        std::string getCurrentAudioOutputPlugin() const;
-
-        /**
-         * Get the noise reduction engin state from
-         * the current audio layer.
-         */
-        bool getNoiseSuppressState() const;
-
-        /**
-         * Set the noise reduction engin state in the current
-         * audio layer.
-         */
-        void setNoiseSuppressState(bool state);
-
-        bool isAGCEnabled() const;
-        void setAGCState(bool enabled);
-
-        bool switchInput(const std::string& callid, const std::string& res);
-
-        /**
-         * Ringtone option.
-         * If ringtone is enabled, ringtone on incoming call use custom choice. If not, only standart tone.
-         * @return int	1 if enabled
-         *	        0 otherwise
-         */
-        int isRingtoneEnabled(const std::string& id);
-
-        /**
-         * Set the ringtone option
-         * Inverse current value
-         */
-        void ringtoneEnabled(const std::string& id);
-
-        /**
-         * Get is always recording functionality
-         */
-        bool getIsAlwaysRecording() const;
-
-        /**
-         * Set is always recording functionality, every calls will then be set in RECORDING mode
-         * once answered
-         */
-        void setIsAlwaysRecording(bool isAlwaysRec);
-
-        /**
-         * Set recording on / off
-         * Start recording
-         * @param id  The call identifier
-         * Returns true if the call was set to record
-         */
-        bool toggleRecordingCall(const std::string& id);
-
-        /**
-         * Return true if the call is currently recorded
-         */
-        bool isRecording(const std::string& id);
-
-        /**
-         * Start playback fo a recorded file if and only if audio layer is not already started.
-         * @param File path of the file to play
-             */
-        bool startRecordedFilePlayback(const std::string&);
-
-        void recordingPlaybackSeek(const double value);
-
-        /**
-         * Stop playback of recorded file
-         * @param File of the file to stop
-         */
-        void stopRecordedFilePlayback(const std::string&);
-
-        /**
-         * Set the maximum number of days to keep in the history
-         * @param calls The number of days
-         */
-        void setHistoryLimit(int days);
-
-        /**
-         * Get the maximum number of days to keep in the history
-         * @return double The number of days
-         */
-        int getHistoryLimit() const;
-
-        /**
-         * Configure the start-up option
-         * @return int	1 if Ring should start in the system tray
-         *	        0 otherwise
-         */
-        int isStartHidden();
-
-        /**
-         * Configure the start-up option
-         * At startup, Ring can be displayed or start hidden in the system tray
-         */
-        void startHidden();
-
-        /**
-         * Get the audio manager
-         * @return int The audio manager
-         *		    "alsa"
-         *		    "pulseaudio"
-         */
-        std::string getAudioManager() const;
-
-        /**
-         * Set the audio manager
-         * @return true if api is now in use, false otherwise
-         */
-        bool setAudioManager(const std::string &api);
-
-        /**
-         * Callback called when the audio layer initialised with its
-         * preferred format.
-         */
-        AudioFormat hardwareAudioFormatChanged(AudioFormat format);
-
-        /**
-         * Should be called by any component dealing with an external
-         * audio source, indicating the format used so the mixer format
-         * can be eventually adapted.
-         * @returns the new format used by the main buffer.
-         */
-        AudioFormat audioFormatUsed(AudioFormat format);
-
-        /**
-         * Handle audio sounds heard by a caller while they wait for their
-         * connection to a called party to be completed.
-         */
-        void ringback();
-
-        /**
-         * Handle played music when an incoming call occurs
-         */
-        void playRingtone(const std::string& accountID);
-
-        /**
-         * Handle played music when a congestion occurs
-         */
-        void congestion();
-
-        /**
-         * Play the dtmf-associated sound
-         * @param code  The pressed key
-         */
-        void playDtmf(char code);
-
-        /**
-         * Handle played sound when a call can not be conpleted because of a busy recipient
-         */
-        void callBusy(Call& call);
-
-        /**
-         * Handle played sound when a failure occurs
-         */
-        void callFailure(Call& call, int code=0);
-
-        /**
-         * Retrieve the current telephone tone
-         * @return AudioLoop*   The audio tone or 0 if no tone (init before calling this function)
-         */
-        AudioLoop* getTelephoneTone();
-
-        /**
-         * Retrieve the current telephone file
-         * @return AudioLoop* The audio file or 0 if the wav is stopped
-         */
-        AudioLoop* getTelephoneFile();
-
-        /**
-         * @return true is there is one or many incoming call waiting
-         * new call, not anwsered or refused
-         */
-        bool incomingCallsWaiting();
-
-        /**
-         * Return a new random callid that is not present in the list
-         * @return std::string A brand new callid
-         */
-        std::string getNewCallID();
-
-        /**
-         * Get the current call
-         * @return std::shared_ptr<Call> A call shared pointer (could be empty)
-         */
-        std::shared_ptr<Call> getCurrentCall() const;
-
-        /**
-         * Get the current call id
-         * @return std::string	The call id or ""
-         */
-        const std::string getCurrentCallId() const;
-
-        /**
-         * Check if a call is the current one
-         * @param call the new call
-         * @return bool True if the call is the current
-         */
-        bool isCurrentCall(const Call& call) const;
-
-        void initAudioDriver();
-
-        /**
-         * Load the accounts order set by the user from the dringrc config file
-         * @return std::vector<std::string> A vector containing the account ID's
-         */
-        std::vector<std::string> loadAccountOrder() const;
-
-
-    private:
-        void removeAccounts();
-
-        bool parseConfiguration();
-
-        // Set the ringtone or recorded call to be played
-        void updateAudioFile(const std::string &file, int sampleRate);
-
-        /**
-         * Get the Call referred to by callID. If the Call does not exist, return NULL
-         */
-        std::shared_ptr<Call> getCallFromCallID(const std::string &callID);
-
-        /**
-         * Process remaining participant given a conference and the current call id.
-         * Mainly called when a participant is detached or hagned up
-         * @param current call id
-         * @param conference pointer
-         */
-        void processRemainingParticipants(Conference &conf);
-
-        /**
-         * Create config directory in home user and return configuration file path
-         */
-        std::string retrieveConfigPath() const;
-
-        void unsetCurrentCall();
-
-        void switchCall(std::shared_ptr<Call> call);
-
-        /*
-         * Play one tone
-         * @return false if the driver is uninitialize
-         */
-        void playATone(Tone::TONEID toneId);
-
-        /** Current Call ID */
-        std::shared_ptr<Call> currentCall_ = nullptr;
-
-        /** Protected current call access */
-        std::mutex currentCallMutex_;
-
-        /** Audio layer */
-        std::shared_ptr<AudioLayer> audiodriver_{nullptr};
-
-        // Main thread
-        std::unique_ptr<DTMF> dtmfKey_;
-
-        /** Buffer to generate DTMF */
-        AudioBuffer dtmfBuf_;
-
-        /////////////////////
-        // Protected by Mutex
-        /////////////////////
-        std::mutex toneMutex_;
-        std::unique_ptr<TelephoneTone> telephoneTone_;
-        std::unique_ptr<AudioFile> audiofile_;
-
-        // To handle volume control
-        // short speakerVolume_;
-        // short micVolume_;
-        // End of sound variable
-
-        /**
-         * Mutex used to protect audio layer
-         */
-        std::mutex audioLayerMutex_;
-
-        /**
-         * Waiting Call Vectors
-         */
-        CallIDSet waitingCalls_;
-
-        /**
-         * Protect waiting call list, access by many voip/audio threads
-         */
-        std::mutex waitingCallsMutex_;
-
-        /**
-         * Add incoming callid to the waiting list
-         * @param id std::string to add
-         */
-        void addWaitingCall(const std::string& id);
-
-        /**
-         * Remove incoming callid to the waiting list
-         * @param id std::string to remove
-         */
-        void removeWaitingCall(const std::string& id);
-
-        /**
-         * Path of the ConfigFile
-         */
-        std::string path_;
-
-        /**
-         * Load the account map from configuration
-         */
-        int loadAccountMap(const YAML::Node &node);
-
-        /**
-         * Instance of the RingBufferPool for the whole application
-         *
-         * In order to send signal to other parts of the application, one must pass through the RingBufferMananger.
-         * Audio instances must be registered into the RingBufferMananger and bound together via the ManagerImpl.
-         *
-         */
-        std::unique_ptr<RingBufferPool> ringbufferpool_;
-
-    public:
-
-        /**
-         * Return a pointer to the instance of the RingBufferPool
-         */
-        RingBufferPool& getRingBufferPool() { return *ringbufferpool_; }
-
-        /**
-         * Tell if there is a current call processed
-         * @return bool True if there is a current call
-         */
-        bool hasCurrentCall() const;
-
-        /**
-         * Get an account pointer, looks for both SIP and IAX
-         * @param accountID account ID to get
-         * @return std::shared_ptr<Account> Shared pointer on an Account instance or nullptr if not found
-         */
-        template <class T=Account>
-        std::shared_ptr<T> getAccount(const std::string& accountID) const {
-            return accountFactory_.getAccount<T>(accountID);
-        }
-
-        template <class T=Account>
-        std::vector<std::shared_ptr<T> > getAllAccounts() const {
-            return accountFactory_.getAllAccounts<T>();
-        }
-
-        template <class T=Account>
-        bool accountCount() const {
-            return accountFactory_.accountCount<T>();
-        }
-
-        std::shared_ptr<Account> getIP2IPAccount() const {
-            return accountFactory_.getIP2IPAccount();
-        }
-
-        // only used by test framework
-        bool hasAccount(const std::string& accountID) {
-            return accountFactory_.hasAccount(accountID);
-        }
-
-        /**
-         * Send registration for all enabled accounts
-         */
-        void registerAccounts();
-
-        /**
-         * Suspends Ring's audio processing if no calls remain, allowing
-         * other applications to resume audio.
-         * See:
-         * https://projects.savoirfairelinux.com/issues/7037
-        */
-        void checkAudio();
-
-        /**
-         * Call periodically to poll for VoIP events */
-        void
-        pollEvents();
-
-        /**
-         * Create a new outgoing 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& toUrl,
-                                              const std::string& preferredAccountId);
-
-        CallFactory callFactory;
-
-        using EventHandler = std::function<void()>;
-
-        /**
-         * Install an event handler called periodically by pollEvents().
-         * @param handlerId an unique identifier for the handler.
-         * @param handler the event handler function.
-         */
-        void registerEventHandler(uintptr_t handlerId, EventHandler handler);
-
-        /**
-         * Remove a previously registered event handler.
-         * @param handlerId id of handler to remove.
-         */
-        void unregisterEventHandler(uintptr_t handlerId);
-
-        IceTransportFactory& getIceTransportFactory() { return *ice_tf_; }
-
-        void addTask(const std::function<bool()>&& task);
-
-#ifdef RING_VIDEO
-        std::shared_ptr<video::SinkClient> createSinkClient(const std::string& id="");
-
-        std::shared_ptr<video::SinkClient> getSinkClient(const std::string& id);
-#endif // RING_VIDEO
-
-    private:
-        NON_COPYABLE(ManagerImpl);
-
-        std::map<uintptr_t, EventHandler> eventHandlerMap_;
-        decltype(eventHandlerMap_)::iterator nextEventHandler_;
-
-        std::list<std::function<bool()>> pendingTaskList_;
-
-        /**
-         * Test if call is a valid call, i.e. have been created and stored in
-         * call-account map
-         * @param callID the std::string to be tested
-         * @return true if call is created and present in the call-account map
-         */
-        bool isValidCall(const std::string& callID);
-
-        /**
-         * Send unregister for all enabled accounts
-         */
-        void unregisterAccounts();
-
-
-        // Map containing conference pointers
-        ConferenceMap conferenceMap_;
-
-        std::atomic_bool finished_ {false};
-
-        AccountFactory accountFactory_;
-
-        std::mt19937_64 rand_;
-
-        void loadDefaultAccountMap();
-
-        void loadAccount(const YAML::Node &item, int &errorCount,
-                         const std::string &accountOrder);
-
-        /* ICE support */
-        std::unique_ptr<IceTransportFactory> ice_tf_;
-
-        std::unique_ptr<tls::GnuTlsGlobalInit> gnutlGIG_;
-
-        /* Sink ID mapping */
-        std::map<std::string, std::weak_ptr<video::SinkClient>> sinkMap_;
-};
-
-} // namespace ring
-
-#endif // MANAGER_IMPL_H_
diff --git a/src/media/video/video_device_monitor.cpp b/src/media/video/video_device_monitor.cpp
index fa5bbef028e4b50ac7ca42e50ff90f1aabd7684f..997f913455fee9d10004ca562402b64696d1b734 100644
--- a/src/media/video/video_device_monitor.cpp
+++ b/src/media/video/video_device_monitor.cpp
@@ -172,7 +172,7 @@ start:
 static void
 notify()
 {
-    if (!ManagerImpl::initialized) {
+    if (!Manager::initialized) {
         RING_WARN("Manager not initialized yet");
         return;
     }
diff --git a/src/ring_api.cpp b/src/ring_api.cpp
index 0cb592d99e1752c485c0efae0555260a8096993d..d6709b8d713ae74f526fc163a32e5c7c0c32a257 100644
--- a/src/ring_api.cpp
+++ b/src/ring_api.cpp
@@ -38,7 +38,6 @@
 #endif
 
 #include "manager.h"
-#include "managerimpl.h"
 #include "logger.h"
 #include "dring.h"
 #include "callmanager_interface.h"
diff --git a/test/audiolayertest.h b/test/audiolayertest.h
index adfc05a922a9ee2c401800fa4a4255d3c9c35092..98e40e8242fc6f69c99f4b14094398d5e7c98517 100644
--- a/test/audiolayertest.h
+++ b/test/audiolayertest.h
@@ -46,7 +46,7 @@
 
 namespace ring {
 
-class ManagerImpl;
+class Manager;
 class PulseLayer;
 
 } // namespace ring
@@ -71,7 +71,7 @@ class AudioLayerTest: public CppUnit::TestFixture {
     private:
         NON_COPYABLE(AudioLayerTest);
 
-        ManagerImpl* manager_;
+        Manager* manager_;
         PulseLayer* pulselayer_;
         int layer_;
 };