diff --git a/src/api/call.h b/src/api/call.h
index 922449ce8d0228f1d6901025c2c6061e535c801c..4dc5959b2ac7dc4ca44a6c1cf2f7524f030177a7 100644
--- a/src/api/call.h
+++ b/src/api/call.h
@@ -134,7 +134,7 @@ struct Info
     QString peerUri;
     bool isOutgoing;
     bool audioMuted = false;
-    bool videoMuted = false;
+    bool videoMuted = true;
     bool isAudioOnly = false;
     Layout layout = Layout::GRID;
     VectorMapStringString participantsInfos = {};
diff --git a/src/api/newcallmodel.h b/src/api/newcallmodel.h
index 6c334f81f2fb101bd933c4abff638c5a818385ae..4fda31db8cd986077f5e482d3f248d75d69edefe 100644
--- a/src/api/newcallmodel.h
+++ b/src/api/newcallmodel.h
@@ -84,9 +84,9 @@ public:
     /**
      * Request a media change in a ongoing call.
      * @param  callId
-     * @param  mediaList new media list for call
+     * @param  mediaLabel label of media to be changed
      */
-    void requestMediaChange(const QString& callId, bool activateVideo);
+    void requestMediaChange(const QString& callId, const QString& mediaLabel);
 
     /**
      * Get the call from its call id
@@ -165,6 +165,7 @@ public:
     void togglePause(const QString& callId) const;
 
     /**
+     * @deprecated Use requestMediaChange instead
      * Toggle a media on a call
      * @param callId
      * @param media {AUDIO, VIDEO}
diff --git a/src/callbackshandler.cpp b/src/callbackshandler.cpp
index 60e49c953309afe1d27e48b8d64844ca5c28244a..374be8561794a2644cefe1fc248ffbeedc8b2c95 100644
--- a/src/callbackshandler.cpp
+++ b/src/callbackshandler.cpp
@@ -138,6 +138,12 @@ CallbacksHandler::CallbacksHandler(const Lrc& parent)
             &CallbacksHandler::slotCallStateChanged,
             Qt::QueuedConnection);
 
+    connect(&CallManager::instance(),
+            &CallManagerInterface::mediaNegotiationStatus,
+            this,
+            &CallbacksHandler::slotMediaNegotiationStatus,
+            Qt::QueuedConnection);
+
     connect(&CallManager::instance(),
             &CallManagerInterface::conferenceCreated,
             this,
@@ -387,6 +393,14 @@ CallbacksHandler::slotCallStateChanged(const QString& callId, const QString& sta
     emit callStateChanged(callId, state, code);
 }
 
+void
+CallbacksHandler::slotMediaNegotiationStatus(const QString& callId,
+                                             const QString& event,
+                                             const VectorMapStringString& mediaList)
+{
+    emit mediaNegotiationStatus(callId, event, mediaList);
+}
+
 void
 CallbacksHandler::slotAccountDetailsChanged(const QString& accountId, const MapStringString& details)
 {
diff --git a/src/callbackshandler.h b/src/callbackshandler.h
index 4e617223e8b91a44f8d3b59ea1817b6980bb3726..8e16e64d3e55a3ae4aed11da2bd2f12774c7bc1d 100644
--- a/src/callbackshandler.h
+++ b/src/callbackshandler.h
@@ -128,6 +128,15 @@ Q_SIGNALS:
      * @param code
      */
     void callStateChanged(const QString& callId, const QString& state, int code);
