From a404577a9e47229aaf2bc2e220b0ebb524cc321c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=A9bastien=20Blin?= <sebastien.blin@savoirfairelinux.com> Date: Wed, 28 Feb 2024 15:00:43 -0500 Subject: [PATCH] call-swarm: avoid dummy call to create a conference Now a conference can start without any call (this avoid to attach a call without peer to create a conference). Path is now clearer for a call creation: + If we receive a call, we attach it to the conference + Else we do not create any call and just attach the host. Next step is to be able to attach a host in audio only without weird tricks and group addParticipant/bindParticipant GitLab: #953 Change-Id: I13785a5525e041c37fb62c0c9f355e9371f1e4ad --- bin/dbus/cx.ring.Ring.CallManager.xml | 5 +- bin/dbus/dbuscallmanager.hpp | 2 +- bin/jni/callmanager.i | 4 +- bin/jni/jni_interface.i | 2 +- bin/nodejs/callback.h | 7 +- bin/nodejs/callmanager.i | 4 +- src/jami/callmanager_interface.h | 2 +- src/jamidht/conversation_module.cpp | 149 ++++++++++++++------------ src/jamidht/conversation_module.h | 12 +-- src/jamidht/jamiaccount.cpp | 46 ++++---- src/jamidht/jamiaccount.h | 3 +- src/manager.cpp | 14 ++- test/agent/src/bindings/signal.cpp | 2 +- test/unitTest/call/conference.cpp | 2 +- tools/jamictrl/controller.py | 4 +- 15 files changed, 143 insertions(+), 115 deletions(-) diff --git a/bin/dbus/cx.ring.Ring.CallManager.xml b/bin/dbus/cx.ring.Ring.CallManager.xml index f44b497858..6178ae67e6 100644 --- a/bin/dbus/cx.ring.Ring.CallManager.xml +++ b/bin/dbus/cx.ring.Ring.CallManager.xml @@ -904,9 +904,10 @@ Emitted when a new conference is created. Client is responsible for storing the confID and call <tp:member-ref>getParticipantList</tp:member-ref> to update the display. </tp:docstring> <arg type="s" name="accountId" /> - <arg type="s" name="confID"> + <arg type="s" name="conversationId" /> + <arg type="s" name="confId"> <tp:docstring> - A new conference ID. + A new conference Id. </tp:docstring> </arg> </signal> diff --git a/bin/dbus/dbuscallmanager.hpp b/bin/dbus/dbuscallmanager.hpp index 6b5630afdc..1fe65b7f70 100644 --- a/bin/dbus/dbuscallmanager.hpp +++ b/bin/dbus/dbuscallmanager.hpp @@ -489,7 +489,7 @@ private: exportable_serialized_callback<CallSignal::RecordPlaybackFilepath>( std::bind(&DBusCallManager::emitRecordPlaybackFilepath, this, _1, _2)), exportable_serialized_callback<CallSignal::ConferenceCreated>( - std::bind(&DBusCallManager::emitConferenceCreated, this, _1, _2)), + std::bind(&DBusCallManager::emitConferenceCreated, this, _1, _2, _3)), exportable_serialized_callback<CallSignal::ConferenceChanged>( std::bind(&DBusCallManager::emitConferenceChanged, this, _1, _2, _3)), exportable_serialized_callback<CallSignal::UpdatePlaybackScale>( diff --git a/bin/jni/callmanager.i b/bin/jni/callmanager.i index b197107b77..96c52814f1 100644 --- a/bin/jni/callmanager.i +++ b/bin/jni/callmanager.i @@ -40,7 +40,7 @@ public: virtual void mediaChangeRequested(const std::string& accountId, const std::string& callId, const std::vector<std::map<std::string, std::string>>& mediaList){} virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){} - virtual void conferenceCreated(const std::string& accountId, const std::string& confId){} + virtual void conferenceCreated(const std::string& accountId, const std::string& conversationId, const std::string& confId){} virtual void conferenceChanged(const std::string& accountId, const std::string& confId, const std::string& state){} virtual void conferenceRemoved(const std::string& accountId, const std::string& confId){} virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){} @@ -164,7 +164,7 @@ public: virtual void mediaChangeRequested(const std::string& accountId, const std::string& callId, const std::vector<std::map<std::string, std::string>>& mediaList){} virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){} - virtual void conferenceCreated(const std::string& accountId, const std::string& confId){} + virtual void conferenceCreated(const std::string& accountId, const std::string& conversationId, const std::string& confId){} virtual void conferenceChanged(const std::string& accountId, const std::string& confId, const std::string& state){} virtual void conferenceRemoved(const std::string& accountId, const std::string& confId){} virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){} diff --git a/bin/jni/jni_interface.i b/bin/jni/jni_interface.i index d2b4e166fc..90da5cdeb0 100644 --- a/bin/jni/jni_interface.i +++ b/bin/jni/jni_interface.i @@ -248,7 +248,7 @@ void init(ConfigurationCallback* confM, Callback* callM, PresenceCallback* presM exportable_callback<CallSignal::IncomingCallWithMedia>(bind(&Callback::incomingCallWithMedia, callM, _1, _2, _3, _4)), exportable_callback<CallSignal::MediaChangeRequested>(bind(&Callback::mediaChangeRequested, callM, _1, _2, _3)), exportable_callback<CallSignal::RecordPlaybackFilepath>(bind(&Callback::recordPlaybackFilepath, callM, _1, _2)), - exportable_callback<CallSignal::ConferenceCreated>(bind(&Callback::conferenceCreated, callM, _1, _2)), + exportable_callback<CallSignal::ConferenceCreated>(bind(&Callback::conferenceCreated, callM, _1, _2, _3)), exportable_callback<CallSignal::ConferenceChanged>(bind(&Callback::conferenceChanged, callM, _1, _2, _3)), exportable_callback<CallSignal::ConferenceRemoved>(bind(&Callback::conferenceRemoved, callM, _1, _2)), exportable_callback<CallSignal::UpdatePlaybackScale>(bind(&Callback::updatePlaybackScale, callM, _1, _2, _3)), diff --git a/bin/nodejs/callback.h b/bin/nodejs/callback.h index e1299401a7..4ec2e59232 100644 --- a/bin/nodejs/callback.h +++ b/bin/nodejs/callback.h @@ -811,15 +811,16 @@ onConversationError(const std::string& accountId, } void -conferenceCreated(const std::string& accountId, const std::string& confId) +conferenceCreated(const std::string& accountId, const std::string& conversationId, const std::string& confId) { std::lock_guard lock(pendingSignalsLock); - pendingSignals.emplace([accountId, confId]() { + pendingSignals.emplace([accountId, confId, conversationId]() { Local<Function> func = Local<Function>::New(Isolate::GetCurrent(), conferenceCreatedCb); if (!func.IsEmpty()) { SWIGV8_VALUE callback_args[] = {V8_STRING_NEW_LOCAL(accountId), + V8_STRING_NEW_LOCAL(conversationId), V8_STRING_NEW_LOCAL(confId)}; - func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 2, callback_args); + func->Call(SWIGV8_CURRENT_CONTEXT(), SWIGV8_NULL(), 3, callback_args); } }); uv_async_send(&signalAsync); diff --git a/bin/nodejs/callmanager.i b/bin/nodejs/callmanager.i index b197107b77..96c52814f1 100644 --- a/bin/nodejs/callmanager.i +++ b/bin/nodejs/callmanager.i @@ -40,7 +40,7 @@ public: virtual void mediaChangeRequested(const std::string& accountId, const std::string& callId, const std::vector<std::map<std::string, std::string>>& mediaList){} virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){} - virtual void conferenceCreated(const std::string& accountId, const std::string& confId){} + virtual void conferenceCreated(const std::string& accountId, const std::string& conversationId, const std::string& confId){} virtual void conferenceChanged(const std::string& accountId, const std::string& confId, const std::string& state){} virtual void conferenceRemoved(const std::string& accountId, const std::string& confId){} virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){} @@ -164,7 +164,7 @@ public: virtual void mediaChangeRequested(const std::string& accountId, const std::string& callId, const std::vector<std::map<std::string, std::string>>& mediaList){} virtual void recordPlaybackFilepath(const std::string& id, const std::string& filename){} - virtual void conferenceCreated(const std::string& accountId, const std::string& confId){} + virtual void conferenceCreated(const std::string& accountId, const std::string& conversationId, const std::string& confId){} virtual void conferenceChanged(const std::string& accountId, const std::string& confId, const std::string& state){} virtual void conferenceRemoved(const std::string& accountId, const std::string& confId){} virtual void updatePlaybackScale(const std::string& filepath, int position, int scale){} diff --git a/src/jami/callmanager_interface.h b/src/jami/callmanager_interface.h index f04ec7d9cc..a3bcca9fed 100644 --- a/src/jami/callmanager_interface.h +++ b/src/jami/callmanager_interface.h @@ -258,7 +258,7 @@ struct LIBJAMI_PUBLIC CallSignal struct LIBJAMI_PUBLIC ConferenceCreated { constexpr static const char* name = "ConferenceCreated"; - using cb_type = void(const std::string&, const std::string&); + using cb_type = void(const std::string&, const std::string&, const std::string&); }; struct LIBJAMI_PUBLIC ConferenceChanged { diff --git a/src/jamidht/conversation_module.cpp b/src/jamidht/conversation_module.cpp index 725848d3ed..fced6f2bf3 100644 --- a/src/jamidht/conversation_module.cpp +++ b/src/jamidht/conversation_module.cpp @@ -2858,10 +2858,10 @@ ConversationModule::getActiveCalls(const std::string& conversationId) const }); } -void +std::shared_ptr<SIPCall> ConversationModule::call(const std::string& url, - const std::shared_ptr<SIPCall>& call, - std::function<void(const std::string&, const DeviceId&)>&& cb) + const std::vector<libjami::MediaMap>& mediaList, + std::function<void(const std::string&, const DeviceId&, const std::shared_ptr<SIPCall>&)>&& cb) { std::string conversationId = "", confId = "", uri = "", deviceId = ""; if (url.find('/') == std::string::npos) { @@ -2870,7 +2870,7 @@ ConversationModule::call(const std::string& url, auto parameters = jami::split_string(url, '/'); if (parameters.size() != 4) { JAMI_ERROR("Incorrect url {:s}", url); - return; + return {}; } conversationId = parameters[0]; uri = parameters[1]; @@ -2878,36 +2878,14 @@ ConversationModule::call(const std::string& url, confId = parameters[3]; } - std::string callUri; - auto sendCall = [&]() { - call->setState(Call::ConnectionState::TRYING); - call->setPeerNumber(callUri); - call->setPeerUri("rdv:" + callUri); - call->addStateListener([w = pimpl_->weak(), conversationId](Call::CallState call_state, - Call::ConnectionState cnx_state, - int) { - if (cnx_state == Call::ConnectionState::DISCONNECTED - && call_state == Call::CallState::MERROR) { - auto shared = w.lock(); - if (!shared) - return false; - if (auto acc = shared->account_.lock()) - emitSignal<libjami::ConfigurationSignal::NeedsHost>(acc->getAccountID(), - conversationId); - return true; - } - return true; - }); - cb(callUri, DeviceId(deviceId)); - }; auto conv = pimpl_->getConversation(conversationId); if (!conv) - return; + return {}; std::unique_lock lk(conv->mtx); if (!conv->conversation) { JAMI_ERROR("Conversation {:s} not found", conversationId); - return; + return {}; } // Check if we want to join a specific conference @@ -2920,7 +2898,6 @@ ConversationModule::call(const std::string& url, auto sendCallRequest = false; if (confId != "") { sendCallRequest = true; - confId = confId == "0" ? Manager::instance().callFactory.getNewCallID() : confId; JAMI_DEBUG("Calling self, join conference"); } else if (!activeCalls.empty()) { // Else, we try to join active calls @@ -2929,7 +2906,6 @@ ConversationModule::call(const std::string& url, confId = ac.at("id"); uri = ac.at("uri"); deviceId = ac.at("device"); - JAMI_DEBUG("Calling last active call: {:s}", callUri); } else if (itRdvAccount != infos.end() && itRdvDevice != infos.end()) { // Else, creates "to" (accountId/deviceId/conversationId/confId) and ask remote host sendCallRequest = true; @@ -2938,65 +2914,100 @@ ConversationModule::call(const std::string& url, confId = "0"; JAMI_DEBUG("Remote host detected. Calling {:s} on device {:s}", uri, deviceId); } + lk.unlock(); - if (sendCallRequest) { - callUri = fmt::format("{}/{}/{}/{}", conversationId, uri, deviceId, confId); - if (uri == pimpl_->username_ && deviceId == pimpl_->deviceId_) { - // In this case, we're probably hosting the conference. - call->setState(Call::ConnectionState::CONNECTED); - // In this case, the call is the only one in the conference - // and there is no peer, so media succeeded and are shown to - // the client. - call->reportMediaNegotiationStatus(); - lk.unlock(); - if (confId == "0") - confId = call->getCallId(); - hostConference(conversationId, confId, call->getCallId(), true); - return; + if (!sendCallRequest + || (uri == pimpl_->username_ && deviceId == pimpl_->deviceId_)) { + confId = confId == "0" ? Manager::instance().callFactory.getNewCallID() : confId; + // TODO attach host with media list + hostConference(conversationId, confId, ""); + return {}; + } + + // Else we need to create a call + auto account = pimpl_->account_.lock(); + auto& manager = Manager::instance(); + std::shared_ptr<SIPCall> call; + + // SIP allows sending empty invites, this use case is not used with Jami accounts. + if (not mediaList.empty()) { + call = manager.callFactory.newSipCall(account, Call::CallType::OUTGOING, mediaList); + } else { + JAMI_WARN("Media list is empty, setting a default list"); + call = manager.callFactory.newSipCall(account, + Call::CallType::OUTGOING, + MediaAttribute::mediaAttributesToMediaMaps( + account->createDefaultMediaList(account->isVideoEnabled()))); + } + + if (not call) + return {}; + + auto callUri = fmt::format("{}/{}/{}/{}", conversationId, uri, deviceId, confId); + account->getIceOptions([call, accountId = account->getAccountID(), callUri, uri = std::move(uri), conversationId, deviceId, cb=std::move(cb)](auto&& opts) { + if (call->isIceEnabled()) { + if (not call->createIceMediaTransport(false) + or not call->initIceMediaTransport(true, + std::forward<dhtnet::IceTransportOptions>(opts))) { + return; + } } + JAMI_DEBUG("New outgoing call with {}", uri); + call->setPeerNumber(uri); + call->setPeerUri("swarm:" + uri); + JAMI_DEBUG("Calling: {:s}", callUri); - sendCall(); - return; - } + call->setState(Call::ConnectionState::TRYING); + call->setPeerNumber(callUri); + call->setPeerUri("rdv:" + callUri); + call->addStateListener([accountId, conversationId](Call::CallState call_state, + Call::ConnectionState cnx_state, + int) { + if (cnx_state == Call::ConnectionState::DISCONNECTED + && call_state == Call::CallState::MERROR) { + emitSignal<libjami::ConfigurationSignal::NeedsHost>(accountId, conversationId); + return true; + } + return true; + }); + cb(callUri, DeviceId(deviceId), call); + }); - // Else, we are the host. - confId = Manager::instance().callFactory.getNewCallID(); - call->setState(Call::ConnectionState::CONNECTED); - // In this case, the call is the only one in the conference - // and there is no peer, so media succeeded and are shown to - // the client. - call->reportMediaNegotiationStatus(); - lk.unlock(); - hostConference(conversationId, confId, call->getCallId(), true); + return call; } void ConversationModule::hostConference(const std::string& conversationId, const std::string& confId, - const std::string& callId, - bool local) + const std::string& callId) { auto acc = pimpl_->account_.lock(); if (!acc) return; - std::shared_ptr<Call> call; - call = acc->getCall(callId); - if (!call) { - JAMI_WARNING("No call with id {} found", callId); - return; - } auto conf = acc->getConference(confId); auto createConf = !conf; + std::shared_ptr<SIPCall> call; + if (!callId.empty()) { + call = std::dynamic_pointer_cast<SIPCall>(acc->getCall(callId)); + if (!call) { + JAMI_WARNING("No call with id {} found", callId); + return; + } + } if (createConf) { - conf = std::make_shared<Conference>(acc, confId, local, call->getMediaAttributeList()); + conf = std::make_shared<Conference>(acc, confId, callId.empty(), callId.empty()? std::vector<MediaAttribute> {} : call->getMediaAttributeList()); acc->attach(conf); } - conf->addParticipant(callId); + + if (!callId.empty()) + conf->addParticipant(callId); + + if (!createConf && callId.empty()) // TODO use mediaList + conf->attachLocalParticipant(); if (createConf) { - emitSignal<libjami::CallSignal::ConferenceCreated>(acc->getAccountID(), confId); + emitSignal<libjami::CallSignal::ConferenceCreated>(acc->getAccountID(), conversationId, confId); } else { - conf->attachLocalParticipant(); conf->reportMediaNegotiationStatus(); emitSignal<libjami::CallSignal::ConferenceChanged>(acc->getAccountID(), conf->getConfId(), @@ -3036,7 +3047,7 @@ ConversationModule::hostConference(const std::string& conversationId, // Master call, so when it's stopped, the conference will be stopped (as we use the hold // state for detaching the call) conf->onShutdown( - [w = pimpl_->weak(), accountUri = pimpl_->username_, confId, conversationId, call, conv]( + [w = pimpl_->weak(), accountUri = pimpl_->username_, confId, conversationId, conv]( int duration) { auto shared = w.lock(); if (shared) { diff --git a/src/jamidht/conversation_module.h b/src/jamidht/conversation_module.h index d01f9ccf16..571808eeef 100644 --- a/src/jamidht/conversation_module.h +++ b/src/jamidht/conversation_module.h @@ -450,16 +450,16 @@ public: /** * Call the conversation * @param url Url to call (swarm:conversation or swarm:conv/account/device/conf to join) - * @param call Call to use + * @param mediaList The media list * @param cb Callback to pass which device to call (called in the same thread) + * @return call if a call is started, else nullptr */ - void call(const std::string& url, - const std::shared_ptr<SIPCall>& call, - std::function<void(const std::string&, const DeviceId&)>&& cb); + std::shared_ptr<SIPCall> call(const std::string& url, + const std::vector<libjami::MediaMap>& mediaList, + std::function<void(const std::string&, const DeviceId&, const std::shared_ptr<SIPCall>&)>&& cb); void hostConference(const std::string& conversationId, const std::string& confId, - const std::string& callId, - bool local); + const std::string& callId); // The following methods modify what is stored on the disk static void saveConvInfos(const std::string& accountId, diff --git a/src/jamidht/jamiaccount.cpp b/src/jamidht/jamiaccount.cpp index 8e63f016fb..0ee7fa9bd6 100644 --- a/src/jamidht/jamiaccount.cpp +++ b/src/jamidht/jamiaccount.cpp @@ -340,6 +340,13 @@ JamiAccount::newIncomingCall(const std::string& from, std::shared_ptr<Call> JamiAccount::newOutgoingCall(std::string_view toUrl, const std::vector<libjami::MediaMap>& mediaList) { + auto uri = Uri(toUrl); + if (uri.scheme() == Uri::Scheme::SWARM || uri.scheme() == Uri::Scheme::RENDEZVOUS) { + // NOTE: In this case newOutgoingCall can act as "unholdConference" and just attach the + // host to the current hosted conference. So, no call will be returned in that case. + return newSwarmOutgoingCallHelper(uri, mediaList); + } + auto& manager = Manager::instance(); std::shared_ptr<SIPCall> call; @@ -357,7 +364,6 @@ JamiAccount::newOutgoingCall(std::string_view toUrl, const std::vector<libjami:: if (not call) return {}; - auto uri = Uri(toUrl); connectionManager_->getIceOptions([call, w = weak(), uri = std::move(uri)](auto&& opts) { if (call->isIceEnabled()) { if (not call->createIceMediaTransport(false) @@ -373,10 +379,7 @@ JamiAccount::newOutgoingCall(std::string_view toUrl, const std::vector<libjami:: call->setPeerNumber(uri.authority()); call->setPeerUri(uri.toString()); - if (uri.scheme() == Uri::Scheme::SWARM || uri.scheme() == Uri::Scheme::RENDEZVOUS) - shared->newSwarmOutgoingCallHelper(call, uri); - else - shared->newOutgoingCallHelper(call, uri); + shared->newOutgoingCallHelper(call, uri); }); return call; @@ -419,16 +422,17 @@ JamiAccount::newOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const U } } -void -JamiAccount::newSwarmOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const Uri& uri) -{ - JAMI_DBG("[Account %s] Calling conversation %s", - getAccountID().c_str(), - uri.authority().c_str()); - convModule()->call( - uri.authority(), - call, - [this, uri, call](const std::string& accountUri, const DeviceId& deviceId) { +std::shared_ptr<SIPCall> +JamiAccount::newSwarmOutgoingCallHelper(const Uri& uri, const std::vector<libjami::MediaMap>& mediaList) +{ + JAMI_DEBUG("[Account {}] Calling conversation {}", + getAccountID(), + uri.authority()); + return convModule()->call( + uri.authority(), mediaList, + [this, uri](const auto& accountUri, const auto& deviceId, const auto& call) { + if (!call) + return; std::unique_lock lkSipConn(sipConnsMtx_); for (auto& [key, value] : sipConns_) { if (key.first != accountUri || key.second != deviceId) @@ -469,8 +473,8 @@ JamiAccount::newSwarmOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, co // Else, ask for a channel (for future calls/text messages) auto type = call->hasVideo() ? "videoCall" : "audioCall"; - JAMI_WARN("[call %s] No channeled socket with this peer. Send request", - call->getCallId().c_str()); + JAMI_WARNING("[call {}] No channeled socket with this peer. Send request", + call->getCallId()); requestSIPConnection(accountUri, deviceId, type, true, call); }); } @@ -552,7 +556,7 @@ JamiAccount::handleIncomingConversationCall(const std::string& callId, if (isNotHosting) { JAMI_DEBUG("Creating conference for swarm {} with id {}", conversationId, confId); // Create conference and host it. - convModule()->hostConference(conversationId, confId, callId, false); + convModule()->hostConference(conversationId, confId, callId); } else { JAMI_DEBUG("Adding participant {} for swarm {} with id {}", callId, conversationId, confId); Manager::instance().addAudio(*call); @@ -3152,6 +3156,12 @@ JamiAccount::getIceOptions() const noexcept return connectionManager_->getIceOptions(); } +void +JamiAccount::getIceOptions(std::function<void(dhtnet::IceTransportOptions&&)> cb) const noexcept +{ + return connectionManager_->getIceOptions(std::move(cb)); +} + dhtnet::IpAddr JamiAccount::getPublishedIpAddress(uint16_t family) const { diff --git a/src/jamidht/jamiaccount.h b/src/jamidht/jamiaccount.h index 1502556e3c..fb7e253516 100644 --- a/src/jamidht/jamiaccount.h +++ b/src/jamidht/jamiaccount.h @@ -338,6 +338,7 @@ public: * Create and return ICE options. */ dhtnet::IceTransportOptions getIceOptions() const noexcept override; + void getIceOptions(std::function<void(dhtnet::IceTransportOptions&&)> cb) const noexcept; dhtnet::IpAddr getPublishedIpAddress(uint16_t family = PF_UNSPEC) const override; /* Devices */ @@ -695,7 +696,7 @@ private: void generateDhParams(); void newOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const Uri& uri); - void newSwarmOutgoingCallHelper(const std::shared_ptr<SIPCall>& call, const Uri& uri); + std::shared_ptr<SIPCall> newSwarmOutgoingCallHelper(const Uri& uri, const std::vector<libjami::MediaMap>& mediaList); std::shared_ptr<SIPCall> createSubCall(const std::shared_ptr<SIPCall>& mainCall); std::filesystem::path idPath_ {}; diff --git a/src/manager.cpp b/src/manager.cpp index 947c19b4b3..078aa7b163 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -1113,7 +1113,7 @@ Manager::outgoingCall(const std::string& account_id, try { call = newOutgoingCall(trim(to), account_id, mediaList); } catch (const std::exception& e) { - JAMI_ERR("%s", e.what()); + JAMI_ERROR("{}", e.what()); return {}; } @@ -1452,8 +1452,12 @@ Manager::ManagerPimpl::addMainParticipant(Conference& conf) bool Manager::ManagerPimpl::hangupConference(Conference& conference) { - JAMI_DBG("Hangup conference %s", conference.getConfId().c_str()); + JAMI_DEBUG("Hangup conference {}", conference.getConfId()); ParticipantSet participants(conference.getParticipantList()); + if (participants.empty()) { + if (auto account = conference.getAccount()) + account->removeConference(conference.getConfId()); + } for (const auto& callId : participants) { if (auto call = base_.getCallFromCallID(callId)) base_.hangupCall(call->getAccountId(), callId); @@ -1527,7 +1531,7 @@ Manager::joinParticipant(const std::string& accountId, mediaAttr = call2->getMediaAttributeList(); auto conf = std::make_shared<Conference>(account, "", true, mediaAttr); account->attach(conf); - emitSignal<libjami::CallSignal::ConferenceCreated>(account->getAccountID(), conf->getConfId()); + emitSignal<libjami::CallSignal::ConferenceCreated>(account->getAccountID(), "", conf->getConfId()); // Bind calls according to their state pimpl_->bindCallToConference(*call1, *conf); @@ -1585,7 +1589,7 @@ Manager::createConfFromParticipantList(const std::string& accountId, // Create the conference if and only if at least 2 calls have been successfully created if (successCounter >= 2) { account->attach(conf); - emitSignal<libjami::CallSignal::ConferenceCreated>(accountId, conf->getConfId()); + emitSignal<libjami::CallSignal::ConferenceCreated>(accountId, "", conf->getConfId()); } } @@ -2619,7 +2623,7 @@ Manager::ManagerPimpl::processIncomingCall(const std::string& accountId, Call& i // First call auto conf = std::make_shared<Conference>(account, "", false); account->attach(conf); - emitSignal<libjami::CallSignal::ConferenceCreated>(account->getAccountID(), + emitSignal<libjami::CallSignal::ConferenceCreated>(account->getAccountID(), "", conf->getConfId()); // Bind calls according to their state diff --git a/test/agent/src/bindings/signal.cpp b/test/agent/src/bindings/signal.cpp index e40443e141..3bfdf05969 100644 --- a/test/agent/src/bindings/signal.cpp +++ b/test/agent/src/bindings/signal.cpp @@ -211,7 +211,7 @@ install_signal_primitives(void*) add_handler<libjami::CallSignal::RecordPlaybackFilepath, const std::string&, const std::string&>( handlers, "record-playback-filepath"); - add_handler<libjami::CallSignal::ConferenceCreated, const std::string&, const std::string&>( + add_handler<libjami::CallSignal::ConferenceCreated, const std::string&, const std::string&, const std::string&>( handlers, "conference-created"); add_handler<libjami::CallSignal::ConferenceChanged, diff --git a/test/unitTest/call/conference.cpp b/test/unitTest/call/conference.cpp index 19d7bd2d64..d864703e23 100644 --- a/test/unitTest/call/conference.cpp +++ b/test/unitTest/call/conference.cpp @@ -235,7 +235,7 @@ ConferenceTest::registerSignalHandlers() cv.notify_one(); })); confHandlers.insert(libjami::exportable_callback<libjami::CallSignal::ConferenceCreated>( - [=](const std::string&, const std::string& conferenceId) { + [=](const std::string&, const std::string&, const std::string& conferenceId) { confId = conferenceId; cv.notify_one(); })); diff --git a/tools/jamictrl/controller.py b/tools/jamictrl/controller.py index 760c86afe9..cff1ac9ef6 100644 --- a/tools/jamictrl/controller.py +++ b/tools/jamictrl/controller.py @@ -298,10 +298,10 @@ class libjamiCtrl(Thread): def onConferenceCreated_cb(self): pass - def onConferenceCreated_callback(self, confId): + def onConferenceCreated_callback(self, convId, confId): pass - def onConferenceCreated(self, confId): + def onConferenceCreated(self, convId, confId): self.currentConfId = confId self.onConferenceCreated_cb() self.onConferenceCreated_callback(confId) -- GitLab