conference: vectorize host attributes

In the previous version of the code, the conference was only
supporting 2 video inputs and one audio source.
For multistream, this is not correct and should be as generic as
possible.

https://git.jami.net/savoirfairelinux/jami-project/-/issues/1429

Change-Id: I7f7f7a2547209844a15f734bea3a62d92e456fde
This commit is contained in:
Sébastien Blin
2022-05-23 05:20:19 -04:00
parent f0b9497825
commit 31b858c36b
2 changed files with 88 additions and 90 deletions

View File

@ -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;
if (videoMixer_)
videoMixer_->stopInputs();
std::vector<std::string> newVideoInputs;
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 (mediaSource.muted_ != mediaAttr.muted_) {
// 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);

View File

@ -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};