Commit ed4bf2fc authored by Guillaume Roguez's avatar Guillaume Roguez

daemon : call refactoring

Refs #52258

Change-Id: I22dec116efc6c033d386c2c845045debca776a0c
parent f8fad9d8
......@@ -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 \
......
......@@ -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();
}
......
/*
* 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);
......
/*
* 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(&timestamp_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);
}
/*
* 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);
......
/*
* 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;
}
/*
* 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
......@@ -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");
......
/*
* 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();
}