diff --git a/src/call.cpp b/src/call.cpp
index 87dfa762b790278f19826a5c72bbeefd3b07dcc5..18d5239d1ad179d208fa6983a945c7ffe530ee5e 100644
--- a/src/call.cpp
+++ b/src/call.cpp
@@ -683,4 +683,15 @@ Call::setConferenceInfo(const std::string& msg)
     }
 }
 
+void
+Call::sendConfOrder(const Json::Value& root)
+{
+    std::map<std::string, std::string> messages;
+    Json::StreamWriterBuilder wbuilder;
+    wbuilder["commentStyle"] = "None";
+    wbuilder["indentation"] = "";
+    messages["application/confOrder+json"] = Json::writeString(wbuilder, root);
+    sendTextMessage(messages, getPeerDisplayName());
+}
+
 } // namespace jami
diff --git a/src/call.h b/src/call.h
index 48d74cbb48d16d348a6ff22a20ab53fc7fe4d572..9ddf1c6ac9624dc775998ac743b41465f8b2cbc7 100644
--- a/src/call.h
+++ b/src/call.h
@@ -346,6 +346,7 @@ public: // media management
     }
 
     std::unique_ptr<AudioDeviceGuard> audioGuard;
+    void sendConfOrder(const Json::Value& root);
 
 protected:
     virtual void merge(Call& scall);
diff --git a/src/conference.cpp b/src/conference.cpp
index 09bf7734a8a2f018408f7b255547e5e536d2dcbd..0da4466d4f50b5939f46a702ddc673bd06e2e710 100644
--- a/src/conference.cpp
+++ b/src/conference.cpp
@@ -92,11 +92,11 @@ Conference::Conference()
                 if (auto videoMixer = shared->getVideoMixer())
                     active = info.source == videoMixer->getActiveParticipant();
                 subCalls.erase(it->second);
-                std::string_view partURI = string_remove_suffix(uri, '@');
-                auto isModerator = shared->isModerator(partURI);
+                std::string_view peerID = string_remove_suffix(uri, '@');
+                auto isModerator = shared->isModerator(peerID);
                 if (uri.empty())
