diff --git a/src/call.h b/src/call.h
index e54632a070998ea487c7e41dbe1f2abd11effb8d..f3374befc8d1d96d6304489748ba9ae57711d16a 100644
--- a/src/call.h
+++ b/src/call.h
@@ -346,7 +346,8 @@ public: // media management
 
     virtual void enterConference(const std::string& confId) = 0;
     virtual void exitConference() = 0;
-    virtual video::VideoGenerator* getVideoReceiver() = 0;
+    virtual std::shared_ptr<Observable<std::shared_ptr<MediaFrame>>>
+    getReceiveVideoFrameActiveWriter() = 0;
 
     std::vector<std::map<std::string, std::string>> getConferenceInfos() const
     {
@@ -401,7 +402,6 @@ protected:
     time_point duration_start_ {time_point::min()};
 
 private:
-
     bool validStateTransition(CallState newState);
 
     void checkPendingIM();
diff --git a/src/conference.cpp b/src/conference.cpp
index 03640959415507f84b93d0e7a497d580afeef406..c2b283a686016c5a0648946eebdbb9e35c49c61c 100644
--- a/src/conference.cpp
+++ b/src/conference.cpp
@@ -316,8 +316,7 @@ Conference::setActiveParticipant(const std::string& participant_id)
         return;
     }
     if (auto call = getCallFromPeerID(participant_id)) {
-        auto videoRecv = reinterpret_cast<Observable<std::shared_ptr<MediaFrame>>*>(
-            call->getVideoReceiver());
+        auto videoRecv = call->getReceiveVideoFrameActiveWriter().get();
         videoMixer_->setActiveParticipant(videoRecv);
         return;
     }
@@ -388,12 +387,12 @@ Conference::sendConferenceInfos()
             if (!account)
                 continue;
 
-            dht::ThreadPool::io().run([call,
-                                       confInfo = getConfInfoHostUri(account->getUsername()
-                                                                         + "@ring.dht",
-                                                                     call->getPeerNumber())] {
-                call->sendConfInfo(confInfo.toString());
-            });
+            dht::ThreadPool::io().run(
+                [call,
+                 confInfo = getConfInfoHostUri(account->getUsername() + "@ring.dht",
+                                               call->getPeerNumber())] {
+                    call->sendConfInfo(confInfo.toString());
+                });
         }
     }
 
@@ -675,7 +674,9 @@ Conference::onConfOrder(const std::string& callId, const std::string& confOrder)
     if (auto call = Manager::instance().getCallFromCallID(callId)) {
         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());
+            JAMI_WARN("Received conference order from a non master (%.*s)",
+                      (int) peerID.size(),
+                      peerID.data());
             return;
         }
 
