diff --git a/src/conference.cpp b/src/conference.cpp index ec0e2569cf62c24e5a40b7fd7663f0091bd7378b..68f8b02fda2b35d790fe47e40c3944e00d41ab30 100644 --- a/src/conference.cpp +++ b/src/conference.cpp @@ -87,11 +87,14 @@ Conference::Conference(const std::shared_ptr<Account>& account) setLocalHostDefaultMediaSource(); #ifdef ENABLE_VIDEO + auto itVideo = std::find_if(hostSources_.begin(), hostSources_.end(), [&](auto attr) { + return attr.type_ == MediaType::MEDIA_VIDEO; + }); // We are done if the video is disabled. - if (not videoEnabled_) + if (not videoEnabled_ || itVideo == hostSources_.end()) return; - videoMixer_ = std::make_shared<video::VideoMixer>(id_, hostVideoSource_.sourceUri_); + videoMixer_ = std::make_shared<video::VideoMixer>(id_, itVideo->sourceUri_); videoMixer_->setOnSourcesUpdated([this](std::vector<video::SourceInfo>&& infos) { runOnMainThread([w = weak(), infos = std::move(infos)] { auto shared = w.lock(); @@ -306,36 +309,37 @@ Conference::setState(State state) void Conference::setLocalHostDefaultMediaSource() { + hostSources_.clear(); // Setup local audio source + MediaAttribute audioAttr; if (confState_ == State::ACTIVE_ATTACHED) { - hostAudioSource_ = {MediaType::MEDIA_AUDIO, false, false, true, {}, "audio_0"}; - hostAudioSource_.sourceType_ = MediaSourceType::CAPTURE_DEVICE; - } else { - hostAudioSource_ = {}; + audioAttr = {MediaType::MEDIA_AUDIO, false, false, true, {}, "audio_0"}; + audioAttr.sourceType_ = MediaSourceType::CAPTURE_DEVICE; } JAMI_DBG("[conf %s] Setting local host audio source to [%s]", id_.c_str(), - hostAudioSource_.toString().c_str()); + audioAttr.toString().c_str()); + hostSources_.emplace_back(audioAttr); #ifdef ENABLE_VIDEO if (isVideoEnabled()) { + MediaAttribute videoAttr; // Setup local video source if (confState_ == State::ACTIVE_ATTACHED) { - hostVideoSource_ + videoAttr = {MediaType::MEDIA_VIDEO, false, false, true, Manager::instance().getVideoManager().videoDeviceMonitor.getMRLForDefaultDevice(), "video_0"}; - hostVideoSource_.sourceType_ = MediaSourceType::CAPTURE_DEVICE; - } else { - hostVideoSource_ = {}; + videoAttr.sourceType_ = MediaSourceType::CAPTURE_DEVICE; } JAMI_DBG("[conf %s] Setting local host video source to [%s]", id_.c_str(), - hostVideoSource_.toString().c_str()); + videoAttr.toString().c_str()); + hostSources_.emplace_back(videoAttr); } #endif } @@ -407,15 +411,9 @@ Conference::createConfAVStream(const StreamData& StreamData, void Conference::setLocalHostMuteState(MediaType type, bool muted) { - if (type == MediaType::MEDIA_AUDIO) { - hostAudioSource_.muted_ = muted; -#ifdef ENABLE_VIDEO - } else if (type == MediaType::MEDIA_VIDEO) { - hostVideoSource_.muted_ = muted; -#endif - } else { - JAMI_ERR("Unsupported media type"); - } + for (auto& source : hostSources_) + if (source.type_ == type) + source.muted_ = muted; } bool @@ -431,19 +429,17 @@ Conference::isMediaSourceMuted(MediaType type) const return true; } -#ifdef ENABLE_VIDEO - auto const& mediaAttr = type == MediaType::MEDIA_AUDIO ? hostAudioSource_ : hostVideoSource_; -#else - auto const& mediaAttr = hostAudioSource_; -#endif - if (mediaAttr.type_ == MediaType::MEDIA_NONE) { - JAMI_WARN("The host source for %s is not set. The mute state is meaningless", - mediaAttr.mediaTypeToString(mediaAttr.type_)); - // Assume muted if the media is not present. - return true; + for (const auto& source : hostSources_) { + if (source.muted_) + return true; + if (source.type_ == MediaType::MEDIA_NONE) { + JAMI_WARN("The host source for %s is not set. The mute state is meaningless", + source.mediaTypeToString(source.type_)); + // Assume muted if the media is not present. + return true; + } } - - return mediaAttr.muted_; + return false; } void @@ -538,48 +534,35 @@ Conference::requestMediaChange(const std::vector<DRing::MediaMap>& mediaList) mediaAttr.toString(true).c_str()); } - uint32_t videoIdx = 0; - for (auto const& mediaAttr : mediaAttrList) { -#ifdef ENABLE_VIDEO - auto& mediaSource = mediaAttr.type_ == MediaType::MEDIA_AUDIO ? hostAudioSource_ - : hostVideoSource_; -#else - auto& mediaSource = hostAudioSource_; -#endif - if (not mediaAttr.sourceUri_.empty() and mediaSource.sourceUri_ != mediaAttr.sourceUri_) { - // For now, only video source URI can be changed by the client, - // so it's an error if we get here and the type is not video. - if (mediaAttr.type_ != MediaType::MEDIA_VIDEO) { - JAMI_ERR("[conf %s] Media source can be changed only for video!", - getConfId().c_str()); - return false; - } - - mediaSource.sourceUri_ = mediaAttr.sourceUri_; - mediaSource.sourceType_ = mediaAttr.sourceType_; + if (videoMixer_) + videoMixer_->stopInputs(); - if (mediaSource.muted_ != mediaAttr.muted_) { + std::vector<std::string> newVideoInputs; + for (auto const& mediaAttr : mediaAttrList) { + // Find media + auto oldIdx = std::find_if(hostSources_.begin(), hostSources_.end(), [&](auto oldAttr) { + return oldAttr.sourceUri_ == mediaAttr.sourceUri_; + }); + // If video, add to newVideoInputs + // NOTE: For now, only supports video + if (mediaAttr.type_ == MediaType::MEDIA_VIDEO) + newVideoInputs.emplace_back(mediaAttr.sourceUri_); + if (oldIdx != hostSources_.end()) { + // Check if muted status changes + if (mediaAttr.muted_ != oldIdx->muted_) { // If the current media source is muted, just call un-mute, it // will set the new source as input. muteLocalHost(mediaAttr.muted_, mediaAttr.type_ == MediaType::MEDIA_AUDIO ? DRing::Media::Details::MEDIA_TYPE_AUDIO : DRing::Media::Details::MEDIA_TYPE_VIDEO); - } else { - videoMixer_->switchInput(mediaAttr.sourceUri_, videoIdx); } - videoIdx++; - } - - // Update the mute state if changed. - if (mediaSource.muted_ != mediaAttr.muted_) { - muteLocalHost(mediaAttr.muted_, - mediaAttr.type_ == MediaType::MEDIA_AUDIO - ? DRing::Media::Details::MEDIA_TYPE_AUDIO - : DRing::Media::Details::MEDIA_TYPE_VIDEO); } } + if (videoMixer_) + videoMixer_->switchInputs(newVideoInputs); + hostSources_ = mediaAttrList; // New medias return true; } @@ -893,9 +876,11 @@ Conference::attachLocalParticipant() #ifdef ENABLE_VIDEO if (videoMixer_) { - std::vector<std::string> videoInputs = {hostVideoSource_.sourceUri_}; - if (not mediaSecondaryInput_.empty()) - videoInputs.emplace_back(mediaSecondaryInput_); + std::vector<std::string> videoInputs; + for (const auto& source : hostSources_) { + if (source.type_ == MediaType::MEDIA_VIDEO) + videoInputs.emplace_back(source.sourceUri_); + } videoMixer_->switchInputs(videoInputs); } #endif @@ -918,16 +903,11 @@ Conference::detachLocalParticipant() RingBufferPool::DEFAULT_ID); }); - // Reset local audio source - hostAudioSource_ = {}; - #ifdef ENABLE_VIDEO if (videoMixer_) videoMixer_->stopInputs(); - - // Reset local video source - hostVideoSource_ = {}; #endif + hostSources_.clear(); setState(State::ACTIVE_DETACHED); } else { JAMI_WARN( @@ -1036,8 +1016,21 @@ Conference::switchInput(const std::string& input) { #ifdef ENABLE_VIDEO JAMI_DBG("[Conf:%s] Setting video input to %s", id_.c_str(), input.c_str()); - - hostVideoSource_.sourceUri_ = input; + std::vector<MediaAttribute> newSources; + auto firstVideo = true; + // Rewrite hostSources (remove all except one video input) + // This method is replaced by requestMediaChange + for (auto& source : hostSources_) { + if (source.type_ == MediaType::MEDIA_VIDEO) { + if (firstVideo) { + firstVideo = false; + source.sourceUri_ = input; + newSources.emplace_back(source); + } + } else { + newSources.emplace_back(source); + } + } // Done if the video is disabled if (not isVideoEnabled()) @@ -1075,6 +1068,16 @@ Conference::getVideoMixer() { return videoMixer_; } + +std::string +Conference::getVideoInput() const +{ + for (const auto& source : hostSources_) { + if (source.type_ == MediaType::MEDIA_VIDEO) + return source.sourceUri_; + } + return {}; +} #endif void @@ -1502,8 +1505,13 @@ Conference::muteLocalHost(bool is_muted, const std::string& mediaType) } } else { if (auto mixer = videoMixer_) { - JAMI_DBG("Un-muting local video source"); - mixer->switchInputs({hostVideoSource_.sourceUri_}); + JAMI_DBG("Un-muting local video sources"); + std::vector<std::string> videoInputs; + for (const auto& source : hostSources_) { + if (source.type_ == MediaType::MEDIA_VIDEO) + videoInputs.emplace_back(source.sourceUri_); + } + mixer->switchInputs(videoInputs); } } emitSignal<DRing::CallSignal::VideoMuted>(id_, is_muted); diff --git a/src/conference.h b/src/conference.h index 2d695a8156004a893d1301088b4adcecd294b55e..5f8b915111f0e83fc2fd5ff3977700b4089ff649 100644 --- a/src/conference.h +++ b/src/conference.h @@ -334,7 +334,7 @@ public: #ifdef ENABLE_VIDEO void createSinks(const ConfInfo& infos); std::shared_ptr<video::VideoMixer> getVideoMixer(); - std::string getVideoInput() const { return hostVideoSource_.sourceUri_; } + std::string getVideoInput() const; #endif std::vector<std::map<std::string, std::string>> getConferenceInfos() const @@ -400,7 +400,6 @@ private: #ifdef ENABLE_VIDEO bool videoEnabled_; - std::string mediaSecondaryInput_ {}; std::shared_ptr<video::VideoMixer> videoMixer_; std::map<std::string, std::shared_ptr<video::SinkClient>> confSinksMap_ {}; #endif @@ -421,19 +420,10 @@ private: /** * If the local host is participating in the conference (attached - * mode ), these two variables will hold the media source states + * mode ), this variable will hold the media source states * of the local host. - * - * NOTE: - * Currently, the conference and the client support only one stream - * per media type, even if the call supports an arbitrary number of - * streams per media type. Thus, these two variables will hold the - * current media source attributes */ - MediaAttribute hostAudioSource_ {}; -#ifdef ENABLE_VIDEO - MediaAttribute hostVideoSource_ {}; -#endif + std::vector<MediaAttribute> hostSources_; bool localModAdded_ {false};