diff --git a/src/call.h b/src/call.h
index c9677570b5cc41069c09a8589311f469411c9af4..d2e370c563b8273684a31ae2fa507d92fc057b40 100644
--- a/src/call.h
+++ b/src/call.h
@@ -372,7 +372,7 @@ public:
     virtual std::vector<MediaAttribute> getMediaAttributeList() const = 0;
 
 #ifdef ENABLE_VIDEO
-    virtual void createSinks(const ConfInfo& infos) = 0;
+    virtual void createSinks(ConfInfo& infos) = 0;
 #endif
 
     virtual void switchInput(const std::string& = {}) {};
diff --git a/src/client/callmanager.cpp b/src/client/callmanager.cpp
index aafd5e9d1597d288445f0c8a4ee749a70dfea01b..67c84b21a23ca1d1c09e8489e5645cd420dab5b3 100644
--- a/src/client/callmanager.cpp
+++ b/src/client/callmanager.cpp
@@ -586,27 +586,8 @@ setActiveStream(const std::string& accountId,
     if (const auto account = jami::Manager::instance().getAccount<jami::JamiAccount>(accountId)) {
         if (auto conf = account->getConference(confId)) {
             conf->setActiveStream(streamId, state);
-        } else if (auto call = account->getCall(confId)) {
-            if (call->conferenceProtocolVersion() == 1) {
-                Json::Value sinkVal;
-                sinkVal["active"] = state;
-                Json::Value mediasObj;
-                mediasObj[streamId] = sinkVal;
-                Json::Value deviceVal;
-                deviceVal["medias"] = mediasObj;
-                Json::Value deviceObj;
-                deviceObj[deviceId] = deviceVal;
-                Json::Value accountVal;
-                deviceVal["devices"] = deviceObj;
-                Json::Value root;
-                root[accountUri] = deviceVal;
-                root["version"] = 1;
-                call->sendConfOrder(root);
-            } else if (call->conferenceProtocolVersion() == 0) {
-                Json::Value root;
-                root["activeParticipant"] = accountUri;
-                call->sendConfOrder(root);
-            }
+        } else if (auto call = std::static_pointer_cast<jami::SIPCall>(account->getCall(confId))) {
+            call->setActiveMediaStream(accountUri, deviceId, streamId, state);
         }
     }
 }