@@ -684,7 +685,9 @@ 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", (int) peerID.size(), peerID.data());
+            JAMI_WARN("Couldn't parse conference order from %.*s",
+                      (int) peerID.size(),
+                      peerID.data());
             return;
         }
         if (root.isMember("layout")) {
@@ -981,8 +984,8 @@ Conference::resizeRemoteParticipants(ConfInfo& confInfo, std::string_view peerUR
     int remoteFrameWidth = confInfo.w;
 
     if (remoteFrameHeight == 0 or remoteFrameWidth == 0) {
-    // get the size of the remote frame from receiveThread
-    // if the one from confInfo is empty
+        // get the size of the remote frame from receiveThread
+        // if the one from confInfo is empty
         if (auto call = std::dynamic_pointer_cast<SIPCall>(
                 getCallFromPeerID(string_remove_suffix(peerURI, '@')))) {
             if (auto const& videoRtp = call->getVideoRtp()) {
diff --git a/src/media/media_attribute.h b/src/media/media_attribute.h
index a6262a6ceb97083b50ce994b400a5b14d2a1816b..8ec8173c44385ddb4cb1ec5dbfe0e2722bf47721 100644
--- a/src/media/media_attribute.h
+++ b/src/media/media_attribute.h
@@ -34,7 +34,7 @@ public:
     MediaAttribute(MediaType type = MediaType::MEDIA_NONE,
                    bool muted = false,
                    bool secure = true,
-                   bool enabled = true,
+                   bool enabled = false,
                    std::string_view source = {},
                    std::string_view label = {})
         : type_(type)
@@ -80,7 +80,7 @@ public:
     MediaType type_ {MediaType::MEDIA_NONE};
     bool muted_ {false};
     bool secure_ {true};
-    bool enabled_ {true};
+    bool enabled_ {false};
     std::string sourceUri_ {};
     std::string label_ {};
 };
diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp
index 94976c7cb7bffea65d500802601912582b9d02cd..d7a8cd17ff5018f96549426553ed92906ba7710d 100644
--- a/src/media/video/video_rtp_session.cpp
+++ b/src/media/video/video_rtp_session.cpp
@@ -397,6 +397,8 @@ VideoRtpSession::exitConference()
         if (receiveThread_) {
             conference_->detachVideo(receiveThread_.get());
             receiveThread_->exitConference();
+        } else {
+            conference_->detachVideo(dummyVideoReceive_.get());
         }
 
         videoMixer_.reset();
diff --git a/src/media/video/video_rtp_session.h b/src/media/video/video_rtp_session.h
index 0243a0927c8ea070e305410ea3adf4c1dc38b06f..80ac4a98571094c492a451b9a2da28ee3246e6c5 100644
--- a/src/media/video/video_rtp_session.h
+++ b/src/media/video/video_rtp_session.h
@@ -104,7 +104,15 @@ public:
 
     std::shared_ptr<VideoMixer>& getVideoMixer() { return videoMixer_; }
 
-    std::unique_ptr<VideoReceiveThread>& getVideoReceive() { return receiveThread_; }
+    std::shared_ptr<VideoReceiveThread>& getVideoReceive() { return receiveThread_; }
+
+    std::shared_ptr<VideoFrameActiveWriter> getReceiveVideoFrameActiveWriter()
+    {
+        if (isReceiving() && receiveThread_)
+            return std::static_pointer_cast<VideoFrameActiveWriter>(receiveThread_);
+        else
+            return dummyVideoReceive_;
+    }
 
 private:
     void setupConferenceVideoPipeline(Conference& conference);
@@ -117,7 +125,9 @@ private:
     DeviceParams localVideoParams_;
 
     std::unique_ptr<VideoSender> sender_;
-    std::unique_ptr<VideoReceiveThread> receiveThread_;
+    std::shared_ptr<VideoReceiveThread> receiveThread_;
+    std::shared_ptr<VideoFrameActiveWriter> dummyVideoReceive_
+        = std::make_shared<VideoFrameActiveWriter>();
     Conference* conference_ {nullptr};
     std::shared_ptr<VideoMixer> videoMixer_;
     std::shared_ptr<VideoFrameActiveWriter> videoLocal_;
diff --git a/src/sip/sipaccountbase.cpp b/src/sip/sipaccountbase.cpp
index 93930760329291e8b7a17a51b9aec7f4af5164f9..c3374d1f4f85b5b1adf11204631c868ad7695bfd 100644
--- a/src/sip/sipaccountbase.cpp
+++ b/src/sip/sipaccountbase.cpp
@@ -138,10 +138,12 @@ std::string
 getDisplayed(const std::string& messageId)
 {
     // implementing https://tools.ietf.org/rfc/rfc5438.txt
-    return fmt::format("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
-                       "<imdn><message-id>{}</message-id>\n"
-                       "<display-notification><status><displayed/></status></display-notification>\n"
-                       "</imdn>", messageId);
+    return fmt::format(
+        "<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
+        "<imdn><message-id>{}</message-id>\n"
+        "<display-notification><status><displayed/></status></display-notification>\n"
+        "</imdn>",
+        messageId);
 }
 
 void
@@ -684,13 +686,13 @@ SIPAccountBase::createDefaultMediaList(bool addVideo, bool onHold)
 
     // Add audio and DTMF events
     mediaList.emplace_back(
-        MediaAttribute(MediaType::MEDIA_AUDIO, onHold, secure, true, "", "main audio"));
+        MediaAttribute(MediaType::MEDIA_AUDIO, onHold, secure, false, "", "main audio"));
 
 #ifdef ENABLE_VIDEO
     // Add video if allowed.
     if (isVideoEnabled() and addVideo) {
         mediaList.emplace_back(
-            MediaAttribute(MediaType::MEDIA_VIDEO, onHold, secure, true, "", "main video"));
+            MediaAttribute(MediaType::MEDIA_VIDEO, onHold, secure, false, "", "main video"));
     }
 #endif
     return mediaList;
diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp
index 1f4c420c369455c3c4d3eacd59002ffed663ed51..b7a18b90c38d79265dedcd7ee1be246549d7f6c0 100644
--- a/src/sip/sipcall.cpp
+++ b/src/sip/sipcall.cpp
@@ -1412,6 +1412,7 @@ SIPCall::startAllMedia()
     // reset
     readyToRecord_ = false;
     resetMediaReady();
+    bool isVideoEnabled = false;
 
     for (const auto& slot : slots) {
         ++slotN;
@@ -1453,6 +1454,9 @@ SIPCall::startAllMedia()
         }
 
         // Configure the media.
+        rtpStream.mediaAttribute_->enabled_ = true;
+        if (rtpStream.mediaAttribute_->type_ == MEDIA_VIDEO)
+            isVideoEnabled = true;
         configureRtpSession(rtpStream.rtpSession_, rtpStream.mediaAttribute_, local, remote);
 
         // Not restarting media loop on hold as it's a huge waste of CPU ressources
@@ -1487,6 +1491,11 @@ SIPCall::startAllMedia()
 
     // Video is muted if all video streams are muted.
     isVideoMuted_ = iter == rtpStreams_.end();
+
+    if (!isVideoEnabled && !getConfId().empty()) {
+        auto conference = Manager::instance().getConferenceFromID(getConfId());
+        conference->attachVideo(getReceiveVideoFrameActiveWriter().get(), getCallId());
+    }
 #endif
 
     // Media is restarted, we can process the last holding request.
diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h
index 5dc0de5e06d30c21fcbd3030a2c84d93d599a91d..81ea04ee80daef89742b689f024d341f06ddd60c 100644
--- a/src/sip/sipcall.h
+++ b/src/sip/sipcall.h
@@ -148,11 +148,12 @@ public:
     std::map<std::string, std::string> getDetails() const override;
     void enterConference(const std::string& confId) override;
     void exitConference() override;
-    video::VideoGenerator* getVideoReceiver() override
+    std::shared_ptr<Observable<std::shared_ptr<MediaFrame>>> getReceiveVideoFrameActiveWriter()
+        override
     {
         auto const& videoRtp = getVideoRtp();
         if (videoRtp)
-            return videoRtp->getVideoReceive().get();
+            return videoRtp->getReceiveVideoFrameActiveWriter();
 
         return nullptr;
     }