-                    partURI = "host"sv;
-                auto isModeratorMuted = shared->isMuted(partURI);
+                    peerID = "host"sv;
+                auto isModeratorMuted = shared->isMuted(peerID);
                 newInfo.emplace_back(ParticipantInfo {std::move(uri),
                                                       "",
                                                       active,
@@ -318,16 +318,18 @@ Conference::setActiveParticipant(const std::string& participant_id)
         videoMixer_->setActiveHost();
         return;
     }
-    for (const auto& item : participants_) {
-        if (auto call = getCall(item)) {
-            if (participant_id == item
-                || call->getPeerNumber().find(participant_id) != std::string::npos) {
-                auto videoRecv = reinterpret_cast<Observable<std::shared_ptr<MediaFrame>>*>(
-                    call->getVideoReceiver());
-                videoMixer_->setActiveParticipant(videoRecv);
-                return;
-            }
-        }
+    if (auto call = getCallFromPeerID(participant_id)) {
+        auto videoRecv = reinterpret_cast<Observable<std::shared_ptr<MediaFrame>>*>(
+            call->getVideoReceiver());
+        videoMixer_->setActiveParticipant(videoRecv);
+        return;
+    }
+
+    auto remoteHost = findHostforRemoteParticipant(participant_id);
+    if (not remoteHost.empty()) {
+        // This logic will be handled client side
+        JAMI_WARN("Change remote layout is not supported");
+        return;
     }
     // Unset active participant by default
     videoMixer_->setActiveParticipant(nullptr);
@@ -673,9 +675,9 @@ Conference::onConfOrder(const std::string& callId, const std::string& confOrder)
 {
     // Check if the peer is a master
     if (auto call = Manager::instance().getCallFromCallID(callId)) {
-        auto uri = string_remove_suffix(call->getPeerNumber(), '@');
-        if (!isModerator(uri)) {
-            JAMI_WARN("Received conference order from a non master (%s)", uri.data());
+        auto peerID = string_remove_suffix(call->getPeerNumber(), '@');
+        if (!isModerator(peerID)) {
+            JAMI_WARN("Received conference order from a non master (%.*s)", (int) peerID.size(), peerID.data());
             return;
         }
 
@@ -684,7 +686,7 @@ Conference::onConfOrder(const std::string& callId, const std::string& confOrder)
         Json::CharReaderBuilder rbuilder;
         auto reader = std::unique_ptr<Json::CharReader>(rbuilder.newCharReader());
         if (!reader->parse(confOrder.c_str(), confOrder.c_str() + confOrder.size(), &root, &err)) {
-            JAMI_WARN("Couldn't parse conference order from %s", uri.data());
+            JAMI_WARN("Couldn't parse conference order from %.*s", (int) peerID.size(), peerID.data());
             return;
         }
         if (root.isMember("layout")) {
@@ -716,27 +718,26 @@ Conference::isModerator(std::string_view uri) const
 }
 
 void
-Conference::setModerator(const std::string& uri, const bool& state)
+Conference::setModerator(const std::string& participant_id, const bool& state)
 {
     for (const auto& p : participants_) {
         if (auto call = getCall(p)) {
-            auto partURI = string_remove_suffix(call->getPeerNumber(), '@');
-            auto isURIModerator = isModerator(uri);
-            if (partURI == uri) {
-                if (state and not isURIModerator) {
-                    JAMI_DBG("Add %s as moderator", partURI.data());
-                    moderators_.emplace(uri);
+            auto isPeerModerator = isModerator(participant_id);
+            if (participant_id == string_remove_suffix(call->getPeerNumber(), '@')) {
+                if (state and not isPeerModerator) {
+                    JAMI_DBG("Add %s as moderator", participant_id.c_str());
+                    moderators_.emplace(participant_id);
                     updateModerators();
-                } else if (not state and isURIModerator) {
-                    JAMI_DBG("Remove %s as moderator", partURI.data());
-                    moderators_.erase(uri);
+                } else if (not state and isPeerModerator) {
+                    JAMI_DBG("Remove %s as moderator", participant_id.c_str());
+                    moderators_.erase(participant_id);
                     updateModerators();
                 }
                 return;
             }
         }
     }
-    JAMI_WARN("Fail to set %s as moderator (participant not found)", uri.c_str());
+    JAMI_WARN("Fail to set %s as moderator (participant not found)", participant_id.c_str());
 }
 
 void
@@ -756,10 +757,30 @@ Conference::isMuted(std::string_view uri) const
 }
 
 void
-Conference::muteParticipant(const std::string& uri, const bool& state)
+Conference::muteParticipant(const std::string& participant_id, const bool& state)
 {
+    // Prioritize remote mute, otherwise the mute info is lost during
+    // the conference merge (we don't send back info to remoteHost,
+    // cf. getConfInfoHostUri method)
+
+    // Transfert remote participant mute
+    auto remoteHost = findHostforRemoteParticipant(participant_id);
+    if (not remoteHost.empty()) {
+        if (auto call = getCallFromPeerID(string_remove_suffix(remoteHost, '@'))) {
+            auto w = call->getAccount();
+            auto account = w.lock();
+            if (!account)
+                return;
+            Json::Value root;
+            root["muteParticipant"] = participant_id;
+            root["muteState"] = state ? TRUE_STR : FALSE_STR;
+            call->sendConfOrder(root);
+            return;
+        }
+    }
+
     // Moderator mute host
-    if (isHost(uri)) {
+    if (isHost(participant_id)) {
         auto isHostMuted = isMuted("host"sv);
         if (state and not isHostMuted) {
             participantsMuted_.emplace("host"sv);
@@ -779,26 +800,20 @@ Conference::muteParticipant(const std::string& uri, const bool& state)
     }
 
     // Mute participant
-    auto peerURI = string_remove_suffix(uri, '@');
-    for (const auto& p : participants_) {
-        if (auto call = getCall(p)) {
-            auto partURI = string_remove_suffix(call->getPeerNumber(), '@');
-            auto isPartMuted = isMuted(partURI);
-            if (partURI == peerURI) {
-                if (state and not isPartMuted) {
-                    JAMI_DBG("Mute participant %.*s", (int) partURI.size(), partURI.data());
-                    participantsMuted_.emplace(std::string(partURI));
-                    unbindParticipant(p);
-                    updateMuted();
-                } else if (not state and isPartMuted) {
-                    JAMI_DBG("Unmute participant %.*s", (int) partURI.size(), partURI.data());
-                    participantsMuted_.erase(std::string(partURI));
-                    bindParticipant(p);
-                    updateMuted();
-                }
-                return;
-            }
+    if (auto call = getCallFromPeerID(participant_id)) {
+        auto isPartMuted = isMuted(participant_id);
+        if (state and not isPartMuted) {
+            JAMI_DBG("Mute participant %.*s", (int) participant_id.size(), participant_id.data());
+            participantsMuted_.emplace(std::string(participant_id));
+            unbindParticipant(call->getCallId());
+            updateMuted();
+        } else if (not state and isPartMuted) {
+            JAMI_DBG("Unmute participant %.*s", (int) participant_id.size(), participant_id.data());
+            participantsMuted_.erase(std::string(participant_id));
+            bindParticipant(call->getCallId());
+            updateMuted();
         }
+        return;
     }
 }
 
@@ -807,21 +822,15 @@ Conference::updateMuted()
 {
     std::lock_guard<std::mutex> lk(confInfoMutex_);
     for (auto& info : confInfo_) {
-        auto uri = string_remove_suffix(info.uri, '@');
-        if (uri.empty()) {
-            uri = "host"sv;
-            info.audioModeratorMuted = isMuted(uri);
+        auto peerID = string_remove_suffix(info.uri, '@');
+        if (peerID.empty()) {
+            peerID = "host"sv;
+            info.audioModeratorMuted = isMuted(peerID);
             info.audioLocalMuted = audioMuted_;
         } else {
-            info.audioModeratorMuted = isMuted(uri);
-            for (const auto& item : participants_) {
-                if (auto call = getCall(item)) {
-                    if (uri == string_remove_suffix(call->getPeerNumber(), '@')) {
-                        info.audioLocalMuted = call->isPeerMuted();
-                        break;
-                    }
-                }
-            }
+            info.audioModeratorMuted = isMuted(peerID);
+            if (auto call = getCallFromPeerID(peerID))
+                info.audioLocalMuted = call->isPeerMuted();
         }
     }
     sendConferenceInfos();
@@ -894,14 +903,27 @@ Conference::hangupParticipant(const std::string& participant_id)
         return;
     }
 
-    for (const auto& p : participants_) {
-        if (auto call = getCall(p)) {
-            std::string_view partURI = string_remove_suffix(call->getPeerNumber(), '@');
-            if (partURI == participant_id) {
-                Manager::instance().hangupCall(call->getCallId());
-                return;
-            }
-        }
+    if (auto call = getCallFromPeerID(participant_id)) {
+        Manager::instance().hangupCall(call->getCallId());
+        return;
+    }
+
+    // Transfert remote participant hangup
+    auto remoteHost = findHostforRemoteParticipant(participant_id);
+    if (remoteHost.empty()) {
+        JAMI_WARN("Can't hangup %s, peer not found", participant_id.c_str());
+        return;
+    }
+    if (auto call = getCallFromPeerID(string_remove_suffix(remoteHost, '@'))) {
+        auto w = call->getAccount();
+        auto account = w.lock();
+        if (!account)
+            return;
+
+        Json::Value root;
+        root["hangupParticipant"] = participant_id;
+        call->sendConfOrder(root);
+        return;
     }
 }
 
@@ -962,14 +984,10 @@ Conference::resizeRemoteParticipant(const std::string& peerURI, ParticipantInfo&
     ParticipantInfo localCell;
 
     // get the size of the remote frame
-    for (const auto& item : participants_) {
-        auto sipCall = std::dynamic_pointer_cast<SIPCall>(
-            Manager::instance().callFactory.getCall(item, Call::LinkType::SIP));
-        if (sipCall && sipCall->getPeerNumber().find(peerURI) != std::string::npos) {
-            remoteFrameHeight = sipCall->getVideoRtp().getVideoReceive()->getHeight();
-            remoteFrameWidth = sipCall->getVideoRtp().getVideoReceive()->getWidth();
-            break;
-        }
+    if (auto call = std::dynamic_pointer_cast<SIPCall>(
+            getCallFromPeerID(string_remove_suffix(peerURI, '@')))) {
+        remoteFrameHeight = call->getVideoRtp().getVideoReceive()->getHeight();
+        remoteFrameWidth = call->getVideoRtp().getVideoReceive()->getWidth();
     }
 
     if (remoteFrameHeight == 0 or remoteFrameWidth == 0) {
@@ -1049,4 +1067,16 @@ Conference::findHostforRemoteParticipant(std::string_view uri)
     return "";
 }
 
+std::shared_ptr<Call>
+Conference::getCallFromPeerID(std::string_view peerID)
+{
+    for (const auto& p : participants_) {
+        auto call = getCall(p);
+        if (call && string_remove_suffix(call->getPeerNumber(), '@') == peerID) {
+            return call;
+        }
+    }
+    return nullptr;
+}
+
 } // namespace jami
diff --git a/src/conference.h b/src/conference.h
index 928485c63e3d956320b109debce294f4b0440030..a063bfa7050df2fa80b1fdd0426d269e5a7ee2c8 100644
--- a/src/conference.h
+++ b/src/conference.h
@@ -340,6 +340,7 @@ private:
     std::map<std::string, ConfInfo> remoteHosts_;
     std::string confInfo2str(const ConfInfo& confInfo);
     std::string_view findHostforRemoteParticipant(std::string_view uri);
+    std::shared_ptr<Call> getCallFromPeerID(std::string_view peerID);
 
 #ifdef ENABLE_PLUGIN
     /**
diff --git a/src/manager.cpp b/src/manager.cpp
index 800dd4d79e7f1ef924be9caef2fbbe009fbccce9..1a28aec0ae0704dcf208c0e088f7bd5d961abc5c 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -1500,12 +1500,7 @@ Manager::setConferenceLayout(const std::string& confId, int layout)
         std::map<std::string, std::string> messages;
         Json::Value root;
         root["layout"] = layout;
-        Json::StreamWriterBuilder wbuilder;
-        wbuilder["commentStyle"] = "None";
-        wbuilder["indentation"] = "";
-        auto output = Json::writeString(wbuilder, root);
-        messages["application/confOrder+json"] = output;
-        call->sendTextMessage(messages, call->getPeerDisplayName());
+        call->sendConfOrder(root);
     }
 }
 
@@ -1518,12 +1513,7 @@ Manager::setActiveParticipant(const std::string& confId, const std::string& part
         std::map<std::string, std::string> messages;
         Json::Value root;
         root["activeParticipant"] = participant;
-        Json::StreamWriterBuilder wbuilder;
-        wbuilder["commentStyle"] = "None";
-        wbuilder["indentation"] = "";
-        auto output = Json::writeString(wbuilder, root);
-        messages["application/confOrder+json"] = output;
-        call->sendTextMessage(messages, call->getPeerDisplayName());
+        call->sendConfOrder(root);
     }
 }
 
@@ -1536,12 +1526,7 @@ Manager::hangupParticipant(const std::string& confId, const std::string& partici
         std::map<std::string, std::string> messages;
         Json::Value root;
         root["hangupParticipant"] = participant;
-        Json::StreamWriterBuilder wbuilder;
-        wbuilder["commentStyle"] = "None";
-        wbuilder["indentation"] = "";
-        auto output = Json::writeString(wbuilder, root);
-        messages["application/confOrder+json"] = output;
-        call->sendTextMessage(messages, call->getPeerDisplayName());
+        call->sendConfOrder(root);
     }
 }
 
@@ -3284,12 +3269,7 @@ Manager::muteParticipant(const std::string& confId,
         Json::Value root;
         root["muteParticipant"] = participant;
         root["muteState"] = state ? TRUE_STR : FALSE_STR;
-        Json::StreamWriterBuilder wbuilder;
-        wbuilder["commentStyle"] = "None";
-        wbuilder["indentation"] = "";
-        auto output = Json::writeString(wbuilder, root);
-        messages["application/confOrder+json"] = output;
-        call->sendTextMessage(messages, call->getPeerDisplayName());
+        call->sendConfOrder(root);
     }
 }