diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index f2aab4c5b04753017d462b1d69a5e215d0c4d71c..e06b506eb53f3894f55439e4e57b9f7326ffcddc 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -394,6 +394,26 @@ SIPCall::requestKeyframe()
     lastKeyFrameReq_ = now;
 }
 
+void
+SIPCall::setMute(bool state)
+{
+    std::string BODY = "<?xml version=\"1.0\" encoding=\"utf-8\" ?>"
+                       "<media_control><vc_primitive><to_encoder>"
+                       "<mute_state="
+                       + std::to_string(state)
+                       + "/>"
+                         "</to_encoder></vc_primitive></media_control>";
+    // see https://tools.ietf.org/html/rfc5168 for XML Schema for Media Control details
+
+    JAMI_DBG("Sending mute state via SIP INFO");
+
+    try {
+        sendSIPInfo(BODY.c_str(), "media_control+xml");
+    } catch (const std::exception& e) {
+        JAMI_ERR("Error sending mute state: %s", e.what());
+    }
+}
+
 void
 SIPCall::updateSDPFromSTUN()
 {
@@ -1294,6 +1314,8 @@ SIPCall::muteMedia(const std::string& mediaType, bool mute)
         avformatrtp_->setMuted(isAudioMuted_);
         if (not isSubcall())
             emitSignal<DRing::CallSignal::AudioMuted>(getCallId(), isAudioMuted_);
+        setMute(mute);
+
     }
 }
 
@@ -1733,4 +1755,18 @@ SIPCall::setRemoteRecording(bool state)
     peerRecording_ = state;
 }
 
+void
+SIPCall::setPeerMute(bool state)
+{
+    if (state) {
+        JAMI_WARN("SIP Peer muted");
+    } else {
+        JAMI_WARN("SIP Peer ummuted");
+    }
+    peerMuted_ = state;
+    if (auto conf = Manager::instance().getConferenceFromID(getConfId())) {
+        conf->muteParticipant(getPeerNumber(), state);
+    }
+}
+
 } // namespace jami
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index e9d88cb8f54e2f30e615ccbd9c215858a8abff8d..58cab3da4a95f302a8e2c84eef75b45070dbec7a 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -240,7 +240,13 @@ public: // NOT SIP RELATED (good candidates to be moved elsewhere)
 
     void setRemoteRecording(bool state);
 
-    bool isPeerRecording() { return peerRecording_; }
+    bool isPeerRecording() const { return peerRecording_; }
+
+    void setMute(bool state);
+
+    void setPeerMute(bool state);
+
+    bool isPeerMuted() const { return peerMuted_; }
 
 private:
     using clock = std::chrono::steady_clock;
@@ -381,6 +387,7 @@ private:
     OnReadyCb offHoldCb_ {};
 
     bool peerRecording_ {false};
+    bool peerMuted_ {false};
 
     std::atomic_bool waitForIceInit_ {false};
 };
diff --git a/src/sip/sipvoiplink.cpp b/src/sip/sipvoiplink.cpp
index 0ef2be8782a38b0a461cd6da3a209fe02f00f4de..7b91e4861cafade3925a18a5c4e2d653f9b6b8dd 100644
--- a/src/sip/sipvoiplink.cpp
+++ b/src/sip/sipvoiplink.cpp
@@ -1053,6 +1053,7 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body)
         static constexpr auto PICT_FAST_UPDATE = "picture_fast_update"sv;
         static constexpr auto DEVICE_ORIENTATION = "device_orientation"sv;
         static constexpr auto RECORDING_STATE = "recording_state"sv;
+        static constexpr auto MUTE_STATE = "mute_state"sv;
 
         if (body_msg.find(PICT_FAST_UPDATE) != std::string_view::npos) {
             call.sendKeyframe();
@@ -1093,6 +1094,20 @@ handleMediaControl(SIPCall& call, pjsip_msg_body* body)
                 }
                 return true;
             }
+        } else if (body_msg.find(MUTE_STATE) != std::string_view::npos) {
+            static const std::regex REC_REGEX("mute_state=([0-1])");
+            std::svmatch matched_pattern;
+            std::regex_search(body_msg, matched_pattern, REC_REGEX);
+
+            if (matched_pattern.ready() && !matched_pattern.empty() && matched_pattern[1].matched) {
+                try {
+                    bool state = std::stoi(matched_pattern[1]);
+                    call.setPeerMute(state);
+                } catch (const std::exception& e) {
+                    JAMI_WARN("Error parsing state remote mute: %s", e.what());
+                }
+                return true;
+            }
         }
     }