diff --git a/bin/dbus/cx.ring.Ring.CallManager.xml b/bin/dbus/cx.ring.Ring.CallManager.xml index 61ae67b6cab6e51fb49f06d119104705afc7fab0..84a3394518724f817d7f3f51386a645619df51fe 100644 --- a/bin/dbus/cx.ring.Ring.CallManager.xml +++ b/bin/dbus/cx.ring.Ring.CallManager.xml @@ -25,6 +25,30 @@ <arg type="s" name="callID" direction="out"/> </method> + <method name="placeCallWithDetails" tp:name-for-bindings="placeCallWithDetails"> + <tp:added version="4.1.0"/> + <tp:docstring> + <p>This is a method in order to place a new call. This version allows to pass some call details. The call is registered with the daemon using this method.</p> + </tp:docstring> + <arg type="s" name="accountID" direction="in"> + <tp:docstring> + The ID of the account with which you want to make a call. If the call is to be placed without any account by means of a SIP URI (i.e. sip:num@server), the "IP2IP_PROFILE" is passed as the accountID. For more details on accounts see the configuration manager interface. + </tp:docstring> + </arg> + <arg type="s" name="to" direction="in"> + <tp:docstring> + If bound to a VoIP account, then the argument is the phone number. In case of calls involving "IP2IP_PROFILE", a complete SIP URI must be specified. + </tp:docstring> + </arg> + <annotation name="org.qtproject.QtDBus.QtTypeName.In2" value="MapStringString"/> + <arg type="a{ss}" name="VolatileCallDetails" direction="in"> + <tp:docstring> + TBD. + </tp:docstring> + </arg> + <arg type="s" name="callID" direction="out"/> + </method> + <method name="refuse" tp:name-for-bindings="refuse"> <tp:docstring> Refuse an incoming call. diff --git a/bin/dbus/dbuscallmanager.cpp b/bin/dbus/dbuscallmanager.cpp index ba13e13fd99f55d3adf3250d6387ea3cab26e58c..3bbcf45081b97ab29a685224f57a173490164529 100644 --- a/bin/dbus/dbuscallmanager.cpp +++ b/bin/dbus/dbuscallmanager.cpp @@ -31,6 +31,13 @@ DBusCallManager::placeCall(const std::string& accountID, const std::string& to) return DRing::placeCall(accountID, to); } +auto +DBusCallManager::placeCallWithDetails(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& VolatileCallDetails) + -> decltype (DRing::placeCall(accountID, to, VolatileCallDetails)) +{ + return DRing::placeCall(accountID, to, VolatileCallDetails); +} + auto DBusCallManager::refuse(const std::string& callID) -> decltype(DRing::refuse(callID)) { diff --git a/bin/dbus/dbuscallmanager.h b/bin/dbus/dbuscallmanager.h index db70c044c65c665c6647187b93281d76055b6763..2f504200081236e427c80c5474265864ed76ce87 100644 --- a/bin/dbus/dbuscallmanager.h +++ b/bin/dbus/dbuscallmanager.h @@ -55,6 +55,8 @@ class DBusCallManager : // Methods std::string placeCall(const std::string& accountID, const std::string& to); + std::string placeCallWithDetails(const std::string& accountID, const std::string& to, + const std::map<std::string, std::string>& VolatileCallDetails); bool refuse(const std::string& callID); bool accept(const std::string& callID); bool hangUp(const std::string& callID); diff --git a/configure.ac b/configure.ac index c558fc93bb12afd85021daee8cdfc88b71c6f6b8..b117399a593576a17b8c96eb1cb2ac6d795c7d83 100644 --- a/configure.ac +++ b/configure.ac @@ -2,7 +2,7 @@ dnl Ring - configure.ac for automake 1.9 and autoconf 2.59 dnl Process this file with autoconf to produce a configure script. AC_PREREQ([2.65]) -AC_INIT([Ring Daemon],[4.0.0],[ring@gnu.org],[ring]) +AC_INIT([Ring Daemon],[4.1.0],[ring@gnu.org],[ring]) AC_COPYRIGHT([[Copyright (c) Savoir-faire Linux 2004-2017]]) AC_REVISION([$Revision$]) diff --git a/doc/doxygen/core-doc.cfg.in b/doc/doxygen/core-doc.cfg.in index 72b2eaa2cc9f6e348febc55c2cee69597029c3bc..31660777df7de735056e1d433d8fe1f011f4aabf 100644 --- a/doc/doxygen/core-doc.cfg.in +++ b/doc/doxygen/core-doc.cfg.in @@ -31,7 +31,7 @@ PROJECT_NAME = "Ring Daemon" # This could be handy for archiving the generated documentation or # if some version control system is used. -PROJECT_NUMBER = 4.0.0 +PROJECT_NUMBER = 4.1.0 # Using the PROJECT_BRIEF tag one can provide an optional one line description # for a project that appears at the top of each page and should give viewer diff --git a/src/account.h b/src/account.h index bbad1e26718839c3cd043259836cc3c6ab92dbe7..331ad3cd48ac36382bc45dc1ef03d5543c70b15e 100644 --- a/src/account.h +++ b/src/account.h @@ -142,7 +142,7 @@ class Account : public Serializable, public std::enable_shared_from_this<Account * @param toUrl The address to call * @return std::shared_ptr<Call> A pointer on the created call */ - virtual std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl) = 0; + virtual std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails = {}) = 0; /* Note: we forbid incoming call creation from an instance of Account. * This is why no newIncomingCall() method exist here. @@ -198,7 +198,7 @@ class Account : public Serializable, public std::enable_shared_from_this<Account /** * Set the registration state of the specified link - * @param state The registration state of underlying VoIPLink + * @param state The registration state of underlying VoIPLink */ virtual void setRegistrationState(RegistrationState state, unsigned detail_code=0, const std::string& detail_str={}); diff --git a/src/call.cpp b/src/call.cpp index db4bee11e6ef09590979b5533fa9948da2640ce4..55fc79afd15d5d3e9f54c0c335908e17ef634426 100644 --- a/src/call.cpp +++ b/src/call.cpp @@ -78,11 +78,14 @@ hangupCalls(Call::SubcallSet callptr_list, int errcode) //============================================================================== -Call::Call(Account& account, const std::string& id, Call::CallType type) +Call::Call(Account& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details) : id_(id) , type_(type) , account_(account) { + setEarlyDetails(details); + addStateListener([this](UNUSED Call::CallState call_state, UNUSED Call::ConnectionState cnx_state, UNUSED int code) { @@ -308,6 +311,12 @@ Call::toggleRecording() return startRecording; } +void +Call::setEarlyDetails(const std::map<std::string, std::string>& details) +{ + (void)details; +} + std::map<std::string, std::string> Call::getDetails() const { diff --git a/src/call.h b/src/call.h index 1caf770951f1dd0af70fcd793824ff081be0aad9..7d0d2f16b808504d6255a7a63c5371efd059b895 100644 --- a/src/call.h +++ b/src/call.h @@ -311,8 +311,10 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { * Constructor of a call * @param id Unique identifier of the call * @param type set definitely this call as incoming/outgoing + * @param details volatile details to customize the call creation */ - Call(Account& account, const std::string& id, Call::CallType type); + Call(Account& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details = {}); // TODO all these members are not protected against multi-thread access @@ -333,6 +335,8 @@ class Call : public Recordable, public std::enable_shared_from_this<Call> { private: friend void hangupCallsIf(Call::SubcallSet, int, const std::function<bool(Call*)>&); + void setEarlyDetails(const std::map<std::string, std::string>& details); + bool validStateTransition(CallState newState); void checkPendingIM(); diff --git a/src/call_factory.h b/src/call_factory.h index 8a3e72fab7ea123a075dd5eb8e437ef28037dd44..019a87b4c50476b5b519c8f0d5c7aff1a0bf99bd 100644 --- a/src/call_factory.h +++ b/src/call_factory.h @@ -71,7 +71,8 @@ class CallFactory { * @param account account useed to create this call */ template <class T, class A> - std::shared_ptr<T> newCall(A& account, const std::string& id, Call::CallType type) { + std::shared_ptr<T> newCall(A& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details={}) { if (!allowNewCall_) { RING_WARN("newCall aborted : CallFactory in forbid state"); return nullptr; @@ -81,8 +82,9 @@ class CallFactory { // and not accessible from std::make_shared. // We use a concrete class to bypass this restriction. struct ConcreteCall : T { - ConcreteCall(A& account, const std::string& id, Call::CallType type) - : T(account, id, type) {} + ConcreteCall(A& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details) + : T(account, id, type, details) {} }; if (hasCall(id)) { @@ -90,7 +92,7 @@ class CallFactory { return nullptr; } - auto call = std::make_shared<ConcreteCall>(account, id, type); + auto call = std::make_shared<ConcreteCall>(account, id, type, details); if (call) { std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); callMaps_[call->getLinkType()].insert(std::make_pair(id, call)); diff --git a/src/client/callmanager.cpp b/src/client/callmanager.cpp index b0d43b82a32c89e003ce7bb3781ce36dc1e806bb..28dfd67fca3ee461162d48f2b424e992b2b07c8a 100644 --- a/src/client/callmanager.cpp +++ b/src/client/callmanager.cpp @@ -65,6 +65,18 @@ placeCall(const std::string& accountID, const std::string& to) } } +std::string +placeCall(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& volatileCallDetails) +{ + // Check if a destination number is available + if (to.empty()) { + RING_DBG("No number entered - Call stopped"); + return {}; + } else { + return ring::Manager::instance().outgoingCall(accountID, to, "", volatileCallDetails); + } +} + bool refuse(const std::string& callID) { diff --git a/src/dring/callmanager_interface.h b/src/dring/callmanager_interface.h index 2b6a54999708d819ca6d26e819270d00ec3e31cc..5ddbc669e74cc7a246fdc795b080945be0c43706 100644 --- a/src/dring/callmanager_interface.h +++ b/src/dring/callmanager_interface.h @@ -37,6 +37,7 @@ void registerCallHandlers(const std::map<std::string, std::shared_ptr<CallbackWr /* Call related methods */ std::string placeCall(const std::string& accountID, const std::string& to); +std::string placeCall(const std::string& accountID, const std::string& to, const std::map<std::string, std::string>& VolatileCallDetails); bool refuse(const std::string& callID); bool accept(const std::string& callID); diff --git a/src/manager.cpp b/src/manager.cpp index 9939a087daed44e245dcb5486b393b8c4284ac22..f74a26dd382496039820f74c6f690894b84f67b2 100644 --- a/src/manager.cpp +++ b/src/manager.cpp @@ -843,7 +843,8 @@ Manager::unregisterAccounts() std::string Manager::outgoingCall(const std::string& preferred_account_id, const std::string& to, - const std::string& conf_id) + const std::string& conf_id, + const std::map<std::string, std::string>& volatileCallDetails) { if (not conf_id.empty() and not isConference(conf_id)) { RING_ERR("outgoingCall() failed, invalid conference id"); @@ -859,7 +860,7 @@ Manager::outgoingCall(const std::string& preferred_account_id, * as the factory may decide to use another account (like IP2IP). */ RING_DBG("New outgoing call to %s", to_cleaned.c_str()); - call = newOutgoingCall(to_cleaned, preferred_account_id); + call = newOutgoingCall(to_cleaned, preferred_account_id, volatileCallDetails); } catch (const std::exception &e) { RING_ERR("%s", e.what()); return {}; @@ -3009,7 +3010,9 @@ Manager::getAudioDriver() } std::shared_ptr<Call> -Manager::newOutgoingCall(const std::string& toUrl, const std::string& preferredAccountId) +Manager::newOutgoingCall(const std::string& toUrl, + const std::string& preferredAccountId, + const std::map<std::string, std::string>& volatileCallDetails) { auto account = getAccount(preferredAccountId); if (account and !account->isUsable()) { @@ -3042,7 +3045,7 @@ Manager::newOutgoingCall(const std::string& toUrl, const std::string& preferredA return nullptr; } - return account->newOutgoingCall(toUrl); + return account->newOutgoingCall(toUrl, volatileCallDetails); } #ifdef RING_VIDEO diff --git a/src/manager.h b/src/manager.h index ec05c50cbdce10926eae18ecd94230a75bda8f5f..f28a641ea97aca3b03ab70f60f97603abde0087d 100644 --- a/src/manager.h +++ b/src/manager.h @@ -119,14 +119,15 @@ class Manager { /** * Functions which occur with a user's action * Place a new call - * @param accountId The account to make the call with + * @param accountId The account to make the call with * @param to The recipient of the call * @param conf_id The conference identifier if any * @return id The call ID on success, empty string otherwise */ std::string outgoingCall(const std::string& accountId, const std::string& to, - const std::string& conf_id = ""); + const std::string& conf_id = "", + const std::map<std::string, std::string>& volatileCallDetails = {}); /** * Functions which occur with a user's action @@ -365,7 +366,7 @@ class Manager { /** * Notify the client he has voice mails - * @param accountId The account identifier + * @param accountId The account identifier * @param nb_msg The number of messages */ void startVoiceMessageNotification(const std::string& accountId, int nb_msg); @@ -397,7 +398,7 @@ class Manager { /** * Retrieve details about a given account - * @param accountID The account identifier + * @param accountID The account identifier * @return std::map< std::string, std::string > The account details */ std::map<std::string, std::string> getAccountDetails(const std::string& accountID) const; @@ -411,7 +412,7 @@ class Manager { /** * Retrieve details about a given call - * @param callID The account identifier + * @param callID The account identifier * @return std::map< std::string, std::string > The call details */ std::map<std::string, std::string> getCallDetails(const std::string& callID); @@ -424,7 +425,7 @@ class Manager { /** * Retrieve details about a given call - * @param callID The account identifier + * @param callID The account identifier * @return std::map< std::string, std::string > The call details */ std::map<std::string, std::string> getConferenceDetails(const std::string& callID) const; @@ -454,8 +455,8 @@ class Manager { * Save the details of an existing account, given the account ID * This will load the configuration map with the given data. * It will also register/unregister links where the 'Enabled' switched. - * @param accountID The account identifier - * @param details The account parameters + * @param accountID The account identifier + * @param details The account parameters */ void setAccountDetails(const std::string& accountID, const std::map<std::string, ::std::string > &details); @@ -483,7 +484,7 @@ class Manager { * Delete an existing account, unregister VoIPLink associated, and * purge from configuration. * If 'flush' argument is true, filesystem entries are also removed. - * @param accountID The account unique ID + * @param accountID The account unique ID */ void removeAccount(const std::string& accountID, bool flush=false); @@ -554,8 +555,8 @@ class Manager { /** * Ringtone option. * If ringtone is enabled, ringtone on incoming call use custom choice. If not, only standart tone. - * @return int 1 if enabled - * 0 otherwise + * @return int 1 if enabled + * 0 otherwise */ int isRingtoneEnabled(const std::string& id); @@ -618,8 +619,8 @@ class Manager { /** * Get the audio manager * @return int The audio manager - * "alsa" - * "pulseaudio" + * "alsa" + * "pulseaudio" */ std::string getAudioManager() const; @@ -707,7 +708,7 @@ class Manager { /** * Get the current call id - * @return std::string The call id or "" + * @return std::string The call id or "" */ const std::string getCurrentCallId() const; @@ -830,7 +831,8 @@ class Manager { * @note This function raises VoipLinkException() on errors. */ std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl, - const std::string& preferredAccountId); + const std::string& preferredAccountId, + const std::map<std::string, std::string>& volatileCallDetails = {}); CallFactory callFactory; diff --git a/src/ringdht/ringaccount.cpp b/src/ringdht/ringaccount.cpp index 65c1106e76e8750ad7461dd82e94aba16d780e1f..e9b19042dd30fa64298508ae7e04503d961a826f 100644 --- a/src/ringdht/ringaccount.cpp +++ b/src/ringdht/ringaccount.cpp @@ -329,13 +329,14 @@ RingAccount::newIncomingCall(const std::string& from) template <> std::shared_ptr<SIPCall> -RingAccount::newOutgoingCall(const std::string& toUrl) +RingAccount::newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails) { auto sufix = stripPrefix(toUrl); RING_DBG("Calling DHT peer %s", sufix.c_str()); auto& manager = Manager::instance(); auto call = manager.callFactory.newCall<SIPCall, RingAccount>(*this, manager.getNewCallID(), - Call::CallType::OUTGOING); + Call::CallType::OUTGOING, + volatileCallDetails); call->setIPToIP(true); call->setSecure(isTlsEnabled()); @@ -395,7 +396,8 @@ RingAccount::startOutgoingCall(const std::shared_ptr<SIPCall>& call, const std:: auto& manager = Manager::instance(); auto dev_call = manager.callFactory.newCall<SIPCall, RingAccount>(*sthis, manager.getNewCallID(), - Call::CallType::OUTGOING); + Call::CallType::OUTGOING, + call->getDetails()); std::weak_ptr<SIPCall> weak_dev_call = dev_call; dev_call->setIPToIP(true); dev_call->setSecure(sthis->isTlsEnabled()); @@ -533,9 +535,9 @@ RingAccount::onConnectedOutgoingCall(SIPCall& call, const std::string& to_id, Ip } std::shared_ptr<Call> -RingAccount::newOutgoingCall(const std::string& toUrl) +RingAccount::newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails) { - return newOutgoingCall<SIPCall>(toUrl); + return newOutgoingCall<SIPCall>(toUrl, volatileCallDetails); } bool diff --git a/src/ringdht/ringaccount.h b/src/ringdht/ringaccount.h index e0769f889e024f6b8a8d6bb1815fc31a0eefbeb9..27b65e1679935077c54e501407d37c580c495668 100644 --- a/src/ringdht/ringaccount.h +++ b/src/ringdht/ringaccount.h @@ -215,7 +215,8 @@ class RingAccount : public SIPAccountBase { * Implementation of Account::newOutgoingCall() * Note: keep declaration before newOutgoingCall template. */ - std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl) override; + std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl, + const std::map<std::string, std::string>& volatileCallDetails = {}) override; /** * Create outgoing SIPCall. @@ -227,11 +228,11 @@ class RingAccount : public SIPAccountBase { #ifndef RING_UWP template <class T=SIPCall> std::shared_ptr<enable_if_base_of<T, SIPCall> > - newOutgoingCall(const std::string& toUrl); + newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails = {}); #else template <class T> std::shared_ptr<T> - newOutgoingCall(const std::string& toUrl); + newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails = {}); #endif /** diff --git a/src/sip/sipaccount.cpp b/src/sip/sipaccount.cpp index 77d883e546d246e88f1100863a4acdbd57f07825..caf6a87caf7ad7bf576ccb4b97bb4a3ad2c90c4a 100644 --- a/src/sip/sipaccount.cpp +++ b/src/sip/sipaccount.cpp @@ -164,13 +164,15 @@ SIPAccount::newIncomingCall(const std::string& from UNUSED) template <> std::shared_ptr<SIPCall> -SIPAccount::newOutgoingCall(const std::string& toUrl) +SIPAccount::newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails) { std::string to; int family; auto& manager = Manager::instance(); - auto call = manager.callFactory.newCall<SIPCall, SIPAccount>(*this, manager.getNewCallID(), Call::CallType::OUTGOING); + auto call = manager.callFactory.newCall<SIPCall, SIPAccount>(*this, manager.getNewCallID(), + Call::CallType::OUTGOING, + volatileCallDetails); call->setSecure(isTlsEnabled()); if (isIP2IP()) { @@ -308,9 +310,9 @@ SIPAccount::getTransportSelector() { } std::shared_ptr<Call> -SIPAccount::newOutgoingCall(const std::string& toUrl) +SIPAccount::newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails) { - return newOutgoingCall<SIPCall>(toUrl); + return newOutgoingCall<SIPCall>(toUrl, volatileCallDetails); } bool diff --git a/src/sip/sipaccount.h b/src/sip/sipaccount.h index d8a311eaf67a034da65dc6606e71df2c2ccfb41f..8a6cecdb82d021f343f3ad90c5f53104cc1f0b0a 100644 --- a/src/sip/sipaccount.h +++ b/src/sip/sipaccount.h @@ -455,7 +455,8 @@ class SIPAccount : public SIPAccountBase { * Implementation of Account::newOutgoingCall() * Note: keep declaration before newOutgoingCall template. */ - std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl) override; + std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl, + const std::map<std::string, std::string>& volatileCallDetails = {}) override; /** * Create outgoing SIPCall. @@ -467,11 +468,11 @@ class SIPAccount : public SIPAccountBase { #ifndef RING_UWP template <class T=SIPCall> std::shared_ptr<enable_if_base_of<T, SIPCall> > - newOutgoingCall(const std::string& toUrl); + newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails = {}); #else template <class T> std::shared_ptr<T> - newOutgoingCall(const std::string& toUrl); + newOutgoingCall(const std::string& toUrl, const std::map<std::string, std::string>& volatileCallDetails = {}); #endif /** diff --git a/src/sip/sipcall.cpp b/src/sip/sipcall.cpp index 70b625bf7e7a34cf2e0c78130c633d92e2016a6c..776e02396302eb4a8d14f1cfa5edf554eb428f34 100644 --- a/src/sip/sipcall.cpp +++ b/src/sip/sipcall.cpp @@ -108,8 +108,9 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf) call.sendSIPInfo(dtmf_body, "dtmf-relay"); } -SIPCall::SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type) - : Call(account, id, type) +SIPCall::SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details) + : Call(account, id, type, details) , avformatrtp_(new AudioRtpSession(id)) #ifdef RING_VIDEO // The ID is used to associate video streams to calls diff --git a/src/sip/sipcall.h b/src/sip/sipcall.h index 9d39d9172bc22bd68e02a8c9b18fa22154bbaed3..2f57e01d7270cc3183e086e250f58ba9aae65b49 100644 --- a/src/sip/sipcall.h +++ b/src/sip/sipcall.h @@ -80,7 +80,8 @@ protected: * @param id The call identifier * @param type The type of the call. Could be Incoming or Outgoing */ - SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type); + SIPCall(SIPAccountBase& account, const std::string& id, Call::CallType type, + const std::map<std::string, std::string>& details={}); public: // overridden const char* getLinkType() const override {