diff --git a/src/account.cpp b/src/account.cpp index ba9603c87da59682cf3eb9c28081f91d9a7a1fd4..667581bdf67f5ce0f47432228928c9b2523943c6 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<std::string, std::string> &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 75e2cd2e78abcfb6aa23cd7cb6d4abca113dc990..4049e33a194bb0b02a233498f266e0573350da32 100644 --- a/src/account.h +++ b/src/account.h @@ -181,8 +181,6 @@ class Account : public Serializable, public std::enable_shared_from_this<Account return false; } - std::vector<std::shared_ptr<Call>> 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<Account mailBox_ = mb; } + bool isRendezVous() const { + return isRendezVous_; + } + void attachCall(const std::string& id); void detachCall(const std::string& id); @@ -384,6 +386,7 @@ class Account : public Serializable, public std::enable_shared_from_this<Account static const char * const HOSTNAME_KEY; static const char * const ACCOUNT_ENABLE_KEY; static const char * const ACCOUNT_AUTOANSWER_KEY; + static const char * const ACCOUNT_ISRENDEZVOUS_KEY; static const char * const ACCOUNT_ACTIVE_CALL_LIMIT_KEY; static const char * const MAILBOX_KEY; static const char * const USER_AGENT_KEY; @@ -437,6 +440,9 @@ class Account : public Serializable, public std::enable_shared_from_this<Account /* If true, automatically answer calls to this account */ bool autoAnswerEnabled_; + /* If true mix calls into a conference */ + bool isRendezVous_; + /** * The number of concurrent calls for the account * -1: Unlimited diff --git a/src/account_schema.h b/src/account_schema.h index 519e35d351318ed0a3f6ae1c9c2252fb30fa13e4..f0e1c91f5c559311d8896a0f5a43e524de03e235 100644 --- a/src/account_schema.h +++ b/src/account_schema.h @@ -36,6 +36,7 @@ static const char *const CONFIG_ACCOUNT_DISPLAYNAME = "Account.displ static const char *const CONFIG_ACCOUNT_MAILBOX = "Account.mailbox"; static const char *const CONFIG_ACCOUNT_ENABLE = "Account.enable"; static const char *const CONFIG_ACCOUNT_AUTOANSWER = "Account.autoAnswer"; +static const char *const CONFIG_ACCOUNT_ISRENDEZVOUS = "Account.rendezVous"; static const char *const CONFIG_ACCOUNT_REGISTRATION_EXPIRE = "Account.registrationExpire"; static const char *const CONFIG_ACCOUNT_DTMF_TYPE = "Account.dtmfType"; static const char *const CONFIG_RINGTONE_PATH = "Account.ringtonePath"; diff --git a/src/dring/account_const.h b/src/dring/account_const.h index dcb4dc79c00a11b2ca8bcff43e1e16036ba24350..f13d5c1c97cb9611f3415ca54c134ec896fb7550 100644 --- a/src/dring/account_const.h +++ b/src/dring/account_const.h @@ -115,6 +115,7 @@ constexpr static const char ENABLED [] = "Account.enable"; constexpr static const char MAILBOX [] = "Account.mailbox"; constexpr static const char DTMF_TYPE [] = "Account.dtmfType"; constexpr static const char AUTOANSWER [] = "Account.autoAnswer"; +constexpr static const char ISRENDEZVOUS [] = "Account.rendezVous"; constexpr static const char ACTIVE_CALL_LIMIT [] = "Account.activeCallLimit"; constexpr static const char HOSTNAME [] = "Account.hostname"; constexpr static const char USERNAME [] = "Account.username"; diff --git a/src/manager.cpp b/src/manager.cpp index 4ea29251b57a3b4d35e6028b5dd725fdc81d0154..66e875b189e49c1f050d37c9f25d8fbc0cb4ad30 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -43,6 +43,7 @@ #include "string_utils.h" #include "jamidht/jamiaccount.h" #include "sip/sipvoiplink.h" +#include "account.h" #include <opendht/rng.h> 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<JamiAccount>(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<DRing::CallSignal::ConferenceCreated>(conf->getConfID()); @@ -1836,8 +1851,42 @@ Manager::incomingCall(Call &call, const std::string& accountId) emitSignal<DRing::CallSignal::IncomingCall>(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<Conference>(); + + // Bind calls according to their state + pimpl_->bindCallToConference(*call, *conf); + conf->detach(); + + pimpl_->conferenceMap_.emplace(conf->getConfID(), conf); + emitSignal<DRing::CallSignal::ConferenceCreated>(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 247d647206bb51396447ce9e09d19b880632accd..44f5c527483f0723a50b271f966ea31db4df2b64 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 ed39906ddd107d53313d695e28f5db85f41fd09d..e770d00ca3288f5c9a89f95b1a979dbf451526b1 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