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);