diff --git a/src/manager.cpp b/src/manager.cpp
index b6a43b60c672eb2acf82e781072750db3ef532c6..2ca950b4ac2a33f91dbb452c8099ccf82a78c3c2 100644
--- a/src/manager.cpp
+++ b/src/manager.cpp
@@ -3036,7 +3036,8 @@ Manager::createSinkClients(
     const std::string& callId,
     const ConfInfo& infos,
     const std::vector<std::shared_ptr<video::VideoFrameActiveWriter>>& videoStreams,
-    std::map<std::string, std::shared_ptr<video::SinkClient>>& sinksMap)
+    std::map<std::string, std::shared_ptr<video::SinkClient>>& sinksMap,
+    const std::string& accountId)
 {
     std::lock_guard<std::mutex> lk(pimpl_->sinksMutex_);
     std::set<std::string> sinkIdsList {};
@@ -3050,7 +3051,15 @@ Manager::createSinkClients(
         }
         if (participant.w && participant.h && !participant.videoMuted) {
             auto currentSink = getSinkClient(sinkId);
+            if (!accountId.empty() &&
+                currentSink &&
+                string_remove_suffix(participant.uri, '@') == getAccount(accountId)->getUsername() &&
+                participant.device == getAccount<JamiAccount>(accountId)->currentDeviceId()) {
+                // This is a local sink that must already exist
+                continue;
+            }
             if (currentSink) {
+                // If sink exists, update it
                 currentSink->setCrop(participant.x, participant.y, participant.w, participant.h);
                 sinkIdsList.emplace(sinkId);
                 continue;
diff --git a/src/manager.h b/src/manager.h
index 1949e7c73828bad981a7613905872d813230c8aa..998e1791147ffb8e022886ce06f5cbacc7367537 100644
--- a/src/manager.h
+++ b/src/manager.h
@@ -821,7 +821,8 @@ public:
     void createSinkClients(const std::string& callId,
                            const ConfInfo& infos,
                            const std::vector<std::shared_ptr<video::VideoFrameActiveWriter>>& videoStreams,
-                           std::map<std::string, std::shared_ptr<video::SinkClient>>& sinksMap);
+                           std::map<std::string, std::shared_ptr<video::SinkClient>>& sinksMap,
+                           const std::string& accountId = "");
 
     /**
      * Return an existing SinkClient instance as a shared_ptr associated to the given identifier.
diff --git a/src/media/media_decoder.cpp b/src/media/media_decoder.cpp
index 8dc5ad4e06de08d40bd91f7912acbbbcd8728336..52625cf15f02766b5bd16a15c881bc65a08ed8af 100644
--- a/src/media/media_decoder.cpp
+++ b/src/media/media_decoder.cpp
@@ -767,19 +767,19 @@ MediaDecoder::flush()
 int
 MediaDecoder::getWidth() const
 {
-    return decoderCtx_->width;
+    return decoderCtx_ ? decoderCtx_->width : 0;
 }
 
 int
 MediaDecoder::getHeight() const
 {
-    return decoderCtx_->height;
+    return decoderCtx_ ? decoderCtx_->height : 0;
 }
 
 std::string
 MediaDecoder::getDecoderName() const
 {
-    return decoderCtx_->codec->name;
+    return decoderCtx_ ? decoderCtx_->codec->name : "";
 }
 
 rational<double>
diff --git a/src/media/video/video_input.cpp b/src/media/video/video_input.cpp
index 5c811bc16d440a1da7c3e73ce7b8f9f475b57c28..9d6bce3a9dfe2bcb160e32697dec231ee800bafd 100644
--- a/src/media/video/video_input.cpp
+++ b/src/media/video/video_input.cpp
@@ -122,7 +122,7 @@ VideoInput::getWidth() const
     if (videoManagedByClient()) {
         return decOpts_.width;
     }
-    return decoder_->getWidth();
+    return decoder_ ? decoder_->getWidth() : 0;
 }
 
 int
@@ -131,7 +131,7 @@ VideoInput::getHeight() const
     if (videoManagedByClient()) {
         return decOpts_.height;
     }
-    return decoder_->getHeight();
+    return decoder_ ? decoder_->getHeight() : 0;
 }
 
 AVPixelFormat
diff --git a/src/media/video/video_mixer.cpp b/src/media/video/video_mixer.cpp
index 33025aa39f65a97737937862a71f36bd61f41930..2238bea051ded77f3ddec44d1f4dae86b71a49d6 100644
--- a/src/media/video/video_mixer.cpp
+++ b/src/media/video/video_mixer.cpp
@@ -309,8 +309,14 @@ VideoMixer::process()
             if (currentLayout_ != Layout::ONE_BIG or active) {
                 sourcesInfo.emplace_back(SourceInfo {{}, 0, 0, 10, 10, false, callId, streamId});
             }
-            if (currentLayout_ == Layout::ONE_BIG and active)
-                successfullyRendered = true;
+            if (currentLayout_ == Layout::ONE_BIG) {
+                if (active)
+                    successfullyRendered = true;
+                else
+                    sourcesInfo.emplace_back(SourceInfo {{}, 0, 0, 0, 0, false, callId, streamId});
+                // Add all participants info even in ONE_BIG layout.
+                // The width and height set to 0 here will led the peer to filter them out.
+            }
         }
         // add video sources
         for (auto& x : sources_) {
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index e8857761c94ce21b4023ea41bb50d61d1ae05a6f..2d22667b51c66b53d18ea4c1e84a8d205bbbc14e 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -28,6 +28,7 @@
 #include "sip/sipaccount.h"
 #include "sip/sipaccountbase.h"
 #include "sip/sipvoiplink.h"
+#include "jamidht/jamiaccount.h"
 #include "logger.h"
 #include "sdp.h"
 #include "manager.h"
@@ -3097,6 +3098,45 @@ SIPCall::exitConference()
     conf_.reset();
 }
 
+void
+SIPCall::setActiveMediaStream(const std::string& accountUri,
+    const std::string& deviceId,
+    const std::string& streamId,
+    const bool& state)
+{
+    auto remoteStreamId = streamId;
+#ifdef ENABLE_VIDEO
+    {
+        std::lock_guard<std::mutex> lk(sinksMtx_);
+        const auto& localIt = local2RemoteSinks_.find(streamId);
+        if (localIt != local2RemoteSinks_.end()) {
+            remoteStreamId = localIt->second;
+        }
+    }
+#endif
+
+    if (Call::conferenceProtocolVersion() == 1) {
+        Json::Value sinkVal;
+        sinkVal["active"] = state;
+        Json::Value mediasObj;
+        mediasObj[remoteStreamId] = sinkVal;
+        Json::Value deviceVal;
+        deviceVal["medias"] = mediasObj;
+        Json::Value deviceObj;
+        deviceObj[deviceId] = deviceVal;
+        Json::Value accountVal;
+        deviceVal["devices"] = deviceObj;
+        Json::Value root;
+        root[accountUri] = deviceVal;
+        root["version"] = 1;
+        Call::sendConfOrder(root);
+    } else if (Call::conferenceProtocolVersion() == 0) {
+        Json::Value root;
+        root["activeParticipant"] = accountUri;
+        Call::sendConfOrder(root);
+    }
+}
+
 #ifdef ENABLE_VIDEO
 void
 SIPCall::setRotation(int streamIdx, int rotation)
@@ -3115,18 +3155,46 @@ SIPCall::setRotation(int streamIdx, int rotation)
 }
 
 void
-SIPCall::createSinks(const ConfInfo& infos)
+SIPCall::createSinks(ConfInfo& infos)
 {
+    std::lock_guard<std::mutex> lk(sinksMtx_);
     if (!hasVideo())
         return;
 
-    std::lock_guard<std::mutex> lk(sinksMtx_);
+    for (auto& participant : infos) {
+        if (string_remove_suffix(participant.uri, '@') == account_.lock()->getUsername()
+            && participant.device
+                == std::dynamic_pointer_cast<JamiAccount>(account_.lock())->currentDeviceId()) {
+            for (auto iter = rtpStreams_.begin(); iter != rtpStreams_.end(); iter++) {
+                if (!iter->mediaAttribute_ || iter->mediaAttribute_->type_ == MediaType::MEDIA_AUDIO) {
+                    continue;
+                }
+                auto localVideo = std::static_pointer_cast<video::VideoRtpSession>(iter->rtpSession_)
+                                    ->getVideoLocal().get();
+                auto size = std::make_pair(10, 10);
+                if (localVideo) {
+                    size = std::make_pair(localVideo->getWidth(), localVideo->getHeight());
+                }
+                const auto& mediaAttribute = iter->mediaAttribute_;
+                if (participant.sinkId.find(mediaAttribute->label_) != std::string::npos) {
+                    local2RemoteSinks_[mediaAttribute->sourceUri_] = participant.sinkId;
+                    participant.sinkId = mediaAttribute->sourceUri_;
+                    participant.videoMuted = mediaAttribute->muted_;
+                    participant.w = size.first;
+                    participant.h = size.second;
+                    participant.x = 0;
+                    participant.y = 0;
+                }
+            }
+        }
+    }
+
     std::vector<std::shared_ptr<video::VideoFrameActiveWriter>> sinks;
     for (const auto& videoRtp : getRtpSessionList(MediaType::MEDIA_VIDEO)) {
         auto& videoReceive = std::static_pointer_cast<video::VideoRtpSession>(videoRtp)
                                  ->getVideoReceive();
         if (!videoReceive)
-            return;
+            continue;
         sinks.emplace_back(
             std::static_pointer_cast<video::VideoFrameActiveWriter>(videoReceive->getSink()));
     }
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index 96df0f04c9cb4636e44ed5894ad455466263c390..663b7c7b7935c5abca39ee0bb4094b04212054f0 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -150,8 +150,9 @@ public:
     void exitConference() override;
 #ifdef ENABLE_VIDEO
     std::mutex sinksMtx_;
-    void createSinks(const ConfInfo& infos) override;
+    void createSinks(ConfInfo& infos) override;
     std::map<std::string, std::shared_ptr<video::SinkClient>> callSinksMap_ {};
+    std::map<std::string, std::string> local2RemoteSinks_ {};
 #endif
     bool hasVideo() const override;
 
@@ -287,6 +288,10 @@ public:
     std::vector<std::shared_ptr<RtpSession>> getRtpSessionList(
         MediaType type = MediaType::MEDIA_ALL) const;
     static size_t getActiveMediaStreamCount(const std::vector<MediaAttribute>& mediaAttrList);
+    void setActiveMediaStream(const std::string& accountUri,
+                              const std::string& deviceId,
+                              const std::string& streamId,
+                              const bool& state);
 
     void setPeerRegisteredName(const std::string& name)
     {