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