diff --git a/daemon/src/Makefile.am b/daemon/src/Makefile.am index e7a13f7655ba1c0786271f77f4046d3383e9f94d..479d5164ce157af1f85376aaa17fcd6ba3e34a78 100644 --- a/daemon/src/Makefile.am +++ b/daemon/src/Makefile.am @@ -75,6 +75,7 @@ libsflphone_la_CFLAGS = \ libsflphone_la_SOURCES = conference.cpp \ account_factory.cpp \ + call_factory.cpp \ preferences.cpp \ managerimpl.cpp \ manager.cpp \ @@ -89,6 +90,7 @@ libsflphone_la_SOURCES = conference.cpp \ threadloop.h \ conference.h \ account factory.h \ + call factory.h \ voiplink.h \ preferences.h \ managerimpl.h \ diff --git a/daemon/src/account.cpp b/daemon/src/account.cpp index 093e5bb39f975e47451d7785943f2a76d854541d..825f8ee921412105f1a87c8b2df3aeb3d9d6dabb 100644 --- a/daemon/src/account.cpp +++ b/daemon/src/account.cpp @@ -108,11 +108,23 @@ Account::Account(const string &accountID) Account::~Account() {} +void +Account::attachCall(const string& id) +{ + callIDSet_.insert(id); +} + +void +Account::detachCall(const string& id) +{ + callIDSet_.erase(id); +} + void Account::freeAccount() { - for (const auto& call : getVoIPLink()->getCalls(accountID_)) - Manager::instance().hangupCall(call->getCallId()); + for (const auto& id : callIDSet_) + Manager::instance().hangupCall(id); unregisterVoIPLink(); } diff --git a/daemon/src/account.h b/daemon/src/account.h index 998c470e8ed81f4e1f28eb389955aa833c73804d..c17e7ee1b3d92cac7a3e4de7d1a8f65e4661b356 100644 --- a/daemon/src/account.h +++ b/daemon/src/account.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -42,6 +43,7 @@ #include <vector> #include <memory> #include <map> +#include <set> class VoIPLink; class Call; @@ -112,14 +114,21 @@ class Account : public Serializable { virtual void unregisterVoIPLink(std::function<void(bool)> cb = std::function<void(bool)>()) = 0; /** - * Create a new outgoing call + * Create a new outgoing call. + * * @param id The ID of the call * @param toUrl The address to call - * @return Call* A pointer on the call + * @return std::shared_ptr<Call> A pointer on the created call */ virtual std::shared_ptr<Call> newOutgoingCall(const std::string& id, const std::string& toUrl) = 0; + /* Note: we forbid incoming call creation from an instance of Account. + * This is why no newIncomingCall() method exist here. + */ + + std::vector<std::shared_ptr<Call> > getCalls(); + /** * Tell if the account is enable or not. * @return true if enabled @@ -210,12 +219,17 @@ class Account : public Serializable { mailBox_ = mb; } + void attachCall(const std::string& id); + + void detachCall(const std::string& id); + static std::vector<std::string> split_string(std::string s); static const char * const VIDEO_CODEC_ENABLED; static const char * const VIDEO_CODEC_NAME; static const char * const VIDEO_CODEC_PARAMETERS; static const char * const VIDEO_CODEC_BITRATE; + private: NON_COPYABLE(Account); @@ -224,8 +238,12 @@ class Account : public Serializable { */ void loadDefaultCodecs(); - protected: + /** + * Set of call's ID attached to the account. + */ + std::set<std::string> callIDSet_ = {}; + protected: static void parseString(const std::map<std::string, std::string> &details, const char *key, std::string &s); static void parseBool(const std::map<std::string, std::string> &details, const char *key, bool &b); diff --git a/daemon/src/call.cpp b/daemon/src/call.cpp index dff059fcb1bd594321efa6c4df47cb787ea0381c..584d9f6ef65ff6320958ca8e2d09ab650cdb9963 100644 --- a/daemon/src/call.cpp +++ b/daemon/src/call.cpp @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -38,8 +39,10 @@ #include "sip/sip_utils.h" #include "ip_utils.h" #include "array_size.h" +#include "map_utils.h" +#include "call_factory.h" -Call::Call(const std::string& id, Call::CallType type, Account& account) +Call::Call(Account& account, const std::string& id, Call::CallType type) : callMutex_() , localAddr_() , localAudioPort_(0) @@ -57,12 +60,22 @@ Call::Call(const std::string& id, Call::CallType type, Account& account) , timestamp_stop_(0) { time(×tamp_start_); + account_.attachCall(id_); } Call::~Call() -{} +{ + account_.detachCall(id_); +} -std::string Call::getAccountId() const +void +Call::removeCall() +{ + Manager::instance().callFactory.removeCall(*this); +} + +const std::string& +Call::getAccountId() const { return account_.getAccountID(); } @@ -299,24 +312,3 @@ Call::getNullDetails() details["ACCOUNTID"] = ""; return details; } - -std::shared_ptr<Call> -Call::newOutgoingCall(const std::string& id, - const std::string& toUrl, - const std::string& preferredAccountId) -{ - std::shared_ptr<Call> call; - std::string toIP = toUrl; - sip_utils::stripSipUriPrefix(toIP); - - if (!IpAddr::isValid(toIP)) { - auto account = Manager::instance().getAccount(preferredAccountId); - if (account) - return account->newOutgoingCall(id, toUrl); - else - WARN("Preferred account %s doesn't exist, using IP2IP account", preferredAccountId.c_str()); - } else - WARN("IP Url detected, using IP2IP account"); - - return Manager::instance().getIP2IPAccount()->newOutgoingCall(id, toIP); -} diff --git a/daemon/src/call.h b/daemon/src/call.h index e8278cbb3bf94c39f82d3f8f85c97be2b1d1c5ee..b2c1526b02ee67adee44c53e9f686fc49a231978 100644 --- a/daemon/src/call.h +++ b/daemon/src/call.h @@ -1,8 +1,9 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +30,7 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ + #ifndef __CALL_H__ #define __CALL_H__ @@ -40,10 +42,14 @@ #include <mutex> #include <map> #include <sstream> +#include <memory> +#include <vector> class VoIPLink; class Account; +template <class T> using CallMap = std::map<std::string, std::shared_ptr<T> >; + /* * @file call.h * @brief A call is the base class for protocol-based calls @@ -74,32 +80,13 @@ class Call : public Recordable { */ enum CallState {INACTIVE, ACTIVE, HOLD, BUSY, ERROR}; - /** - * Constructor of a call - * @param id Unique identifier of the call - * @param type set definitely this call as incoming/outgoing - */ - Call(const std::string& id, Call::CallType type, Account& account); virtual ~Call(); /** - * Create a new outgoing call - * @param id The ID of the call - * @param toUrl The address to call - * @param preferredAccountId The IP of preferred account to use. - * This is not necessary the account used. - * @return Call* A shared pointer on a valid call. - * @note This function raises VoipLinkException() on errors. - */ - static std::shared_ptr<Call> newOutgoingCall(const std::string& id, - const std::string& toUrl, - const std::string& preferredAccountId); - - /** - * Return a copy of the call id + * Return a reference on the call id * @return call id */ - std::string getCallId() const { + const std::string& getCallId() const { return id_; } @@ -107,7 +94,7 @@ class Call : public Recordable { * Return a reference on the conference id * @return call id */ - std::string getConfId() const { + const std::string& getConfId() const { return confID_; } @@ -116,7 +103,7 @@ class Call : public Recordable { } Account& getAccount() const { return account_; } - std::string getAccountId() const; + const std::string& getAccountId() const; CallType getCallType() const { return type_; @@ -313,6 +300,16 @@ class Call : public Recordable { const std::string &from) = 0; #endif + void removeCall(); + + protected: + /** + * Constructor of a call + * @param id Unique identifier of the call + * @param type set definitely this call as incoming/outgoing + */ + Call(Account& account, const std::string& id, Call::CallType type); + private: bool validTransition(CallState newState); diff --git a/daemon/src/call_factory.cpp b/daemon/src/call_factory.cpp new file mode 100644 index 0000000000000000000000000000000000000000..3e29a2640a8005aba3d6caeef782a0a267f5f08b --- /dev/null +++ b/daemon/src/call_factory.cpp @@ -0,0 +1,158 @@ +/* + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#include "call_factory.h" + +#include <stdexcept> + +void +CallFactory::forbid() +{ + allowNewCall_ = false; +} + +void +CallFactory::removeCall(Call& call) +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + const auto& id = call.getCallId(); + DEBUG("Removing call %s", id.c_str()); + const auto& account = call.getAccount(); + auto& map = callMaps_.at(account.getAccountType()); + map.erase(id); + DEBUG("Remaining %u %s call(s)", map.size(), account.getAccountType()); +} + +void +CallFactory::removeCall(const std::string& id) +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + if (auto call = getCall(id)) { + removeCall(*call); + } else + ERROR("No call with ID %s", id.c_str()); +} + +//============================================================================== +// Template specializations (when T = Call) + +template <> bool +CallFactory::hasCall<Call>(const std::string& id) const +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + for (const auto& item : callMaps_) { + const auto& map = item.second; + if (map.find(id) != map.cend()) + return true; + } + + return false; +} + +template <> void +CallFactory::clear<Call>() +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + callMaps_.clear(); +} + +template <> bool +CallFactory::empty<Call>() const +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + for (const auto& item : callMaps_) { + const auto& map = item.second; + if (!map.empty()) + return false; + } + + return true; +} + +template <> std::shared_ptr<Call> +CallFactory::getCall<Call>(const std::string& id) +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + for (const auto& item : callMaps_) { + const auto& map = item.second; + const auto& iter = map.find(id); + if (iter != map.cend()) + return iter->second; + } + + return nullptr; +} + +template <> std::vector<std::shared_ptr<Call> > +CallFactory::getAllCalls<Call>() +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + std::vector<std::shared_ptr<Call> > v; + + for (const auto& itemmap : callMaps_) { + const auto& map = itemmap.second; + for (const auto item : map) + v.push_back(item.second); + } + + v.shrink_to_fit(); + return v; +} + +template <> std::vector<std::string> +CallFactory::getCallIDs<Call>() const { + std::vector<std::string> v; + + for (const auto& item : callMaps_) { + const auto& map = item.second; + for (const auto& it : map) + v.push_back(it.first); + } + + v.shrink_to_fit(); + return v; +} + +template <> std::size_t +CallFactory::callCount<Call>() +{ + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + std::size_t count = 0; + + for (const auto& itemmap : callMaps_) + count += itemmap.second.size(); + + return count; +} diff --git a/daemon/src/call_factory.h b/daemon/src/call_factory.h new file mode 100644 index 0000000000000000000000000000000000000000..fbd6748645f2a06603df06d4078670a1c5452f10 --- /dev/null +++ b/daemon/src/call_factory.h @@ -0,0 +1,242 @@ +/* + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Additional permission under GNU GPL version 3 section 7: + * + * If you modify this program, or any covered work, by linking or + * combining it with the OpenSSL project's OpenSSL library (or a + * modified version of that library), containing parts covered by the + * terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc. + * grants you additional permission to convey the resulting work. + * Corresponding Source for a non-source form of such a combination + * shall include the source code for the parts of OpenSSL used as well + * as that of the covered work. + */ + +#ifndef CALL_FACTORY_H +#define CALL_FACTORY_H + +#include <call.h> +#include <account.h> + +#include <map> +#include <memory> +#include <mutex> +#include <vector> +#include <string> +#include <utility> + +class CallFactory { + public: + /** + * Forbid creation of new calls. + */ + void forbid(); + + /** + * Remove given call instance from call list. + */ + void removeCall(Call& call); + + /** + * Accessor on removeCall with callID than instance. + */ + void removeCall(const std::string& id); + + // Specializations of following template methods for T = Call + // are defined in call.cpp + + /** + * Return if given call exists. Type can optionally be specified. + */ + template <class T = Call> + bool hasCall(const std::string& id) const { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + const auto map = getMap_<T>(); + return map and map->find(id) != map->cend(); + } + + /** + * Create a new call instance of Call class T, using Account class A. + * @param id Unique identifier of the call + * @param type set definitely this call as incoming/outgoing + * @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) { + if (!allowNewCall_) { + WARN("newCall aborted : CallFactory in forbid state"); + return nullptr; + } + + // Trick: std::make_shared<T> can't build as T constructor is protected + // 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) {} + }; + + if (hasCall(id)) { + ERROR("Call %s is already created", id.c_str()); + return nullptr; + } + + auto call = std::make_shared<ConcreteCall>(account, id, type); + + { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + callMaps_[account.getAccountType()].insert(std::make_pair(id, call)); + } + + return call; + } + + /** + * Return if calls exist. Type can optionally be specified. + */ + template <class T = Call> + bool empty() const { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + const auto map = getMap_<T>(); + return !map or map->empty(); + } + + /** + * Erase all calls. Type can optionally be specified. + */ + template <class T = Call> + void clear() { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + auto map = getMap_<T>(); + if (!map) return; + + map->clear(); + } + + /** + * Return call pointer associated to given ID. Type can optionally be specified. + */ + template <class T = Call> + std::shared_ptr<T> getCall(const std::string& id) { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + const auto map = getMap_<T>(); + if (!map) return nullptr; + + const auto& it = map->find(id); + if (it == map->cend()) + return nullptr; + + return std::static_pointer_cast<T>(it->second); + } + + /** + * Return all calls. Type can optionally be specified. + */ + template <class T = Call> + std::vector<std::shared_ptr<T> > getAllCalls() { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + std::vector<std::shared_ptr<T> > v; + + const auto map = getMap_<T>(); + if (map) { + for (const auto& it : *map) + v.push_back(std::static_pointer_cast<T>(it.second)); + } + + v.shrink_to_fit(); + return v; + } + + /** + * Return all call's IDs. Type can optionally be specified. + */ + template <class T = Call> + std::vector<std::string> getCallIDs() const { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + std::vector<std::string> v; + + const auto map = getMap_<T>(); + if (map) { + for (const auto& it : *map) + v.push_back(it.first); + } + + v.shrink_to_fit(); + return v; + } + + /** + * Return number of calls. Type can optionally be specified. + */ + template <class T = Call> + std::size_t callCount() { + std::lock_guard<std::recursive_mutex> lk(callMapsMutex_); + + const auto map = getMap_<T>(); + if (!map) return 0; + + return map->size(); + } + + private: + mutable std::recursive_mutex callMapsMutex_{}; + + std::atomic_bool allowNewCall_{true}; + + std::map<std::string, CallMap<Call> > callMaps_{}; + + template <class T> + const CallMap<Call>* getMap_() const { + const auto& itermap = callMaps_.find(T::LINK_TYPE); + + if (itermap != callMaps_.cend()) + return &itermap->second; + + return nullptr; + } +}; + +// Specializations defined in call_factory.cpp + +template <> bool +CallFactory::hasCall<Call>(const std::string& id) const; + +template <> void +CallFactory::clear<Call>(); + +template <> bool +CallFactory::empty<Call>() const; + +template <> std::shared_ptr<Call> +CallFactory::getCall<Call>(const std::string& id); + +template <> std::vector<std::shared_ptr<Call> > +CallFactory::getAllCalls<Call>(); + +template <> std::vector<std::string> +CallFactory::getCallIDs<Call>() const; + +template <> std::size_t +CallFactory::callCount<Call>(); + +#endif // CALL_FACTORY_H diff --git a/daemon/src/client/callmanager.cpp b/daemon/src/client/callmanager.cpp index 05f3112302e39e5114fc4a4bc7068c63e7d94b54..d1c3ba17a4207d1d6a1e4d63fa38aee851cf2b71 100644 --- a/daemon/src/client/callmanager.cpp +++ b/daemon/src/client/callmanager.cpp @@ -32,6 +32,7 @@ #include "global.h" #include "callmanager.h" +#include "call_factory.h" #include "sip/sipcall.h" #include "sip/sipvoiplink.h" @@ -285,7 +286,7 @@ CallManager::getAudioZrtpSession(const std::string& callID) if (!link) throw CallManagerException("Failed to get sip link"); - auto call = link->getSipCall(callID); + const auto call = Manager::instance().callFactory.getCall<SIPCall>(callID); if (!call) throw CallManagerException("Call id " + callID + " is not valid"); diff --git a/daemon/src/conference.cpp b/daemon/src/conference.cpp index 908b2397ce4e8e78d95d5794f0d892ab9ca6ed58..b681e9b4d4ba769b3ad9a877f121ba11f973fe71 100644 --- a/daemon/src/conference.cpp +++ b/daemon/src/conference.cpp @@ -1,7 +1,7 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author : Alexandre Savard <alexandre.savard@savoirfairelinux.com> - * + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -37,12 +37,13 @@ #include "audio/mainbuffer.h" #ifdef SFL_VIDEO -#include "sip/sipvoiplink.h" #include "sip/sipcall.h" #include "client/videomanager.h" #include "video/video_input.h" #endif +#include "call_factory.h" + #include "logger.h" @@ -61,7 +62,7 @@ Conference::~Conference() { #ifdef SFL_VIDEO for (const auto &participant_id : participants_) { - if (auto call = SIPVoIPLink::instance().getSipCall(participant_id)) + if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id)) call->getVideoRtp().exitConference(); } #endif // SFL_VIDEO @@ -81,7 +82,7 @@ void Conference::add(const std::string &participant_id) { if (participants_.insert(participant_id).second) { #ifdef SFL_VIDEO - if (auto call = SIPVoIPLink::instance().getSipCall(participant_id)) + if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id)) call->getVideoRtp().enterConference(this); #endif // SFL_VIDEO } @@ -91,7 +92,7 @@ void Conference::remove(const std::string &participant_id) { if (participants_.erase(participant_id)) { #ifdef SFL_VIDEO - if (auto call = SIPVoIPLink::instance().getSipCall(participant_id)) + if (auto call = Manager::instance().callFactory.getCall<SIPCall>(participant_id)) call->getVideoRtp().exitConference(); #endif // SFL_VIDEO } diff --git a/daemon/src/iax/iaxaccount.cpp b/daemon/src/iax/iaxaccount.cpp index 2ceaf8e8df4bbbebdfb3035198ec363ca33c86e0..af09a370ba03f3604f3bbc17722a7010771a479b 100644 --- a/daemon/src/iax/iaxaccount.cpp +++ b/daemon/src/iax/iaxaccount.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +44,7 @@ #include "manager.h" #include "config/yamlnode.h" #include "config/yamlemitter.h" +#include "call_factory.h" constexpr const char * const IAXAccount::ACCOUNT_TYPE; @@ -169,10 +171,18 @@ IAXAccount::loadConfig() #endif } -std::shared_ptr<Call> +template <> +std::shared_ptr<IAXCall> +IAXAccount::newIncomingCall(const std::string& id) +{ + return Manager::instance().callFactory.newCall<IAXCall, IAXAccount>(*this, id, Call::INCOMING); +} + +template <> +std::shared_ptr<IAXCall> IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) { - auto call = std::make_shared<IAXCall>(id, Call::OUTGOING, *this, &link_); + auto call = Manager::instance().callFactory.newCall<IAXCall, IAXAccount>(*this, id, Call::OUTGOING); call->setPeerNumber(toUrl); call->initRecFilename(toUrl); @@ -182,11 +192,15 @@ IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) call->setConnectionState(Call::PROGRESSING); call->setState(Call::ACTIVE); - IAXVoIPLink::addIaxCall(call); - return call; } +std::shared_ptr<Call> +IAXAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) +{ + return newOutgoingCall<IAXCall>(id, toUrl); +} + void IAXAccount::iaxOutgoingInvite(IAXCall* call) { diff --git a/daemon/src/iax/iaxaccount.h b/daemon/src/iax/iaxaccount.h index a74286f5602beadcf0ab214ca9d378a18b8fa056..3bea07d430e07bc1beb6803295402484c549d171 100644 --- a/daemon/src/iax/iaxaccount.h +++ b/daemon/src/iax/iaxaccount.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -35,6 +36,9 @@ #include "account.h" #include "iaxvoiplink.h" #include "noncopyable.h" +#include "sfl_types.h" // enable_if_base_of + +class IAXCall; /** * @file: iaxaccount.h @@ -50,15 +54,6 @@ class IAXAccount : public Account { return ACCOUNT_TYPE; } - /** - * Create a new outgoing call - * @param id The ID of the call - * @param toUrl The address to call - * @return Call* A pointer on the call - */ - std::shared_ptr<Call> newOutgoingCall(const std::string& id, - const std::string& toUrl); - virtual void serialize(Conf::YamlEmitter &emitter); virtual void unserialize(const Conf::YamlNode &map); @@ -105,6 +100,36 @@ class IAXAccount : public Account { return &link_; } + /** + * Implementation of Account::newOutgoingCall() + * Note: keep declaration before newOutgoingCall template. + */ + std::shared_ptr<Call> newOutgoingCall(const std::string& id, + const std::string& toUrl); + + /** + * Create outgoing IAXCall. + * @param[in] id The ID of the call + * @param[in] toUrl The address to call + * @return std::shared_ptr<T> A shared pointer on the created call. + * The type of this instance is given in template argument. + * This type can be any base class of IAXCall class (included). + */ + template <class T=IAXCall> + std::shared_ptr<enable_if_base_of<T, IAXCall> > + newOutgoingCall(const std::string& id, const std::string& toUrl); + + /** + * Create incoming IAXCall. + * @param[in] id The ID of the call + * @return std::shared_ptr<T> A shared pointer on the created call. + * The type of this instance is given in template argument. + * This type can be any base class of IAXCall class (included). + */ + template <class T=IAXCall> + std::shared_ptr<enable_if_base_of<T, IAXCall> > + newIncomingCall(const std::string& id); + private: NON_COPYABLE(IAXAccount); diff --git a/daemon/src/iax/iaxcall.cpp b/daemon/src/iax/iaxcall.cpp index b42710d990e47d0d2ffbe9fd612fb62fe4986159..761f5a3cd621b406a00c2ce132d95c5adeedf9d9 100644 --- a/daemon/src/iax/iaxcall.cpp +++ b/daemon/src/iax/iaxcall.cpp @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -44,6 +45,8 @@ #include "im/instant_messaging.h" #endif +const char* const IAXCall::LINK_TYPE = IAXAccount::ACCOUNT_TYPE; + static int codecToASTFormat(int c) { @@ -65,9 +68,11 @@ codecToASTFormat(int c) } } -IAXCall::IAXCall(const std::string& id, Call::CallType type, - IAXAccount& account, IAXVoIPLink* link) : - Call(id, type, account), format(0), session(NULL), link_(link) +IAXCall::IAXCall(IAXAccount& account, const std::string& id, Call::CallType type) + : Call(account, id, type), + format(0), + session(NULL), + link_(static_cast<IAXVoIPLink*>(account.getVoIPLink())) {} int IAXCall::getSupportedFormat(const std::string &accountID) const @@ -157,7 +162,7 @@ IAXCall::hangup(int reason UNUSED) iax_hangup(session, (char*) "Dumped Call"); session = nullptr; - link_->removeIaxCall(getCallId()); + removeCall(); } void @@ -168,7 +173,7 @@ IAXCall::refuse() iax_reject(session, (char*) "Call rejected manually."); } - link_->removeIaxCall(getCallId()); + removeCall(); } void diff --git a/daemon/src/iax/iaxcall.h b/daemon/src/iax/iaxcall.h index 5dfed54e5d879c465f52f3752e77f8d32f1f4be9..b2faf6139711bf91b2629f7589b6d049d5f4d516 100644 --- a/daemon/src/iax/iaxcall.h +++ b/daemon/src/iax/iaxcall.h @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -48,16 +49,20 @@ class IAXAccount; */ class iax_session; -class IAXCall : public Call { +class IAXCall : public Call +{ public: + static const char* const LINK_TYPE; + + protected: /** * Constructor * @param id The unique ID of the call * @param type The type of the call */ - IAXCall(const std::string& id, Call::CallType type, - IAXAccount& account, IAXVoIPLink* link); + IAXCall(IAXAccount& account, const std::string& id, Call::CallType type); + public: /** * @return int The bitwise list of supported formats */ diff --git a/daemon/src/iax/iaxvoiplink.cpp b/daemon/src/iax/iaxvoiplink.cpp index 09487dbc01ac2778080123c0cb13e280487fe10e..d99c683641c3a646cfa143fdf1c377117bee5bc2 100644 --- a/daemon/src/iax/iaxvoiplink.cpp +++ b/daemon/src/iax/iaxvoiplink.cpp @@ -1,7 +1,8 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -28,6 +29,7 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ + #include "iaxvoiplink.h" #include <unistd.h> #include <cmath> @@ -42,9 +44,8 @@ #include "audio/resampler.h" #include "array_size.h" #include "map_utils.h" +#include "call_factory.h" -IAXCallMap IAXVoIPLink::iaxCallMap_; -std::mutex IAXVoIPLink::iaxCallMapMutex_; std::mutex IAXVoIPLink::mutexIAX = {}; IAXVoIPLink::IAXVoIPLink(IAXAccount& account) : @@ -61,10 +62,6 @@ IAXVoIPLink::IAXVoIPLink(IAXAccount& account) : IAXVoIPLink::~IAXVoIPLink() { terminate(); - - // This is our last account - if (Manager::instance().accountCount<IAXAccount>() == 1) - clearIaxCallMap(); } void @@ -88,23 +85,27 @@ IAXVoIPLink::terminate() if (!initDone_) return; - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); handlingEvents_ = false; - for (auto & item : iaxCallMap_) { - auto& call = item.second; - if (call) { - std::lock_guard<std::mutex> lock(mutexIAX); - iax_hangup(call->session, const_cast<char*>("Dumped Call")); - call.reset(); - } + for (const auto& call : Manager::instance().callFactory.getAllCalls<IAXCall>()) { + std::lock_guard<std::mutex> lock(mutexIAX); + iax_hangup(call->session, const_cast<char*>("Dumped Call")); + call->removeCall(); } - iaxCallMap_.clear(); - initDone_ = false; } +static std::shared_ptr<IAXCall> +iaxGetCallFromSession(iax_session* session) +{ + for (auto call : Manager::instance().callFactory.getAllCalls<IAXCall>()) { + if (call->session == session) + return call; + } + return nullptr; +} + bool IAXVoIPLink::handleEvents() { @@ -125,10 +126,8 @@ IAXVoIPLink::handleEvents() continue; } - const std::string id(iaxFindCallIDBySession(event->session)); - - if (not id.empty()) { - iaxHandleCallEvent(event, id); + if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) { + iaxHandleCallEvent(event, raw_call_ptr->getCallId()); } else if (event->session && event->session == account_.getRegSession()) { // This is a registration session, deal with it iaxHandleRegReply(event); @@ -153,34 +152,11 @@ IAXVoIPLink::handleEvents() return handlingEvents_; } -std::vector<std::string> -IAXVoIPLink::getCallIDs() -{ - std::vector<std::string> v; - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - - map_utils::vectorFromMapKeys(iaxCallMap_, v); - return v; -} - -std::vector<std::shared_ptr<Call> > -IAXVoIPLink::getCalls(const std::string &account_id) const -{ - std::vector<std::shared_ptr<Call> > calls; - for (const auto & item : iaxCallMap_) { - if (item.second->getAccountId() == account_id) - calls.push_back(item.second); - } - return calls; -} - void IAXVoIPLink::sendAudioFromMic() { - for (const auto & item : iaxCallMap_) { - auto& currentCall = item.second; - - if (!currentCall or currentCall->getState() != Call::ACTIVE) + for (const auto currentCall : Manager::instance().callFactory.getAllCalls<IAXCall>()) { + if (currentCall->getState() != Call::ACTIVE) continue; int codecType = currentCall->getAudioCodec(); @@ -231,84 +207,22 @@ IAXVoIPLink::sendAudioFromMic() } } -std::shared_ptr<IAXCall> -IAXVoIPLink::getIAXCall(const std::string& id) -{ - return getIaxCall(id); -} - -void -IAXVoIPLink::clearIaxCallMap() -{ - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - iaxCallMap_.clear(); -} - -void -IAXVoIPLink::addIaxCall(std::shared_ptr<IAXCall>& call) -{ - if (call == nullptr) - return; - - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - if (!getIaxCall(call->getCallId())) - iaxCallMap_[call->getCallId()] = std::shared_ptr<IAXCall>(call); -} - -void -IAXVoIPLink::removeIaxCall(const std::string& id) -{ - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - - DEBUG("Removing call %s from list", id.c_str()); - iaxCallMap_.erase(id); -} - -std::shared_ptr<IAXCall> -IAXVoIPLink::getIaxCall(const std::string& id) -{ - IAXCallMap::iterator iter = iaxCallMap_.find(id); - if (iter != iaxCallMap_.end()) - return iter->second; - else - return nullptr; -} - -std::string -IAXVoIPLink::iaxFindCallIDBySession(iax_session* session) -{ - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - - for (const auto & item : iaxCallMap_) { - auto& call = item.second; - - if (call and call->session == session) - return call->getCallId(); - } - - return ""; -} - void IAXVoIPLink::handleReject(const std::string &id) { - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - if (auto call = getIAXCall(id)) { - call->setConnectionState(Call::CONNECTED); - call->setState(Call::ERROR); - } + if (auto call = Manager::instance().callFactory.getCall<IAXCall>(id)) { + call->setConnectionState(Call::CONNECTED); + call->setState(Call::ERROR); + Manager::instance().callFailure(id); + call->removeCall(); } - Manager::instance().callFailure(id); - removeIaxCall(id); } void IAXVoIPLink::handleAccept(iax_event* event, const std::string &id) { if (event->ies.format) { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - if (auto call = getIAXCall(id)) + if (auto call = Manager::instance().callFactory.getCall<IAXCall>(id)) call->format = event->ies.format; } } @@ -316,18 +230,15 @@ IAXVoIPLink::handleAccept(iax_event* event, const std::string &id) void IAXVoIPLink::handleAnswerTransfer(iax_event* event, const std::string &id) { - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - auto call = getIAXCall(id); - if (!call or call->getConnectionState() == Call::CONNECTED) - return; + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call or call->getConnectionState() == Call::CONNECTED) + return; - call->setConnectionState(Call::CONNECTED); - call->setState(Call::ACTIVE); + call->setConnectionState(Call::CONNECTED); + call->setState(Call::ACTIVE); - if (event->ies.format) - call->format = event->ies.format; - } + if (event->ies.format) + call->format = event->ies.format; Manager::instance().addStream(id); Manager::instance().peerAnsweredCall(id); @@ -338,29 +249,27 @@ IAXVoIPLink::handleAnswerTransfer(iax_event* event, const std::string &id) void IAXVoIPLink::handleBusy(const std::string &id) { - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - auto call = getIAXCall(id); - if (!call) - return; - call->setConnectionState(Call::CONNECTED); - call->setState(Call::BUSY); - } + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call) + return; + + call->setConnectionState(Call::CONNECTED); + call->setState(Call::BUSY); + Manager::instance().callBusy(id); - removeIaxCall(id); + call->removeCall(); } void IAXVoIPLink::handleMessage(iax_event* event, const std::string &id) { std::string peerNumber; - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - auto call = getIAXCall(id); - if (!call) - return; - peerNumber = call->getPeerNumber(); - } + + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call) + return; + + peerNumber = call->getPeerNumber(); Manager::instance().incomingMessage(id, peerNumber, std::string((const char*) event->data)); } @@ -368,23 +277,31 @@ IAXVoIPLink::handleMessage(iax_event* event, const std::string &id) void IAXVoIPLink::handleRinging(const std::string &id) { - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - auto call = getIAXCall(id); - if (!call) - return; - call->setConnectionState(Call::RINGING); - } + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call) + return; + + call->setConnectionState(Call::RINGING); Manager::instance().peerRingingCall(id); } void -IAXVoIPLink::iaxHandleCallEvent(iax_event* event, const std::string &id) +IAXVoIPLink::handleHangup(const std::string &id) +{ + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call) + return; + + Manager::instance().peerHungupCall(id); + call->removeCall(); +} + +void +IAXVoIPLink::iaxHandleCallEvent(iax_event* event, const std::string& id) { switch (event->etype) { case IAX_EVENT_HANGUP: - Manager::instance().peerHungupCall(id); - removeIaxCall(id); + handleHangup(id); break; case IAX_EVENT_REJECT: @@ -442,41 +359,38 @@ void IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, const std::string &id) AudioBuffer *out; - { - std::lock_guard<std::mutex> lock(iaxCallMapMutex_); - auto call = getIAXCall(id); - if (!call) - throw VoipLinkException("Could not find call"); + auto call = Manager::instance().callFactory.getCall<IAXCall>(id); + if (!call) + throw VoipLinkException("Could not find call"); - sfl::AudioCodec *audioCodec = static_cast<sfl::AudioCodec *>(Manager::instance().audioCodecFactory.getCodec(call->getAudioCodec())); + sfl::AudioCodec *audioCodec = static_cast<sfl::AudioCodec *>(Manager::instance().audioCodecFactory.getCodec(call->getAudioCodec())); - if (!audioCodec) - return; + if (!audioCodec) + return; - Manager::instance().getMainBuffer().setInternalSamplingRate(audioCodec->getClockRate()); - unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate(); + Manager::instance().getMainBuffer().setInternalSamplingRate(audioCodec->getClockRate()); + unsigned int mainBufferSampleRate = Manager::instance().getMainBuffer().getInternalSamplingRate(); - if (event->subclass) - call->format = event->subclass; + if (event->subclass) + call->format = event->subclass; - unsigned char *data = (unsigned char*) event->data; - unsigned int size = event->datalen; + unsigned char *data = (unsigned char*) event->data; + unsigned int size = event->datalen; - unsigned int max = audioCodec->getClockRate() * 20 / 1000; + unsigned int max = audioCodec->getClockRate() * 20 / 1000; - if (size > max) - size = max; + if (size > max) + size = max; - audioCodec->decode(rawBuffer_.getData(), data , size); - out = &rawBuffer_; - unsigned int audioRate = audioCodec->getClockRate(); + audioCodec->decode(rawBuffer_.getData(), data , size); + out = &rawBuffer_; + unsigned int audioRate = audioCodec->getClockRate(); - if (audioRate != mainBufferSampleRate) { - rawBuffer_.setSampleRate(mainBufferSampleRate); - resampledData_.setSampleRate(audioRate); - resampler_.resample(rawBuffer_, resampledData_); - out = &resampledData_; - } + if (audioRate != mainBufferSampleRate) { + rawBuffer_.setSampleRate(mainBufferSampleRate); + resampledData_.setSampleRate(audioRate); + resampler_.resample(rawBuffer_, resampledData_); + out = &resampledData_; } Manager::instance().getMainBuffer().putData(*out, id); @@ -509,7 +423,7 @@ void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event) case IAX_EVENT_CONNECT: id = Manager::instance().getNewCallID(); - call = std::make_shared<IAXCall>(id, Call::INCOMING, account_, this); + call = account_.newIncomingCall<IAXCall>(id); call->session = event->session; call->setConnectionState(Call::PROGRESSING); @@ -533,17 +447,15 @@ void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event) iax_accept(event->session, format); iax_ring_announce(event->session); - addIaxCall(call); call->format = format; break; case IAX_EVENT_HANGUP: - id = iaxFindCallIDBySession(event->session); - - if (not id.empty()) { + if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) { + id = raw_call_ptr->getCallId(); Manager::instance().peerHungupCall(id); - removeIaxCall(id); + raw_call_ptr->removeCall(); } break; diff --git a/daemon/src/iax/iaxvoiplink.h b/daemon/src/iax/iaxvoiplink.h index 215e0aaff615eeb4ea63fbc7a494ef452cc542c1..712b8c35b42937dbd45fdf40240769cf5f0230ee 100644 --- a/daemon/src/iax/iaxvoiplink.h +++ b/daemon/src/iax/iaxvoiplink.h @@ -1,8 +1,9 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -36,7 +37,6 @@ #include "config.h" #endif -#include <mutex> #include "account.h" #include "voiplink.h" #include "audio/audiobuffer.h" @@ -47,16 +47,13 @@ #include <iax-client.h> +#include <mutex> #include <memory> -class IAXCall; class IAXAccount; - class AudioCodec; class AudioLayer; -typedef std::map<std::string, std::shared_ptr<IAXCall> > IAXCallMap; - /** * @file iaxvoiplink.h * @brief VoIPLink contains a thread that listen to external events @@ -75,11 +72,6 @@ class IAXVoIPLink : public VoIPLink { bool handleEvents(); - /* Returns a list of all callIDs */ - static std::vector<std::string> getCallIDs(); - - std::vector<std::shared_ptr<Call> > getCalls(const std::string &accountId) const; - /** * Init the voip link */ @@ -96,12 +88,6 @@ class IAXVoIPLink : public VoIPLink { */ virtual void cancel(const std::string& /*id*/) {} - static void clearIaxCallMap(); - static void addIaxCall(std::shared_ptr<IAXCall>& call); - // must be called while holding iaxCallMapMutex - static std::shared_ptr<IAXCall> getIaxCall(const std::string& id); - static void removeIaxCall(const std::string &id); - /** Mutex for iax_ calls, since we're the only one dealing with the incorporated * iax_stuff inside this class. */ static std::mutex mutexIAX; @@ -115,9 +101,7 @@ class IAXVoIPLink : public VoIPLink { void handleAnswerTransfer(iax_event* event, const std::string &id); void handleBusy(const std::string &id); void handleMessage(iax_event* event, const std::string &id); - - static std::mutex iaxCallMapMutex_; - static IAXCallMap iaxCallMap_; + void handleHangup(const std::string &id); /* * Decode the message count IAX send. @@ -129,13 +113,6 @@ class IAXVoIPLink : public VoIPLink { int processIAXMsgCount(int msgcount); - /** - * Get IAX Call from an id - * @param id CallId - * @return IAXCall pointer or 0 - */ - std::shared_ptr<IAXCall> getIAXCall(const std::string& id); - /** * Find a iaxcall by iax session number * @param session an iax_session valid pointer diff --git a/daemon/src/manager.cpp b/daemon/src/manager.cpp index 74c93592cbf50f35358c209047d2634e9ef6c54c..cced0b6d50461549e2d4cbd404c4ed8290138b5d 100644 --- a/daemon/src/manager.cpp +++ b/daemon/src/manager.cpp @@ -29,6 +29,7 @@ */ #include "manager.h" +#include "logger.h" ManagerImpl& Manager::instance() { diff --git a/daemon/src/managerimpl.cpp b/daemon/src/managerimpl.cpp index 1c8b6c3420a4dda3d7254334d053254637d30ec9..14efa79e3b54ba5dadec8b3e31e788e5a44f9e35 100644 --- a/daemon/src/managerimpl.cpp +++ b/daemon/src/managerimpl.cpp @@ -48,12 +48,14 @@ #include "voiplink.h" #include "account.h" +#include "call_factory.h" + // FIXME: remove these dependencies #include "sip/sipvoiplink.h" -#include "sip/sipcall.h" +#include "sip/sip_utils.h" + #if HAVE_IAX #include "iax/iaxvoiplink.h" -#include "iax/iaxcall.h" #include "iax/iaxaccount.h" #endif @@ -136,7 +138,7 @@ ManagerImpl::ManagerImpl() : currentCallId_(), currentCallMutex_(), audiodriver_(nullptr), dtmfKey_(), dtmfBuf_(0, AudioFormat::MONO()), toneMutex_(), telephoneTone_(), audiofile_(), audioLayerMutex_(), waitingCalls_(), waitingCallsMutex_(), path_(), - mainBuffer_(), conferenceMap_(), history_(), + mainBuffer_(), callFactory(), conferenceMap_(), history_(), finished_(false), accountFactory_() { @@ -269,15 +271,20 @@ ManagerImpl::finish() finished_ = true; try { + // Forbid call creation + callFactory.forbid(); - std::vector<std::string> callList(getCallList()); - DEBUG("Hangup %zu remaining call(s)", callList.size()); - - for (const auto &item : callList) - hangupCall(item); + // Hangup all remaining active calls + DEBUG("Hangup %zu remaining call(s)", callFactory.callCount()); + for (const auto call : callFactory.getAllCalls()) + hangupCall(call->getCallId()); + callFactory.clear(); + // Save accounts config and call's history saveConfig(); + saveHistory(); + // Disconnect accounts, close link stacks and free allocated ressources unregisterAccounts(); accountFactory_.clear(); SIPVoIPLink::destroy(); @@ -288,8 +295,6 @@ ManagerImpl::finish() delete audiodriver_; audiodriver_ = nullptr; } - - saveHistory(); } catch (const VoipLinkException &err) { ERROR("%s", err.what()); } @@ -331,7 +336,7 @@ void ManagerImpl::switchCall(const std::string& id) /* Main Thread */ bool -ManagerImpl::outgoingCall(const std::string& prefered_account_id, +ManagerImpl::outgoingCall(const std::string& preferred_account_id, const std::string& call_id, const std::string& to, const std::string& conf_id) @@ -373,7 +378,7 @@ ManagerImpl::outgoingCall(const std::string& prefered_account_id, * as the factory may decide to use another account (like IP2IP). */ DEBUG("New outgoing call to %s", to_cleaned.c_str()); - auto call = Call::newOutgoingCall(call_id, to_cleaned, prefered_account_id); + auto call = newOutgoingCall(call_id, to_cleaned, preferred_account_id); // try to reverse match the peer name using the cache if (call->getDisplayName().empty()) { @@ -963,13 +968,7 @@ ManagerImpl::addMainParticipant(const std::string& conference_id) std::shared_ptr<Call> ManagerImpl::getCallFromCallID(const std::string& callID) { - std::shared_ptr<Call> call = SIPVoIPLink::instance().getSipCall(callID); -#if HAVE_IAX - if (!call) - call = IAXVoIPLink::getIaxCall(callID); -#endif - - return call; + return callFactory.getCall(callID); } bool @@ -2594,11 +2593,6 @@ ManagerImpl::loadAccountMap(Conf::YamlParser &parser) std::map<std::string, std::string> ManagerImpl::getCallDetails(const std::string &callID) { - // We need here to retrieve the call information attached to the call ID - // To achieve that, we need to get the voip link attached to the call - // But to achieve that, we need to get the account the call was made with - - // Then the VoIP link this account is linked with (IAX2 or SIP) if (auto call = getCallFromCallID(callID)) { return call->getDetails(); } else { @@ -2617,12 +2611,7 @@ ManagerImpl::getHistory() std::vector<std::string> ManagerImpl::getCallList() const { - std::vector<std::string> v(SIPVoIPLink::instance().getCallIDs()); -#if HAVE_IAX - const std::vector<std::string> iaxCalls(IAXVoIPLink::getCallIDs()); - v.insert(v.end(), iaxCalls.begin(), iaxCalls.end()); -#endif - return v; + return callFactory.getCallIDs(); } std::map<std::string, std::string> @@ -2780,3 +2769,32 @@ ManagerImpl::getVideoManager() return client_.getVideoManager(); } #endif + +std::shared_ptr<Call> +ManagerImpl::newOutgoingCall(const std::string& id, + const std::string& toUrl, + const std::string& preferredAccountId) +{ + std::shared_ptr<Account> account = Manager::instance().getIP2IPAccount(); + std::string finalToUrl = toUrl; + + // FIXME: have a generic version to remove sip dependency + sip_utils::stripSipUriPrefix(finalToUrl); + + if (!IpAddr::isValid(finalToUrl)) { + account = getAccount(preferredAccountId); + if (account) + finalToUrl = toUrl; + else + WARN("Preferred account %s doesn't exist, using IP2IP account", + preferredAccountId.c_str()); + } else + WARN("IP Url detected, using IP2IP account"); + + if (!account) { + ERROR("No suitable account found to create outgoing call"); + return nullptr; + } + + return account->newOutgoingCall(id, finalToUrl); +} diff --git a/daemon/src/managerimpl.h b/daemon/src/managerimpl.h index a7d68ab47fdcf9e1dcb40b3ffbaef74b4e74950b..c313f11a17548e6529c1cc0f80a1507f9d3d81cd 100644 --- a/daemon/src/managerimpl.h +++ b/daemon/src/managerimpl.h @@ -50,9 +50,10 @@ #include "config/sfl_config.h" -#include "call.h" #include "conference.h" + #include "account_factory.h" +#include "call_factory.h" #include "audio/audiolayer.h" #include "audio/sound/tone.h" // for Tone::TONEID declaration @@ -152,7 +153,7 @@ class ManagerImpl { /** * Functions which occur with a user's action * Place a new call - * @param accountId The account to make tha call with + * @param accountId The account to make the call with * @param call_id The call identifier * @param to The recipient of the call * @param conf_id The conference identifier if any @@ -961,6 +962,21 @@ class ManagerImpl { void pollEvents(); + /** + * Create a new outgoing call + * @param id The ID of the call + * @param toUrl The address to call + * @param preferredAccountId The IP of preferred account to use. + * This is not necessary the account used. + * @return Call* A shared pointer on a valid call. + * @note This function raises VoipLinkException() on errors. + */ + std::shared_ptr<Call> newOutgoingCall(const std::string& id, + const std::string& toUrl, + const std::string& preferredAccountId); + + CallFactory callFactory; + private: NON_COPYABLE(ManagerImpl); diff --git a/daemon/src/sfl_types.h b/daemon/src/sfl_types.h index a534c2e1dc3b0d23d4b7347a53ac6751b6aeeb79..855b03a2b597964f0c7fd3393ea4a57ae8d13fc1 100644 --- a/daemon/src/sfl_types.h +++ b/daemon/src/sfl_types.h @@ -33,10 +33,18 @@ #include <cstddef> // for size_t #include <stdint.h> +#include <type_traits> typedef int16_t SFLAudioSample; #define SFL_DATA_FORMAT_MAX SHRT_MAX static const size_t SIZEBUF = 32000; /** About 1s of buffering at 48kHz */ +/** + * This meta-function is used to enable a template overload + * only if given class T is a base of class U + */ +template <class T, class U> +using enable_if_base_of = typename std::enable_if<std::is_base_of<T, U>::value, T>::type; + #endif // SFL_TYPES_H_ diff --git a/daemon/src/sip/sipaccount.cpp b/daemon/src/sip/sipaccount.cpp index 12319b5dae7179a4594a1cc3e76f1c71ae175bb8..5501ce46e5a693b12bff5af8e6b7f5fc0e03b8b6 100644 --- a/daemon/src/sip/sipaccount.cpp +++ b/daemon/src/sip/sipaccount.cpp @@ -1,22 +1,23 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. -* -* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> -* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> -* -* This program is free software; you can redistribute it and/or modify -* it under the terms of the GNU General Public License as published by -* the Free Software Foundation; either version 3 of the License, or -* (at your option) any later version. -* -* This program is distributed in the hope that it will be useful, -* but WITHOUT ANY WARRANTY; without even the implied warranty of -* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -* GNU General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software -* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. + * + * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> + * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * Additional permission under GNU GPL version 3 section 7: * @@ -28,7 +29,7 @@ * Corresponding Source for a non-source form of such a combination * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. -*/ + */ #include "sipaccount.h" @@ -42,6 +43,8 @@ #include "sip_utils.h" #include "array_size.h" +#include "call_factory.h" + #ifdef SFL_PRESENCE #include "sippresence.h" #include "client/configurationmanager.h" @@ -217,9 +220,16 @@ unserializeRange(const Conf::YamlNode &mapNode, const char *minKey, const char * updateRange(tmpMin, tmpMax, range); } -std::shared_ptr<Call> -SIPAccount::newOutgoingCall(const std::string& id, - const std::string& toUrl) +template <> +std::shared_ptr<SIPCall> +SIPAccount::newIncomingCall(const std::string& id) +{ + return Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::INCOMING); +} + +template <> +std::shared_ptr<SIPCall> +SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) { std::string to; std::string toUri; @@ -252,7 +262,7 @@ SIPAccount::newOutgoingCall(const std::string& id, DEBUG("UserAgent: New registered account call to %s", toUrl.c_str()); } - auto call = std::make_shared<SIPCall>(id, Call::OUTGOING, *this); + auto call = Manager::instance().callFactory.newCall<SIPCall, SIPAccount>(*this, id, Call::OUTGOING); call->setIPToIP(isIP2IP()); call->setPeerNumber(toUri); @@ -304,6 +314,12 @@ SIPAccount::newOutgoingCall(const std::string& id, return call; } +std::shared_ptr<Call> +SIPAccount::newOutgoingCall(const std::string& id, const std::string& toUrl) +{ + return newOutgoingCall<SIPCall>(id, toUrl); +} + bool SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call) { @@ -371,7 +387,6 @@ SIPAccount::SIPStartCall(std::shared_ptr<SIPCall>& call) call->setConnectionState(Call::PROGRESSING); call->setState(Call::ACTIVE); - link_.addSipCall(call); return true; } diff --git a/daemon/src/sip/sipaccount.h b/daemon/src/sip/sipaccount.h index c9642eff6f058ceb7b0ea42926a2ce6d55feb87d..5f043f5e3cade1a0a85f37cca3157d12d56484de 100644 --- a/daemon/src/sip/sipaccount.h +++ b/daemon/src/sip/sipaccount.h @@ -43,6 +43,7 @@ #include "account.h" #include "noncopyable.h" #include "ip_utils.h" +#include "sfl_types.h" // enable_if_base_of #include <pjsip/sip_transport_tls.h> #include <pjsip/sip_types.h> @@ -136,21 +137,13 @@ class SIPAccount : public Account { * @param accountID The account identifier */ SIPAccount(const std::string& accountID, bool presenceEnabled); + ~SIPAccount(); const char* getAccountType() const { return ACCOUNT_TYPE; } - /** - * Create a new outgoing call - * @param id The ID of the call - * @param toUrl The address to call - * @return Call* A pointer on the call - */ - std::shared_ptr<Call> newOutgoingCall(const std::string& id, - const std::string& toUrl); - VoIPLink* getVoIPLink(); pjsip_host_port getHostPortFromSTUN(pj_pool_t *pool); @@ -614,6 +607,36 @@ class SIPAccount : public Account { void scheduleReregistration(pjsip_endpoint *endpt); + /** + * Implementation of Account::newOutgoingCall() + * Note: keep declaration before newOutgoingCall template. + */ + std::shared_ptr<Call> newOutgoingCall(const std::string& id, + const std::string& toUrl); + + /** + * Create outgoing SIPCall. + * @param[in] id The ID of the call + * @param[in] toUrl The address to call + * @return std::shared_ptr<T> A shared pointer on the created call. + * The type of this instance is given in template argument. + * This type can be any base class of SIPCall class (included). + */ + template <class T=SIPCall> + std::shared_ptr<enable_if_base_of<T, SIPCall> > + newOutgoingCall(const std::string& id, const std::string& toUrl); + + /** + * Create incoming SIPCall. + * @param[in] id The ID of the call + * @return std::shared_ptr<T> A shared pointer on the created call. + * The type of this instance is given in template argument. + * This type can be any base class of SIPCall class (included). + */ + template <class T=SIPCall> + std::shared_ptr<enable_if_base_of<T, SIPCall> > + newIncomingCall(const std::string& id); + void onRegister(pjsip_regc_cbparam *param); private: diff --git a/daemon/src/sip/sipcall.cpp b/daemon/src/sip/sipcall.cpp index 794e780802f87f636b43a3d41762b1ef3ef08295..361d19827e9d1431dbb304b0fdd0d3fd1f1f14f9 100644 --- a/daemon/src/sip/sipcall.cpp +++ b/daemon/src/sip/sipcall.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -31,6 +32,7 @@ * as that of the covered work. */ +#include "call_factory.h" #include "sipcall.h" #include "sip_utils.h" #include "logger.h" // for _debug @@ -63,6 +65,8 @@ static const int INCREMENT_SIZE = INITIAL_SIZE; * Given a SIP call ID (usefull for transaction sucha as transfer)*/ static std::map<std::string, std::string> transferCallID; +const char* const SIPCall::LINK_TYPE = SIPAccount::ACCOUNT_TYPE; + static void dtmfSend(SIPCall &call, char code, const std::string &dtmf) { @@ -92,9 +96,9 @@ dtmfSend(SIPCall &call, char code, const std::string &dtmf) call.sendSIPInfo(dtmf_body, "dtmf-relay"); } -SIPCall::SIPCall(const std::string& id, Call::CallType type, - SIPAccount& account) : - Call(id, type, account) +SIPCall::SIPCall(SIPAccount& account, const std::string& id, + Call::CallType type) + : Call(account, id, type) , inv(NULL) , audiortp_(this) #ifdef SFL_VIDEO @@ -110,6 +114,16 @@ SIPCall::SIPCall(const std::string& id, Call::CallType type, SIPCall::~SIPCall() { + const auto mod_ua_id = SIPVoIPLink::instance().getModId(); + + // prevent this from getting accessed in callbacks + if (inv->mod_data[mod_ua_id]) { + WARN("Call was not properly removed from invite callbacks"); + + // WARN: this assignation is not thread-safe! + inv->mod_data[mod_ua_id] = nullptr; + } + // local sdp must be destroyed before pool local_sdp_.reset(); pj_pool_release(pool_); @@ -333,7 +347,7 @@ SIPCall::hangup(int reason) // Stop all RTP streams stopRtpIfCurrent(); - siplink.removeSipCall(getCallId()); + removeCall(); } void @@ -357,7 +371,7 @@ SIPCall::refuse() // Make sure the pointer is NULL in callbacks inv->mod_data[siplink.getModId()] = NULL; - siplink.removeSipCall(getCallId()); + removeCall(); } static void @@ -684,7 +698,7 @@ SIPCall::onServerFailure() { const std::string id(getCallId()); Manager::instance().callFailure(id); - SIPVoIPLink::instance().removeSipCall(id); + removeCall(); } void @@ -692,7 +706,7 @@ SIPCall::onClosed() { const std::string id(getCallId()); Manager::instance().peerHungupCall(id); - SIPVoIPLink::instance().removeSipCall(id); + removeCall(); Manager::instance().checkAudio(); } diff --git a/daemon/src/sip/sipcall.h b/daemon/src/sip/sipcall.h index 5c8079d3372d111c3a8e3c794ae2ba7549b4bcae..34aa380375f12508bd75ec01fcde9a5a7ce699fd 100644 --- a/daemon/src/sip/sipcall.h +++ b/daemon/src/sip/sipcall.h @@ -1,8 +1,9 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> * Author : Laurielle Lea <laurielle.lea@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -29,6 +30,7 @@ * shall include the source code for the parts of OpenSSL used as well * as that of the covered work. */ + #ifndef __SIPCALL_H__ #define __SIPCALL_H__ @@ -60,18 +62,21 @@ class SIPAccount; * @file sipcall.h * @brief SIPCall are SIP implementation of a normal Call */ -class SIPCall : public Call { +class SIPCall : public Call +{ public: + static const char* const LINK_TYPE; + protected: /** - * Constructor + * Constructor (protected) * @param id The call identifier * @param type The type of the call. Could be Incoming * Outgoing */ - SIPCall(const std::string& id, Call::CallType type, - SIPAccount& account); + SIPCall(SIPAccount& account, const std::string& id, Call::CallType type); + public: /** * Destructor */ @@ -166,13 +171,12 @@ class SIPCall : public Call { void onClosed(); private: + NON_COPYABLE(SIPCall); // override of Call::createHistoryEntry std::map<std::string, std::string> createHistoryEntry() const; - NON_COPYABLE(SIPCall); - void stopRtpIfCurrent(); /** diff --git a/daemon/src/sip/sipvoiplink.cpp b/daemon/src/sip/sipvoiplink.cpp index 2510e5dbc1fbe9a91bd84bc4553884beaed955d8..3b621bf9b13238ae978051bd359a5efce9df375e 100644 --- a/daemon/src/sip/sipvoiplink.cpp +++ b/daemon/src/sip/sipvoiplink.cpp @@ -1,9 +1,10 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Yun Liu <yun.liu@savoirfairelinux.com> * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -41,6 +42,8 @@ #include "sipcall.h" #include "sip_utils.h" +#include "call_factory.h" + #include "manager.h" #if HAVE_SDES #include "sdes_negotiator.h" @@ -48,7 +51,6 @@ #include "logger.h" #include "array_size.h" -#include "map_utils.h" #include "ip_utils.h" #if HAVE_INSTANT_MESSAGING @@ -282,8 +284,7 @@ transaction_request_cb(pjsip_rx_data *rdata) Manager::instance().hookPreference.runHook(rdata->msg_info.msg); - auto call = std::make_shared<SIPCall>(Manager::instance().getNewCallID(), - Call::INCOMING, *sipaccount); + auto call = sipaccount->newIncomingCall<SIPCall>(Manager::instance().getNewCallID()); // FIXME : for now, use the same address family as the SIP tranport auto family = pjsip_transport_type_get_af(sipaccount->getTransportType()); @@ -459,7 +460,6 @@ transaction_request_cb(pjsip_rx_data *rdata) call->setConnectionState(Call::RINGING); - SIPVoIPLink::instance().addSipCall(call); Manager::instance().incomingCall(*call, account_id); } @@ -482,8 +482,8 @@ pj_pool_t* SIPVoIPLink::getPool() const return pool_; } -SIPVoIPLink::SIPVoIPLink() : sipTransport(), - sipCallMapMutex_(), sipCallMap_() +SIPVoIPLink::SIPVoIPLink() + : sipTransport() #ifdef SFL_VIDEO , keyframeRequestsMutex_() , keyframeRequests_() @@ -587,7 +587,9 @@ SIPVoIPLink::~SIPVoIPLink() const pj_time_val tv = {0, 10}; pjsip_endpt_handle_events(endpt_, &tv); - clearSipCallMap(); + if (!Manager::instance().callFactory.empty<SIPCall>()) + ERROR("%d SIP calls remains!", + Manager::instance().callFactory.callCount<SIPCall>()); // destroy SIP transport before endpoint sipTransport.reset(); @@ -720,105 +722,6 @@ void SIPVoIPLink::cancelKeepAliveTimer(pj_timer_entry& timer) pjsip_endpt_cancel_timer(endpt_, &timer); } -void -SIPVoIPLink::clearSipCallMap() -{ - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - sipCallMap_.clear(); -} - -std::vector<std::string> -SIPVoIPLink::getCallIDs() -{ - std::vector<std::string> v; - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - - map_utils::vectorFromMapKeys(sipCallMap_, v); - return v; -} - -std::vector<std::shared_ptr<Call> > -SIPVoIPLink::getCalls(const std::string &account_id) const -{ - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - - std::vector<std::shared_ptr<Call> > calls; - for (const auto & item : sipCallMap_) { - if (item.second->getAccountId() == account_id) - calls.push_back(item.second); - } - return calls; -} - -void SIPVoIPLink::addSipCall(std::shared_ptr<SIPCall>& call) -{ - if (!call) - return; - - const std::string id(call->getCallId()); - - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - - // emplace C++11 method has been implemented in GCC 4.8.0 - // see https://gcc.gnu.org/bugzilla/show_bug.cgi?id=44436 -#if !defined(__GNUC__) or (__GNUC__ >= 4 && __GNUC_MINOR__ >= 8) - if (not sipCallMap_.emplace(id, call).second) -#else - if (sipCallMap_.find(id) == sipCallMap_.end()) { - sipCallMap_[id] = call; - } else -#endif - ERROR("Call %s is already in the call map", id.c_str()); - -} - -void SIPVoIPLink::removeSipCall(const std::string& id) -{ - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - - DEBUG("Removing call %s from list", id.c_str()); - SipCallMap::iterator iter = sipCallMap_.find(id); - if (iter != sipCallMap_.end()) { - auto count = iter->second.use_count(); - if (count > 1) - WARN("removing a used SIPCall (by %d holders)", count); - } - sipCallMap_.erase(id); -} - -std::shared_ptr<SIPCall> -SIPVoIPLink::getSipCall(const std::string& id) -{ - std::lock_guard<std::mutex> lock(sipCallMapMutex_); - - SipCallMap::iterator iter = sipCallMap_.find(id); - - if (iter != sipCallMap_.end()) - return iter->second; - else { - DEBUG("No SIP call with ID %s", id.c_str()); - return nullptr; - } -} - -std::shared_ptr<SIPCall> -SIPVoIPLink::tryGetSIPCall(const std::string& id) -{ - std::shared_ptr<SIPCall> call; - - if (sipCallMapMutex_.try_lock()) { - SipCallMap::iterator iter = sipCallMap_.find(id); - - if (iter != sipCallMap_.end()) - call = iter->second; - - sipCallMapMutex_.unlock(); - } else - ERROR("Could not acquire SIPCallMap mutex"); - - return call; -} - #ifdef SFL_VIDEO // Called from a video thread void @@ -850,7 +753,7 @@ SIPVoIPLink::requestKeyframe(const std::string &callID) const int tries = 10; for (int i = 0; !call and i < tries; ++i) - call = SIPVoIPLink::instance().tryGetSIPCall(callID); + call = Manager::instance().callFactory.getCall<SIPCall>(callID); // fixme: need a try version if (!call) return; @@ -1353,10 +1256,10 @@ onCallTransfered(pjsip_inv_session *inv, pjsip_rx_data *rdata) } try { - Call::newOutgoingCall(Manager::instance().getNewCallID(), - std::string(refer_to->hvalue.ptr, - refer_to->hvalue.slen), - currentCall->getAccountId()); + Manager::instance().newOutgoingCall(Manager::instance().getNewCallID(), + std::string(refer_to->hvalue.ptr, + refer_to->hvalue.slen), + currentCall->getAccountId()); Manager::instance().hangupCall(currentCall->getCallId()); } catch (const VoipLinkException &e) { ERROR("%s", e.what()); diff --git a/daemon/src/sip/sipvoiplink.h b/daemon/src/sip/sipvoiplink.h index 4f234d9af83283e3148323119a01b1a24bae662e..a6b4d98870a12e8b713f5a5409c6af8fe6214b42 100644 --- a/daemon/src/sip/sipvoiplink.h +++ b/daemon/src/sip/sipvoiplink.h @@ -1,10 +1,11 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Yun Liu <yun.liu@savoirfairelinux.com> * Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com> * Author: Alexandre Savard <alexandre.savard@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -104,8 +105,6 @@ class SIPVoIPLink : public VoIPLink { /* Returns a list of all callIDs */ std::vector<std::string> getCallIDs(); - std::vector<std::shared_ptr<Call> > getCalls(const std::string &account_id) const; - /** * Register a new keepalive registration timer to this endpoint */ @@ -128,23 +127,6 @@ class SIPVoIPLink : public VoIPLink { */ pj_caching_pool *getMemoryPoolFactory(); - void clearSipCallMap(); - void addSipCall(std::shared_ptr<SIPCall>& call); - - std::shared_ptr<SIPCall> getSipCall(const std::string& id); - - /** - * A non-blocking SIPCall accessor - * - * Will return NULL if the callMapMutex could not be locked - * - * @param id The call identifier - * @return SIPCall* A pointer to the SIPCall object - */ - std::shared_ptr<SIPCall> tryGetSIPCall(const std::string &id); - - void removeSipCall(const std::string &id); - /** * Create the default UDP transport according ot Ip2Ip profile settings */ @@ -185,9 +167,6 @@ class SIPVoIPLink : public VoIPLink { SIPVoIPLink(); ~SIPVoIPLink(); - mutable std::mutex sipCallMapMutex_; - SipCallMap sipCallMap_; - #ifdef SFL_VIDEO void dequeKeyframeRequests(); void requestKeyframe(const std::string &callID); diff --git a/daemon/src/video/video_input.cpp b/daemon/src/video/video_input.cpp index fdcd3a43f78a04ce8f5eefe485e5927dfe250a58..ea08a20c7186e7ea4a6e9653ea4d8d9a7a9dc810 100644 --- a/daemon/src/video/video_input.cpp +++ b/daemon/src/video/video_input.cpp @@ -38,6 +38,8 @@ #include <map> #include <string> +#include <cassert> +#include <unistd.h> namespace sfl_video { diff --git a/daemon/src/video/video_mixer.cpp b/daemon/src/video/video_mixer.cpp index 045672b7e11319d71103c535686a230180bc38ad..4aa7d3547109d4a802410d60d0f5817c4466c985 100644 --- a/daemon/src/video/video_mixer.cpp +++ b/daemon/src/video/video_mixer.cpp @@ -37,6 +37,7 @@ #include "logger.h" #include <cmath> +#include <unistd.h> static const double FRAME_DURATION = 1/30.; diff --git a/daemon/src/voiplink.h b/daemon/src/voiplink.h index fd98442975e23721ad6867203a9946f0f882694c..aa5d61da7f3b06dd25206620c8c3878dbc328578 100644 --- a/daemon/src/voiplink.h +++ b/daemon/src/voiplink.h @@ -1,9 +1,10 @@ /* - * Copyright (C) 2004-2013 Savoir-Faire Linux Inc. + * Copyright (C) 2004-2014 Savoir-Faire Linux Inc. * * Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com> * Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com> * Author: Yan Morin <yan.morin@savoirfairelinux.com> + * Author : Guillaume Roguez <guillaume.roguez@savoirfairelinux.com> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -34,16 +35,8 @@ #ifndef __VOIP_LINK_H__ #define __VOIP_LINK_H__ -#include "account.h" - #include <stdexcept> -#include <functional> #include <string> -#include <vector> -#include <memory> - -class Call; -class Account; class VoipLinkException : public std::runtime_error { public: @@ -66,12 +59,6 @@ class VoIPLink { */ virtual bool handleEvents() = 0; - /** - * Virtual method - * Returns calls involving this account. - */ - virtual std::vector<std::shared_ptr<Call> > getCalls(const std::string &account_id) const = 0; - protected: bool handlingEvents_ = false; }; diff --git a/daemon/test/siptest.cpp b/daemon/test/siptest.cpp index 22ed5bbec1b2c6f72654aa4a503c5406bddbb9f0..abe01882c437c7c2e0512c34620d0290d6dc7ffe 100644 --- a/daemon/test/siptest.cpp +++ b/daemon/test/siptest.cpp @@ -41,6 +41,7 @@ #include "manager.h" #include "sip/sipvoiplink.h" #include "sip/sip_utils.h" +#include "sip/sipcall.h" // anonymous namespace namespace { @@ -176,15 +177,12 @@ void SIPTest::testSimpleIncomingIpCall() // the incoming invite. sleep(2); - // gtrab call id from sipvoiplink - SIPVoIPLink& siplink = SIPVoIPLink::instance(); - - CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1); - SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin(); - std::string testcallid = iterCallId->first; + CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1); // Answer this call - CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid)); + const auto& calls = Manager::instance().callFactory.getAllCalls<SIPCall>(); + const auto call = *calls.cbegin(); + CPPUNIT_ASSERT(Manager::instance().answerCall(call->getCallId())); sleep(1); @@ -284,15 +282,13 @@ void SIPTest::testTwoIncomingIpCall() // the incoming invite. sleep(1); - // gtrab call id from sipvoiplink - SIPVoIPLink& sipLink = SIPVoIPLink::instance(); - - CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 1); - SipCallMap::iterator iterCallId = sipLink.sipCallMap_.begin(); - std::string firstCallID = iterCallId->first; + CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1); // Answer this call - CPPUNIT_ASSERT(Manager::instance().answerCall(firstCallID)); + auto calls = Manager::instance().callFactory.getCallIDs<SIPCall>(); + auto iterCallId = calls.cbegin(); + const auto& firstCallId = *iterCallId; + CPPUNIT_ASSERT(Manager::instance().answerCall(firstCallId)); sleep(1); pthread_t secondCallThread; @@ -303,13 +299,13 @@ void SIPTest::testTwoIncomingIpCall() sleep(1); - CPPUNIT_ASSERT(sipLink.sipCallMap_.size() == 2); - iterCallId = sipLink.sipCallMap_.begin(); - - if (iterCallId->first == firstCallID) + CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 2); + calls = Manager::instance().callFactory.getCallIDs<SIPCall>(); + iterCallId = calls.cbegin(); + if (*iterCallId == firstCallId) ++iterCallId; - std::string secondCallID(iterCallId->first); + std::string secondCallID(*iterCallId); CPPUNIT_ASSERT(Manager::instance().answerCall(secondCallID)); @@ -411,19 +407,16 @@ void SIPTest::testIncomingIpCallSdp() // the incoming invite. sleep(2); - // gtrab call id from sipvoiplink - SIPVoIPLink& siplink = SIPVoIPLink::instance(); + CPPUNIT_ASSERT(Manager::instance().callFactory.callCount<SIPCall>() == 1); - CPPUNIT_ASSERT(siplink.sipCallMap_.size() == 1); - SipCallMap::iterator iterCallId = siplink.sipCallMap_.begin(); - std::string testcallid = iterCallId->first; + // Answer this call + const auto& calls = Manager::instance().callFactory.getAllCalls<SIPCall>(); // TODO: hmmm, should IP2IP call be stored in call list.... CPPUNIT_ASSERT(Manager::instance().getCallList().empty()); // Answer this call - CPPUNIT_ASSERT(Manager::instance().answerCall(testcallid)); - + CPPUNIT_ASSERT(Manager::instance().answerCall((*calls.cbegin())->getCallId())); sleep(1);