mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
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
This commit is contained in:
@ -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_},
|
||||
|
@ -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
|
||||
|
@ -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";
|
||||
|
@ -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";
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
Reference in New Issue
Block a user