From 3c85f03690f7b515ebda8be54d6611352cc95d4c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= Date: Fri, 17 Jul 2020 14:55:02 -0400 Subject: [PATCH] conference: add a rendez-vous mode This patch aims to be a first iteration on a new conference mode. Actually, creating a conference for many participants is pretty boring and the UX is bad because for any conference, we need to call any participant and add them. This new mode transform an account into a meeting account. This means whenever this account receives a call (from an authorized peer) the call is answered and added to the current conference. So, an account can easily host a meeting. Gitlab: #269 Change-Id: I5ece585f8eb46f5cf6a5f9e3dc56829949cc7a81 --- src/account.cpp | 6 +++ src/account.h | 10 +++- src/account_schema.h | 1 + src/dring/account_const.h | 1 + src/manager.cpp | 69 +++++++++++++++++++++++---- src/manager.h | 3 +- src/media/video/video_rtp_session.cpp | 13 ++--- 7 files changed, 84 insertions(+), 19 deletions(-) diff --git a/src/account.cpp b/src/account.cpp index ba9603c87..667581bdf 100644 --- a/src/account.cpp +++ b/src/account.cpp @@ -78,6 +78,7 @@ const char * const Account::PASSWORD_KEY = "password"; const char * const Account::HOSTNAME_KEY = "hostname"; const char * const Account::ACCOUNT_ENABLE_KEY = "enable"; const char * const Account::ACCOUNT_AUTOANSWER_KEY = "autoAnswer"; +const char * const Account::ACCOUNT_ISRENDEZVOUS_KEY = "rendezVous"; const char * const Account::ACCOUNT_ACTIVE_CALL_LIMIT_KEY = "activeCallLimit"; const char * const Account::MAILBOX_KEY = "mailbox"; const char * const Account::DEFAULT_USER_AGENT = PACKAGE_NAME; @@ -101,6 +102,7 @@ Account::Account(const std::string &accountID) , alias_() , enabled_(true) , autoAnswerEnabled_(false) + , isRendezVous_(false) , registrationState_(RegistrationState::UNREGISTERED) , systemCodecContainer_(getSystemCodecContainer()) , accountCodecInfoList_() @@ -227,6 +229,7 @@ Account::serialize(YAML::Emitter& out) const out << YAML::Key << ACTIVE_CODEC_KEY << YAML::Value << activeCodecs; out << YAML::Key << MAILBOX_KEY << YAML::Value << mailBox_; out << YAML::Key << ACCOUNT_AUTOANSWER_KEY << YAML::Value << autoAnswerEnabled_; + out << YAML::Key << ACCOUNT_ISRENDEZVOUS_KEY << YAML::Value << isRendezVous_; out << YAML::Key << ACCOUNT_ACTIVE_CALL_LIMIT_KEY << YAML::Value << activeCallLimit_; out << YAML::Key << RINGTONE_ENABLED_KEY << YAML::Value << ringtoneEnabled_; out << YAML::Key << RINGTONE_PATH_KEY << YAML::Value << ringtonePath_; @@ -246,6 +249,7 @@ Account::unserialize(const YAML::Node& node) parseValue(node, ALIAS_KEY, alias_); parseValue(node, ACCOUNT_ENABLE_KEY, enabled_); parseValue(node, ACCOUNT_AUTOANSWER_KEY, autoAnswerEnabled_); + parseValueOptional(node, ACCOUNT_ISRENDEZVOUS_KEY, isRendezVous_); parseValue(node, ACCOUNT_ACTIVE_CALL_LIMIT_KEY, activeCallLimit_); //parseValue(node, PASSWORD_KEY, password_); @@ -298,6 +302,7 @@ Account::setAccountDetails(const std::map &details) parseString(details, Conf::CONFIG_ACCOUNT_MAILBOX, mailBox_); parseString(details, Conf::CONFIG_ACCOUNT_USERAGENT, userAgent_); parseBool(details, Conf::CONFIG_ACCOUNT_AUTOANSWER, autoAnswerEnabled_); + parseBool(details, Conf::CONFIG_ACCOUNT_ISRENDEZVOUS, isRendezVous_); parseInt(details, DRing::Account::ConfProperties::ACTIVE_CALL_LIMIT, activeCallLimit_); parseBool(details, Conf::CONFIG_RINGTONE_ENABLED, ringtoneEnabled_); parseString(details, Conf::CONFIG_RINGTONE_PATH, ringtonePath_); @@ -328,6 +333,7 @@ Account::getAccountDetails() const {Conf::CONFIG_ACCOUNT_USERAGENT, hasCustomUserAgent_ ? userAgent_ : DEFAULT_USER_AGENT}, {Conf::CONFIG_ACCOUNT_HAS_CUSTOM_USERAGENT, hasCustomUserAgent_ ? userAgent_ : DEFAULT_USER_AGENT}, {Conf::CONFIG_ACCOUNT_AUTOANSWER, autoAnswerEnabled_ ? TRUE_STR : FALSE_STR}, + {Conf::CONFIG_ACCOUNT_ISRENDEZVOUS, isRendezVous_ ? TRUE_STR : FALSE_STR}, {DRing::Account::ConfProperties::ACTIVE_CALL_LIMIT, std::to_string(activeCallLimit_)}, {Conf::CONFIG_RINGTONE_ENABLED, ringtoneEnabled_ ? TRUE_STR : FALSE_STR}, {Conf::CONFIG_RINGTONE_PATH, ringtonePath_}, diff --git a/src/account.h b/src/account.h index 75e2cd2e7..4049e33a1 100644 --- a/src/account.h +++ b/src/account.h @@ -181,8 +181,6 @@ class Account : public Serializable, public std::enable_shared_from_this> getCalls(); - /** * Tell if the account is enable or not. * @return true if enabled, false otherwise @@ -289,6 +287,10 @@ class Account : public Serializable, public std::enable_shared_from_this using random_device = dht::crypto::random_device; @@ -535,11 +536,17 @@ Manager::ManagerPimpl::processRemainingParticipants(Conference& conf) auto p = participants.begin(); if (auto call = base_.getCallFromCallID(*p)) { call->setConfId(""); - // if we are not listening to this conference - if (current_call_id != conf.getConfID()) - base_.onHoldCall(call->getCallId()); - else - switchCall(call); + // if we are not listening to this conference and not a rendez-vous + auto isRdv = false; + if (auto acc = std::dynamic_pointer_cast(base_.getAccount(call->getAccountId()))) + isRdv = acc->getAccountDetails()[Conf::CONFIG_ACCOUNT_ISRENDEZVOUS] == TRUE_STR; + + if (!isRdv) { + if (current_call_id != conf.getConfID()) + base_.onHoldCall(call->getCallId()); + else + switchCall(call); + } } JAMI_DBG("No remaining participants, remove conference"); @@ -1344,6 +1351,10 @@ Manager::addParticipant(const std::string& callId, pimpl_->bindCallToConference(*call, *conf); + // Don't attach current user yet + if (conf->getState() == Conference::State::ACTIVE_DETACHED) + return true; + // TODO: remove this ugly hack => There should be different calls when double clicking // a conference to add main participant to it, or (in this case) adding a participant // toconference @@ -1384,7 +1395,7 @@ Manager::getCallFromCallID(const std::string& callID) const } bool -Manager::joinParticipant(const std::string& callId1, const std::string& callId2) +Manager::joinParticipant(const std::string& callId1, const std::string& callId2, bool attached) { if (callId1 == callId2) { JAMI_ERR("Cannot join participant %s to itself", callId1.c_str()); @@ -1412,8 +1423,12 @@ Manager::joinParticipant(const std::string& callId1, const std::string& callId2) pimpl_->bindCallToConference(*call2, *conf); // Switch current call id to this conference - pimpl_->switchCall(conf->getConfID()); - conf->setState(Conference::State::ACTIVE_ATTACHED); + if (attached) { + pimpl_->switchCall(conf->getConfID()); + conf->setState(Conference::State::ACTIVE_ATTACHED); + } else { + conf->detach(); + } pimpl_->conferenceMap_.emplace(conf->getConfID(), conf); emitSignal(conf->getConfID()); @@ -1836,8 +1851,42 @@ Manager::incomingCall(Call &call, const std::string& accountId) emitSignal(accountId, callID, call.getPeerDisplayName() + " " + from); auto currentCall = getCurrentCall(); - if (pimpl_->autoAnswer_) { - runOnMainThread([this, callID]{ answerCall(callID); }); + if (call.getAccount().isRendezVous()) { + runOnMainThread([this, callID] { + answerCall(callID); + auto call = getCallFromCallID(callID); + auto accountId = call->getAccountId(); + for (const auto& cid: getCallList()) { + if (auto call = getCallFromCallID(cid)) { + if (call->getState() != Call::CallState::ACTIVE) + continue; + if (call->getAccountId() == accountId) { + if (cid != callID) { + if (call->getConfId().empty()) { + joinParticipant(callID, cid, false); + } else { + addParticipant(callID, call->getConfId()); + } + return; + } + } + } + } + // First call + auto conf = std::make_shared(); + + // Bind calls according to their state + pimpl_->bindCallToConference(*call, *conf); + conf->detach(); + + pimpl_->conferenceMap_.emplace(conf->getConfID(), conf); + emitSignal(conf->getConfID()); + + }); + } else if (pimpl_->autoAnswer_) { + runOnMainThread([this, callID]{ + answerCall(callID); + }); } else if (currentCall) { // Test if already calling this person if (currentCall->getAccountId() == accountId diff --git a/src/manager.h b/src/manager.h index 247d64720..44f5c5274 100644 --- a/src/manager.h +++ b/src/manager.h @@ -285,7 +285,8 @@ class DRING_TESTABLE Manager { * @param the second call id */ bool joinParticipant(const std::string& call_id1, - const std::string& call_id2); + const std::string& call_id2, + bool attached = true); /** * Create a conference from a list of participant diff --git a/src/media/video/video_rtp_session.cpp b/src/media/video/video_rtp_session.cpp index ed39906dd..e770d00ca 100644 --- a/src/media/video/video_rtp_session.cpp +++ b/src/media/video/video_rtp_session.cpp @@ -333,15 +333,16 @@ VideoRtpSession::enterConference(Conference* conference) JAMI_DBG("[call:%s] enterConference (conf: %s)", callID_.c_str(), conference->getConfID().c_str()); - if (send_.enabled or receiveThread_) { - videoMixer_ = conference->getVideoMixer(); + // TODO is this correct? The video Mixer should be enabled for a detached conference even if we are not sending values + videoMixer_ = conference->getVideoMixer(); #if defined(__APPLE__) && TARGET_OS_MAC - videoMixer_->setParameters(localVideoParams_.width, - localVideoParams_.height, - av_get_pix_fmt(localVideoParams_.pixel_format.c_str())); + videoMixer_->setParameters(localVideoParams_.width, + localVideoParams_.height, + av_get_pix_fmt(localVideoParams_.pixel_format.c_str())); #else - videoMixer_->setParameters(localVideoParams_.width, localVideoParams_.height); + videoMixer_->setParameters(localVideoParams_.width, localVideoParams_.height); #endif + if (send_.enabled or receiveThread_) { setupConferenceVideoPipeline(*conference_); // Restart encoder with conference parameter ON in order to unlink HW encoder