+    /**
+     * Connect this signal to know when a call medias are available
+     * @param callId the call id
+     * @param event
+     * @param mediaList new mediaList for the call
+     */
+    void mediaNegotiationStatus(const QString& callId,
+                                const QString& event,
+                                const VectorMapStringString& mediaList);
     /**
      * Connect this signal to know when the account details have changed
      * @param accountId the one who changes
@@ -405,14 +414,14 @@ private Q_SLOTS:
      * Get the URI of the peer and emit incomingCall
      * @param accountId account linked
      * @param callId the incoming call id
-     * @param fromQString the uri of the peer
+     * @param fromUri the uri of the peer
      */
     void slotIncomingCall(const QString& accountId, const QString& callId, const QString& fromUri);
     /**
      * Get the URI of the peer and emit incomingCallWithMedia
      * @param accountId account linked
      * @param callId the incoming call id
-     * @param fromQString the uri of the peer
+     * @param fromUri the uri of the peer
      * @param mediaList the mediaList received
      */
     void slotIncomingCallWithMedia(const QString& accountId,
@@ -423,7 +432,6 @@ private Q_SLOTS:
      * Get the URI of the peer and emit mediaChangeRequested
      * @param accountId account linked
      * @param callId the incoming call id
-     * @param fromQString the uri of the peer
      * @param mediaList the mediaList received
      */
     void slotMediaChangeRequested(const QString& accountId,
@@ -436,6 +444,15 @@ private Q_SLOTS:
      * @param code unused for now
      */
     void slotCallStateChanged(const QString& callId, const QString& state, int code);
+    /**
+     * Emit mediaNegotiationStatus
+     * @param callId the call which changes.
+     * @param eventstate the new state
+     * @param mediaList new mediaList for the call
+     */
+    void slotMediaNegotiationStatus(const QString& callId,
+                                    const QString& event,
+                                    const VectorMapStringString& mediaList);
     /**
      * Parse a call message and emit incomingVCardChunk if it's a VCard chunk
      * else incomingCallMessage if it's a text message
diff --git a/src/newcallmodel.cpp b/src/newcallmodel.cpp
index ef3f9a9468b4389650328b76b29ab14ab668246d..21338964839adb890a9d0b33ef120c5f1a47656c 100644
--- a/src/newcallmodel.cpp
+++ b/src/newcallmodel.cpp
@@ -180,6 +180,15 @@ public Q_SLOTS:
      * @param code unused
      */
     void slotCallStateChanged(const QString& callId, const QString& state, int code);
+    /**
+     * Listen from CallbacksHandler when a call medias are ready
+     * @param callId
+     * @param event
+     * @param mediaList
+     */
+    void slotMediaNegotiationStatus(const QString& callId,
+                                    const QString& event,
+                                    const VectorMapStringString& mediaList);
     /**
      * Listen from CallbacksHandler when a VCard chunk is incoming
      * @param callId
@@ -328,6 +337,7 @@ NewCallModel::createCall(const QString& uri, bool isAudioOnly)
     callInfo->status = call::Status::SEARCHING;
     callInfo->type = call::Type::DIALOG;
     callInfo->isAudioOnly = isAudioOnly;
+    callInfo->videoMuted = isAudioOnly;
     callInfo->mediaList = mediaList;
     pimpl_->calls.emplace(callId, std::move(callInfo));
 
@@ -335,35 +345,46 @@ NewCallModel::createCall(const QString& uri, bool isAudioOnly)
 }
 
 void
-NewCallModel::requestMediaChange(const QString& callId, bool activateVideo)
+NewCallModel::requestMediaChange(const QString& callId, const QString& mediaLabel)
 {
+    // Main audio: audio_0
+    // Main video: video_0
+
     auto& callInfo = pimpl_->calls[callId];
     if (!callInfo)
         return;
 
     auto proposedList = callInfo->mediaList;
 
-    bool found {false};
+    int found = 0;
     for (auto& item : proposedList) {
-        if (item["MEDIA_TYPE"] == "MEDIA_TYPE_VIDEO") {
-            item["ENABLED"] = activateVideo ? "true" : "false";
-            item["MUTED"] = activateVideo ? "false" : "true";
-            found = true;
+        if (item["LABEL"] == mediaLabel) {
+            item["ENABLED"] = "true";
+            item["MUTED"] = item["MUTED"] == "true" ? "false" : "true";
+            break;
         }
+        found++;
     }
-    if (!found && activateVideo) {
+    if (found == proposedList.size() && mediaLabel == "video_0") {
         MapStringString mediaAttribute = {{"MEDIA_TYPE", "MEDIA_TYPE_VIDEO"},
                                           {"ENABLED", "true"},
                                           {"MUTED", "false"},
                                           {"SOURCE", ""},
                                           {"LABEL", "video_0"}};
         proposedList.push_back(mediaAttribute);
+        // We should prepare it here for adding file and screen sharing
+        // for now it supports only adding main video to an audio only call
     }
-    if (CallManager::instance().requestMediaChange(callId, proposedList)) {
-        callInfo->isAudioOnly &= !activateVideo;
-        callInfo->videoMuted = !activateVideo;
-        callInfo->mediaList = proposedList;
-        emit callInfosChanged(owner.id, callId);
+    CallManager::instance().requestMediaChange(callId, proposedList);
+    // If media existed and its mute state was changed here, then we should
+    // update the mediaList because we will not receive signal
+    // mediaNegotiationStatus
+    if (found < callInfo->mediaList.size()) {
+        callInfo->mediaList[found]["MUTED"] = callInfo->mediaList[found]["MUTED"] == "true"
+                                                  ? "false"
+                                                  : "true";
+        if (callInfo->status == call::Status::IN_PROGRESS)
+            emit callInfosChanged(owner.id, callId);
     }
 }
 
@@ -461,30 +482,8 @@ NewCallModel::toggleMedia(const QString& callId, const NewCallModel::Media media
         return;
     auto& call = pimpl_->calls[callId];
 
-    if (call->isAudioOnly && media == NewCallModel::Media::VIDEO) {
-        requestMediaChange(callId, true);
-        return;
-    }
-
-    switch (media) {
-    case NewCallModel::Media::AUDIO:
-        CallManager::instance().muteLocalMedia(callId,
-                                               DRing::Media::Details::MEDIA_TYPE_AUDIO,
-                                               !call->audioMuted);
-        call->audioMuted = !call->audioMuted;
-        break;
-
-    case NewCallModel::Media::VIDEO:
-        CallManager::instance().muteLocalMedia(callId,
-                                               DRing::Media::Details::MEDIA_TYPE_VIDEO,
-                                               !call->videoMuted);
-        call->videoMuted = !call->videoMuted;
-        break;
-
-    case NewCallModel::Media::NONE:
-    default:
-        break;
-    }
+    auto mediaLabel = media == NewCallModel::Media::VIDEO ? "video_0" : "audio_0";
+    requestMediaChange(callId, mediaLabel);
 }
 
 void
@@ -668,6 +667,10 @@ NewCallModelPimpl::NewCallModelPimpl(const NewCallModel& linked,
             &CallbacksHandler::callStateChanged,
             this,
             &NewCallModelPimpl::slotCallStateChanged);
+    connect(&callbacksHandler,
+            &CallbacksHandler::mediaNegotiationStatus,
+            this,
+            &NewCallModelPimpl::slotMediaNegotiationStatus);
     connect(&callbacksHandler,
             &CallbacksHandler::incomingVCardChunk,
             this,
@@ -951,9 +954,6 @@ NewCallModelPimpl::slotIncomingCallWithMedia(const QString& accountId,
     //    return;
     //}
 
-    // do not use auto here (QDBusPendingReply<MapStringString>)
-    MapStringString callDetails = CallManager::instance().getCallDetails(callId);
-
     auto callInfo = std::make_shared<call::Info>();
     callInfo->id = callId;
     // peer uri = ring:<jami_id> or sip number
@@ -964,7 +964,13 @@ NewCallModelPimpl::slotIncomingCallWithMedia(const QString& accountId,
     callInfo->isOutgoing = false;
     callInfo->status = call::Status::INCOMING_RINGING;
     callInfo->type = call::Type::DIALOG;
-    callInfo->isAudioOnly = callDetails["AUDIO_ONLY"] == "true" ? true : false;
+    callInfo->isAudioOnly = true;
+    for (const auto& item : mediaList) {
+        if (item["MEDIA_TYPE"] == "MEDIA_TYPE_VIDEO") {
+            callInfo->isAudioOnly = false;
+            break;
+        }
+    }
     callInfo->mediaList = mediaList;
     calls.emplace(callId, std::move(callInfo));
 
@@ -980,7 +986,7 @@ NewCallModelPimpl::slotIncomingCallWithMedia(const QString& accountId,
     if (!linked.owner.confProperties.isRendezVous && linked.owner.confProperties.autoAnswer) {
         linked.accept(callId);
     }
-}
+} // namespace lrc
 
 void
 NewCallModelPimpl::slotMediaChangeRequested(const QString& accountId,
@@ -1001,15 +1007,13 @@ NewCallModelPimpl::slotMediaChangeRequested(const QString& accountId,
 
     for (auto& item : answerMedia) {
         if (item["MEDIA_TYPE"] == "MEDIA_TYPE_VIDEO") {
-            item["MUTED"] = (callInfo->isAudioOnly || callInfo->videoMuted) ? "true" : "false";
+            item["MUTED"] = callInfo->videoMuted ? "true" : "false";
             item["ENABLED"] = "true";
-            callInfo->isAudioOnly = false;
-            callInfo->videoMuted = true;
         }
     }
-    callInfo->mediaList = QVector<MapStringString>::fromList(answerMedia);
-    CallManager::instance().answerMediaChangeRequest(callId, callInfo->mediaList);
-    emit linked.callInfosChanged(linked.owner.id, callId);
+    CallManager::instance().answerMediaChangeRequest(callId,
+                                                     QVector<MapStringString>::fromList(
+                                                         answerMedia));
 }
 
 void
@@ -1085,6 +1089,38 @@ NewCallModelPimpl::slotCallStateChanged(const QString& callId, const QString& st
     }
 }
 
+void
+NewCallModelPimpl::slotMediaNegotiationStatus(const QString& callId,
+                                              const QString& event,
+                                              const VectorMapStringString& mediaList)
+{
+    if (!linked.hasCall(callId)) {
+        return;
+    }
+
+    auto& callInfo = calls[callId];
+    if (!callInfo) {
+        return;
+    }
+
+    callInfo->isAudioOnly = true;
+    for (const auto& item : mediaList) {
+        if (item["MEDIA_TYPE"] == "MEDIA_TYPE_VIDEO") {
+        	if (item["ENABLED"] == "true") {
+            	callInfo->isAudioOnly = false;
+            	callInfo->videoMuted = item["MUTED"] == "true";
+            }
+        }
+        if (item["MEDIA_TYPE"] == "MEDIA_TYPE_AUDIO") {
+            callInfo->audioMuted = item["MUTED"] == "true";
+        }
+    }
+
+    callInfo->mediaList = mediaList;
+    if (callInfo->status == call::Status::IN_PROGRESS)
+        emit linked.callInfosChanged(linked.owner.id, callId);
+}
+
 void
 NewCallModelPimpl::slotincomingVCardChunk(
     const QString& callId, const QString& from, int part, int numberOfParts, const QString& payload)
diff --git a/src/qtwrapper/callmanager_wrap.h b/src/qtwrapper/callmanager_wrap.h
index 69b1c4bb9e522bb3c78da94bfddff0b4e587c81e..84417e8c3524081826a1ea5a74d2f8f8427ecbdf 100644
--- a/src/qtwrapper/callmanager_wrap.h
+++ b/src/qtwrapper/callmanager_wrap.h
@@ -55,6 +55,18 @@ public:
                                       code);
                     Q_EMIT callStateChanged(QString(callID.c_str()), QString(state.c_str()), code);
                 }),
+            exportable_callback<CallSignal::MediaNegotiationStatus>(
+                [this](const std::string& callID,
+                       const std::string& event,
+                       const std::vector<std::map<std::string, std::string>>& mediaList) {
+                    LOG_DRING_SIGNAL3("mediaNegotiationStatus",
+                                      QString(callID.c_str()),
+                                      QString(event.c_str()),
+                                      convertVecMap(mediaList));
+                    Q_EMIT mediaNegotiationStatus(QString(callID.c_str()),
+                                                  QString(event.c_str()),
+                                                  convertVecMap(mediaList));
+                }),
             exportable_callback<CallSignal::TransferFailed>([this]() {
                 LOG_DRING_SIGNAL("transferFailed", "");
                 Q_EMIT transferFailed();
@@ -456,6 +468,9 @@ public Q_SLOTS: // METHODS
 
 Q_SIGNALS: // SIGNALS
     void callStateChanged(const QString& callID, const QString& state, int code);
+    void mediaNegotiationStatus(const QString& callID,
+                                const QString& event,
+                                const VectorMapStringString& mediaList);
     void transferFailed();
     void transferSucceeded();
     void recordPlaybackStopped(const QString& filepath);