removing IAX account and libiax dependency

This patch removes all IAX account code and libiax dependency in contrib.
References in documentation have also been removed where needed.

Change-Id: Ifff23725ccf7e1a6820dbc6f57256138a0fca042
Tuleap: #813
This commit is contained in:
Guillaume Roguez
2016-06-30 10:02:22 -04:00
committed by gerrit2
parent 7479d74ce5
commit 36e857fcf0
29 changed files with 12 additions and 1560 deletions

2
README
View File

@ -22,7 +22,7 @@ Introduction
Ring is a Voice-over-IP software phone. We want it to be: Ring is a Voice-over-IP software phone. We want it to be:
- user friendly (fast, sleek, easy to learn interface) - user friendly (fast, sleek, easy to learn interface)
- professional grade (transfers, holds, optimal audio quality) - professional grade (transfers, holds, optimal audio quality)
- fully compatible with Asterisk (SIP and IAX protocols) - compatible with Asterisk (using SIP account)
- de-centralized call (P2P-DHT) - de-centralized call (P2P-DHT)
- customizable - customizable

View File

@ -31,7 +31,7 @@
<ul> <ul>
<li>CONFIG_ACCOUNT_ENABLE: True or False (Default: True)</li> <li>CONFIG_ACCOUNT_ENABLE: True or False (Default: True)</li>
<li>CONFIG_ACCOUNT_RESOLVE_ONCE</li> <li>CONFIG_ACCOUNT_RESOLVE_ONCE</li>
<li>CONFIG_ACCOUNT_TYPE: SIP or IAX2 (Default: SIP)</li> <li>CONFIG_ACCOUNT_TYPE: SIP or RING</li>
<li>HOSTNAME: The IP adress or hostname of the registrar</li> <li>HOSTNAME: The IP adress or hostname of the registrar</li>
<li>USERNAME: The username (or extension) of the account</li> <li>USERNAME: The username (or extension) of the account</li>
<li>PASSWORD: The password associated to the account</li> <li>PASSWORD: The password associated to the account</li>
@ -621,11 +621,6 @@
<!-- General Settings Panel --> <!-- General Settings Panel -->
<method name="isIax2Enabled" tp:name-for-bindings="isIax2Enabled">
<arg type="i" name="res" direction="out">
</arg>
</method>
<method name="getHistoryLimit" tp:name-for-bindings="getHistoryLimit"> <method name="getHistoryLimit" tp:name-for-bindings="getHistoryLimit">
<arg type="i" name="days" direction="out"> <arg type="i" name="days" direction="out">
</arg> </arg>

View File

@ -325,12 +325,6 @@ DBusConfigurationManager::getSupportedAudioManagers()
}; };
} }
auto
DBusConfigurationManager::isIax2Enabled() -> decltype(DRing::isIax2Enabled())
{
return DRing::isIax2Enabled();
}
auto auto
DBusConfigurationManager::getRecordPath() -> decltype(DRing::getRecordPath()) DBusConfigurationManager::getRecordPath() -> decltype(DRing::getRecordPath())
{ {

View File

@ -103,7 +103,6 @@ class DBusConfigurationManager :
std::string getAudioManager(); std::string getAudioManager();
bool setAudioManager(const std::string& api); bool setAudioManager(const std::string& api);
std::vector<std::string> getSupportedAudioManagers(); std::vector<std::string> getSupportedAudioManagers();
int32_t isIax2Enabled();
std::string getRecordPath(); std::string getRecordPath();
void setRecordPath(const std::string& recPath); void setRecordPath(const std::string& recPath);
bool getIsAlwaysRecording(); bool getIsAlwaysRecording();

View File

@ -530,22 +530,6 @@ AS_CASE(["$with_opus"],
[PKG_CHECK_MODULES([opus], [opus], [HAVE_OPUS=1], [HAVE_OPUS=0])]) [PKG_CHECK_MODULES([opus], [opus], [HAVE_OPUS=1], [HAVE_OPUS=0])])
AM_CONDITIONAL([BUILD_OPUS], [test "$HAVE_OPUS" -eq 1]) AM_CONDITIONAL([BUILD_OPUS], [test "$HAVE_OPUS" -eq 1])
AC_ARG_WITH([iax],
AS_HELP_STRING([--without-iax], [Ignore presence of iax and disable it]))
AS_IF([test "x$with_iax" != "xno"],
[AC_CHECK_HEADER("iax/iax-client.h", [have_iax=yes], [have_iax=no])],
[have_iax=no])
# only fail if IAX was explicitly requested but not found
AS_IF([test "x$have_iax" = "xyes"],
[AC_DEFINE([HAVE_IAX], 1, [Define if you have libiax])
AM_CONDITIONAL(USE_IAX, `true`)],
[AS_IF([test "x$with_iax" = "xyes"],
[AC_MSG_ERROR([iax requested but not found])])
AC_DEFINE([HAVE_IAX], 0, [Define if you have libiax])
AM_CONDITIONAL(USE_IAX, `false`)])
# dht is default-enabled, but requires gnutls # dht is default-enabled, but requires gnutls
AC_ARG_ENABLE([dht], AC_ARG_ENABLE([dht],
AS_HELP_STRING([--disable-dht], [disable support for dht])) AS_HELP_STRING([--disable-dht], [disable support for dht]))
@ -617,7 +601,6 @@ AC_CONFIG_FILES([Makefile \
src/Makefile \ src/Makefile \
src/sip/Makefile \ src/sip/Makefile \
src/im/Makefile \ src/im/Makefile \
src/iax/Makefile \
src/ringdht/Makefile \ src/ringdht/Makefile \
src/media/Makefile \ src/media/Makefile \
src/media/audio/Makefile \ src/media/audio/Makefile \

View File

@ -1,25 +0,0 @@
#IAX
IAX_VERSION = 0e5980f1d78ce462e2d1ed6bc39ff35c8341f201
IAX_URL = https://gitlab.savoirfairelinux.com/sflphone/libiax2/repository/archive.tar.gz?ref=$(IAX_VERSION)
PKGS += iax
$(TARBALLS)/iax-git.tar.gz:
$(call download,$(IAX_URL))
.sum-iax: iax-git.tar.gz
$(warning $@ not implemented)
touch $@
iax: iax-git.tar.gz .sum-iax
$(UNPACK)
mv libiax2-$(IAX_VERSION)-$(IAX_VERSION) $@
touch $@
.iax: iax
$(RECONF)
cd $< && $(HOSTVARS) ./configure $(HOSTCONF)
cd $< && $(MAKE) install
touch $@

View File

@ -28,14 +28,6 @@ INSTANT_MESSAGING_SUBDIR = im
IM_LIBA=./im/libim.la IM_LIBA=./im/libim.la
endif endif
# Redefine the USE_IAX variable here, so that it could be used in manager
if USE_IAX
IAX_SUBDIR=iax
IAX_CXXFLAG=-DUSE_IAX
IAX_LIBA=./iax/libiaxlink.la
IAX_LIB=-liax
endif
if USE_DHT if USE_DHT
RINGACC_SUBDIR=ringdht RINGACC_SUBDIR=ringdht
RINGACC_CXXFLAG=-DUSE_DHT RINGACC_CXXFLAG=-DUSE_DHT
@ -47,7 +39,7 @@ TLS_LIB = @GNUTLS_LIBS@
TLS_CFLAGS = @GNUTLS_CFLAGS@ TLS_CFLAGS = @GNUTLS_CFLAGS@
endif endif
SUBDIRS = client media config hooks sip upnp security $(IAX_SUBDIR) $(RINGACC_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(RING_VIDEO_SUBDIR) SUBDIRS = client media config hooks sip upnp security $(RINGACC_SUBDIR) $(INSTANT_MESSAGING_SUBDIR) $(RING_VIDEO_SUBDIR)
# libring # libring
@ -62,7 +54,6 @@ libring_la_LIBADD = \
./security/libsecurity.la \ ./security/libsecurity.la \
./upnp/libupnpcontrol.la \ ./upnp/libupnpcontrol.la \
$(RINGACC_LIBA) \ $(RINGACC_LIBA) \
$(IAX_LIBA) \
$(IM_LIBA) \ $(IM_LIBA) \
$(RING_VIDEO_LIBS) $(RING_VIDEO_LIBS)
@ -78,7 +69,6 @@ libring_la_LDFLAGS = \
@LIBUPNP_LIBS@ \ @LIBUPNP_LIBS@ \
@PORTAUDIO_LIBS@ \ @PORTAUDIO_LIBS@ \
$(TLS_LIB) \ $(TLS_LIB) \
$(IAX_LIB) \
$(IM_LIB) \ $(IM_LIB) \
$(PCRE_LIBS) $(PCRE_LIBS)

View File

@ -257,7 +257,7 @@ Account::unserialize(const YAML::Node& node)
void void
Account::setAccountDetails(const std::map<std::string, std::string> &details) Account::setAccountDetails(const std::map<std::string, std::string> &details)
{ {
// Account setting common to SIP and IAX // Account setting common to any account type
parseString(details, Conf::CONFIG_ACCOUNT_ALIAS, alias_); parseString(details, Conf::CONFIG_ACCOUNT_ALIAS, alias_);
parseString(details, Conf::CONFIG_ACCOUNT_DISPLAYNAME, displayName_); parseString(details, Conf::CONFIG_ACCOUNT_DISPLAYNAME, displayName_);
parseBool(details, Conf::CONFIG_ACCOUNT_ENABLE, enabled_); parseBool(details, Conf::CONFIG_ACCOUNT_ENABLE, enabled_);

View File

@ -72,7 +72,7 @@ class VoipLinkException : public std::runtime_error
/** /**
* @file account.h * @file account.h
* @brief Interface to protocol account (SIPAccount, IAXAccount) * @brief Interface to protocol account (ex: SIPAccount)
* It can be enable on loading or activate after. * It can be enable on loading or activate after.
* It contains account, configuration, VoIP Link and Calls (inside the VoIPLink) * It contains account, configuration, VoIP Link and Calls (inside the VoIPLink)
*/ */

View File

@ -25,9 +25,6 @@
#include "account_factory.h" #include "account_factory.h"
#include "sip/sipaccount.h" #include "sip/sipaccount.h"
#if HAVE_IAX
#include "iax/iaxaccount.h"
#endif
#if HAVE_DHT #if HAVE_DHT
#include "ringdht/ringaccount.h" #include "ringdht/ringaccount.h"
#endif #endif
@ -43,11 +40,6 @@ AccountFactory::AccountFactory()
auto sipfunc = [](const std::string& id){ return std::make_shared<SIPAccount>(id, true); }; auto sipfunc = [](const std::string& id){ return std::make_shared<SIPAccount>(id, true); };
generators_.insert(std::make_pair(SIPAccount::ACCOUNT_TYPE, sipfunc)); generators_.insert(std::make_pair(SIPAccount::ACCOUNT_TYPE, sipfunc));
RING_DBG("registered %s account", SIPAccount::ACCOUNT_TYPE); RING_DBG("registered %s account", SIPAccount::ACCOUNT_TYPE);
#if HAVE_IAX
auto iaxfunc = [](const std::string& id){ return std::make_shared<IAXAccount>(id); };
generators_.insert(std::make_pair(IAXAccount::ACCOUNT_TYPE, iaxfunc));
RING_DBG("registered %s account", IAXAccount::ACCOUNT_TYPE);
#endif
#if HAVE_DHT #if HAVE_DHT
auto dhtfunc = [](const std::string& id){ return std::make_shared<RingAccount>(id, false); }; auto dhtfunc = [](const std::string& id){ return std::make_shared<RingAccount>(id, false); };
generators_.insert(std::make_pair(RingAccount::ACCOUNT_TYPE, dhtfunc)); generators_.insert(std::make_pair(RingAccount::ACCOUNT_TYPE, dhtfunc));

View File

@ -38,9 +38,6 @@
#include "ip_utils.h" #include "ip_utils.h"
#include "sip/sipaccount.h" #include "sip/sipaccount.h"
#include "ringdht/ringaccount.h" #include "ringdht/ringaccount.h"
#if HAVE_IAX
#include "iax/iaxaccount.h"
#endif
#include "audio/audiolayer.h" #include "audio/audiolayer.h"
#include "system_codec_container.h" #include "system_codec_container.h"
#include "account_const.h" #include "account_const.h"
@ -350,10 +347,6 @@ getAccountTemplate(const std::string& accountType)
return ring::RingAccount("dummy", false).getAccountDetails(); return ring::RingAccount("dummy", false).getAccountDetails();
else if (accountType == Account::ProtocolNames::SIP) else if (accountType == Account::ProtocolNames::SIP)
return ring::SIPAccount("dummy", false).getAccountDetails(); return ring::SIPAccount("dummy", false).getAccountDetails();
#if HAVE_IAX
else if (accountType == Account::ProtocolNames::IAX)
return ring::IAXAccount("dummy").getAccountDetails();
#endif
return {}; return {};
} }
@ -600,12 +593,6 @@ setAgcState(bool enabled)
ring::Manager::instance().setAGCState(enabled); ring::Manager::instance().setAGCState(enabled);
} }
int32_t
isIax2Enabled()
{
return HAVE_IAX;
}
std::string std::string
getRecordPath() getRecordPath()
{ {

View File

@ -33,7 +33,6 @@ namespace Account {
namespace ProtocolNames { namespace ProtocolNames {
constexpr static const char SIP [] = "SIP"; constexpr static const char SIP [] = "SIP";
constexpr static const char IAX [] = "IAX";
constexpr static const char IP2IP [] = "IP2IP"; constexpr static const char IP2IP [] = "IP2IP";
constexpr static const char RING [] = "RING"; constexpr static const char RING [] = "RING";

View File

@ -94,7 +94,6 @@ void muteRingtone(bool mute);
std::string getAudioManager(); std::string getAudioManager();
bool setAudioManager(const std::string& api); bool setAudioManager(const std::string& api);
int32_t isIax2Enabled();
std::string getRecordPath(); std::string getRecordPath();
void setRecordPath(const std::string& recPath); void setRecordPath(const std::string& recPath);
bool getIsAlwaysRecording(); bool getIsAlwaysRecording();

View File

@ -1,21 +0,0 @@
include $(top_srcdir)/globals.mak
if USE_IAX
noinst_LTLIBRARIES = libiaxlink.la
libiaxlink_la_SOURCES = \
iaxaccount.cpp \
iaxcall.cpp \
iaxvoiplink.cpp
libiaxlink_la_CXXFLAGS = \
-DUSE_IAX
noinst_HEADERS = \
iaxaccount.h \
iaxcall.h \
iaxvoiplink.h
endif

View File

@ -1,232 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "iaxaccount.h"
#include "account_schema.h"
#include "iaxvoiplink.h"
#include "iaxcall.h"
#include "logger.h"
#include "manager.h"
#include "call_factory.h"
#include "intrin.h"
#include "config/yamlparser.h"
#include <yaml-cpp/yaml.h>
namespace ring {
constexpr const char * const IAXAccount::ACCOUNT_TYPE;
IAXAccount::IAXAccount(const std::string& accountID)
: Account(accountID), link_(new IAXVoIPLink(*this))
{}
void IAXAccount::serialize(YAML::Emitter &out)
{
out << YAML::BeginMap;
Account::serialize(out);
out << YAML::Key << PASSWORD_KEY << YAML::Value << password_;
out << YAML::EndMap;
}
void IAXAccount::unserialize(const YAML::Node &node)
{
Account::unserialize(node);
yaml_utils::parseValue(node, PASSWORD_KEY, password_);
}
void IAXAccount::setAccountDetails(const std::map<std::string, std::string> &details)
{
// Account setting common to SIP and IAX
Account::setAccountDetails(details);
parseString(details, Conf::CONFIG_ACCOUNT_PASSWORD, password_);
}
std::map<std::string, std::string> IAXAccount::getAccountDetails() const
{
std::map<std::string, std::string> a = Account::getAccountDetails();
a[Conf::CONFIG_ACCOUNT_PASSWORD] = password_;
return a;
}
std::map<std::string, std::string> IAXAccount::getVolatileAccountDetails() const
{
std::map<std::string, std::string> a = Account::getVolatileAccountDetails();
return a;
}
void IAXAccount::doRegister()
{
try {
link_->init(rand_);
sendRegister();
} catch (const VoipLinkException &e) {
RING_ERR("IAXAccount: %s", e.what());
}
}
void
IAXAccount::doUnregister(std::function<void(bool)> cb)
{
try {
sendUnregister();
link_->terminate();
} catch (const VoipLinkException &e) {
RING_ERR("IAXAccount: %s", e.what());
}
if (cb)
cb(true);
}
void
IAXAccount::loadConfig()
{
// If IAX is not supported, do not register this account
#if !HAVE_IAX
enabled_ = false;
#endif
}
template <>
std::shared_ptr<IAXCall>
IAXAccount::newIncomingCall(const std::string& from UNUSED)
{
auto& manager = Manager::instance();
return manager.callFactory.newCall<IAXCall, IAXAccount>(*this, manager.getNewCallID(),
Call::CallType::INCOMING);
}
template <>
std::shared_ptr<IAXCall>
IAXAccount::newOutgoingCall(const std::string& toUrl)
{
auto& manager = Manager::instance();
auto call = manager.callFactory.newCall<IAXCall, IAXAccount>(*this, manager.getNewCallID(),
Call::CallType::OUTGOING);
call->setPeerNumber(toUrl);
call->initRecFilename(toUrl);
iaxOutgoingInvite(call.get());
call->setState(Call::CallState::ACTIVE, Call::ConnectionState::PROGRESSING);
return call;
}
std::shared_ptr<Call>
IAXAccount::newOutgoingCall(const std::string& toUrl)
{
return newOutgoingCall<IAXCall>(toUrl);
}
void
IAXAccount::iaxOutgoingInvite(IAXCall* call)
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
call->session = iax_session_new();
std::string username(getUsername());
std::string strNum(username + ":" + getPassword() + "@" + getHostname() + "/" + call->getPeerNumber());
/** @todo Make preference dynamic, and configurable */
const auto accountID = getAccountID();
int audio_format_preferred = call->getFirstMatchingFormat(call->getSupportedFormat(accountID), accountID);
int audio_format_capability = call->getSupportedFormat(accountID);
iax_call(call->session, username.c_str(), username.c_str(), strNum.c_str(),
NULL, 0, audio_format_preferred, audio_format_capability);
}
void
IAXAccount::sendRegister()
{
if (not isEnabled()) {
RING_WARN("Account must be enabled to register, ignoring");
return;
}
if (getHostname().empty())
throw VoipLinkException("Account hostname is empty");
if (getUsername().empty())
throw VoipLinkException("Account username is empty");
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
regSession_.reset(iax_session_new());
}
if (regSession_) {
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
RING_DBG("register IAXAccount %s", getHostname().c_str());
iax_register(regSession_.get(), getHostname().data(),
getUsername().data(), getPassword().data(), 120);
}
nextRefreshStamp_ = time(NULL) + 10;
setRegistrationState(RegistrationState::TRYING);
}
}
void
IAXAccount::sendUnregister(std::function<void(bool)> cb)
{
RING_DBG("unregister IAXAccount %s", getHostname().c_str());
destroyRegSession();
nextRefreshStamp_ = 0;
setRegistrationState(RegistrationState::UNREGISTERED);
if (cb)
cb(true);
}
void
IAXAccount::destroyRegSession()
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
regSession_.reset();
}
void
IAXAccount::checkRegister()
{
if (nextRefreshStamp_ and nextRefreshStamp_ < time(NULL))
sendRegister();
}
bool
IAXAccount::matchRegSession(const iax_session* session) const
{
return regSession_.get() == session;
}
} // namespace ring

View File

@ -1,158 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#ifndef IAXACCOUNT_H
#define IAXACCOUNT_H
#include "account.h"
#include "iaxvoiplink.h"
#include "ring_types.h" // enable_if_base_of
namespace YAML {
class Emitter;
class Node;
}
namespace ring {
class IAXCall;
/**
* @file: iaxaccount.h
* @brief An IAX Account specify IAX specific functions and objects (IAXCall/IAXVoIPLink)
*/
class IAXAccount : public Account {
public:
constexpr static const char * const ACCOUNT_TYPE = "IAX";
IAXAccount(const std::string& accountID);
virtual void serialize(YAML::Emitter &out);
virtual void unserialize(const YAML::Node &node);
const char* getAccountType() const {
return ACCOUNT_TYPE;
}
std::map<std::string, std::string> getAccountDetails() const;
virtual std::map<std::string, std::string> getVolatileAccountDetails() const;
void setNextRefreshStamp(int value) {
nextRefreshStamp_ = value;
}
// Actually useless, since config loading is done in init()
void loadConfig();
// Register an account
void doRegister();
// Unregister an account
void doUnregister(std::function<void(bool)> cb = std::function<void(bool)>());
/**
* Send out registration
*/
void sendRegister();
/**
* Destroy registration session
* @todo Send an IAX_COMMAND_REGREL to force unregistration upstream.
* Urgency: low
*/
void sendUnregister(std::function<void(bool)> cb = std::function<void(bool)>());
std::string getPassword() const {
return password_;
}
bool matchRegSession(const iax_session* session) const;
void destroyRegSession();
void checkRegister();
/**
* Implementation of Account::newOutgoingCall()
* Note: keep declaration before newOutgoingCall template.
*/
std::shared_ptr<Call> newOutgoingCall(const std::string& toUrl);
/**
* Create outgoing IAXCall.
* @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& toUrl);
/**
* Create incoming IAXCall.
* @param[in] from The origin uri 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& from);
/**
* Set whether or not to use UPnP
*/
void setUseUPnP(bool) {
/* do nothing for now as UPnP isn't implemented for IAX */
}
private:
void setAccountDetails(const std::map<std::string, std::string> &details);
/**
* Send an outgoing call invite to iax
* @param call An IAXCall pointer
*/
void iaxOutgoingInvite(IAXCall* call);
/** registration session : nullptr if not register */
struct RegSessionDeleter {
void operator()(iax_session* session) { iax_destroy(session); }
};
std::unique_ptr<iax_session, RegSessionDeleter> regSession_ = nullptr;
// Account login information: password
std::string password_{};
std::unique_ptr<IAXVoIPLink> link_;
/** Timestamp of when we should refresh the registration up with
* the registrar. Values can be: EPOCH timestamp, 0 if we want no registration, 1
* to force a registration. */
int nextRefreshStamp_ = 0;
};
} // namespace ring
#endif

View File

@ -1,249 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#include <cstring>
#include <sys/socket.h>
#include <iax/iax-client.h>
#include <iax/frame.h>
#include "intrin.h"
#include "iaxcall.h"
#include "logger.h"
#include "manager.h"
#include "iaxaccount.h"
#include "iaxvoiplink.h"
#include "audio/ringbufferpool.h"
#include "audio/ringbuffer.h"
#if HAVE_INSTANT_MESSAGING
#include "im/instant_messaging.h"
#endif
namespace ring {
const char* const IAXCall::LINK_TYPE = IAXAccount::ACCOUNT_TYPE;
static int
codecToASTFormat(int c)
{
switch (c) {
case PAYLOAD_CODEC_ULAW:
return AST_FORMAT_ULAW;
case PAYLOAD_CODEC_GSM:
return AST_FORMAT_GSM;
case PAYLOAD_CODEC_ALAW:
return AST_FORMAT_ALAW;
case PAYLOAD_CODEC_ILBC_20:
return AST_FORMAT_ILBC;
case PAYLOAD_CODEC_SPEEX_8000:
return AST_FORMAT_SPEEX;
default:
RING_ERR("Codec %d not supported!", c);
return 0;
}
}
IAXCall::IAXCall(IAXAccount& account, const std::string& id, Call::CallType type)
: Call(account, id, type),
format(0),
session(NULL)
{
ringbuffer_ = Manager::instance().getRingBufferPool().createRingBuffer(getCallId());
}
int
IAXCall::getSupportedFormat(const std::string &accountID) const
{
const auto account = Manager::instance().getAccount(accountID);
int format_mask = 0;
if (account) {
std::vector<unsigned> codecs{account->getActiveCodecs(MEDIA_AUDIO)};
for (const auto &i : codecs)
format_mask |= codecToASTFormat(i);
} else
RING_ERR("No IAx account could be found");
return format_mask;
}
int
IAXCall::getFirstMatchingFormat(int needles, const std::string &accountID) const
{
const auto account = Manager::instance().getAccount(accountID);
if (account != NULL) {
std::vector<unsigned> codecs{account->getActiveCodecs(MEDIA_AUDIO)};
for (const auto &i : codecs) {
int format_mask = codecToASTFormat(i);
// Return the first that matches
if (format_mask & needles)
return format_mask;
}
} else
RING_ERR("No IAx account could be found");
return 0;
}
int
IAXCall::getAudioCodecPayload() const
{
switch (format) {
case AST_FORMAT_ULAW:
return PAYLOAD_CODEC_ULAW;
case AST_FORMAT_GSM:
return PAYLOAD_CODEC_GSM;
case AST_FORMAT_ALAW:
return PAYLOAD_CODEC_ALAW;
case AST_FORMAT_ILBC:
return PAYLOAD_CODEC_ILBC_20;
case AST_FORMAT_SPEEX:
return PAYLOAD_CODEC_SPEEX_8000;
default:
RING_ERR("IAX: Format %d not supported!", format);
return -1;
}
}
void
IAXCall::answer()
{
Manager::instance().addAudio(*this);
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_answer(session);
}
setState(Call::CallState::ACTIVE, Call::ConnectionState::CONNECTED);
Manager::instance().getRingBufferPool().flushAllBuffers();
}
void
IAXCall::hangup(int reason UNUSED)
{
Manager::instance().getRingBufferPool().unBindAll(getCallId());
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_hangup(session, (char*) "Dumped Call");
session = nullptr;
removeCall();
}
void
IAXCall::refuse()
{
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_reject(session, (char*) "Call rejected manually.");
}
removeCall();
}
void
IAXCall::transfer(const std::string& to)
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
char callto[to.length() + 1];
strcpy(callto, to.c_str());
iax_transfer(session, callto);
}
bool
IAXCall::attendedTransfer(const std::string& /*targetID*/)
{
return false; // TODO
}
bool
IAXCall::onhold()
{
Manager::instance().getRingBufferPool().unBindAll(getCallId());
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_quelch_moh(session, true);
}
return setState(Call::CallState::HOLD);
}
bool
IAXCall::offhold()
{
Manager::instance().addAudio(*this);
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_unquelch(session);
}
if (setState(Call::CallState::ACTIVE)) {
Manager::instance().startAudioDriverStream();
return true;
}
return false;
}
void
IAXCall::peerHungup()
{
Manager::instance().getRingBufferPool().unBindAll(getCallId());
session = nullptr;
Call::peerHungup();
}
void
IAXCall::carryingDTMFdigits(char code)
{
std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
iax_send_dtmf(session, code);
}
#if HAVE_INSTANT_MESSAGING
void
IAXCall::sendTextMessage(const std::map<std::string, std::string>& /*messages */,
const std::string& /*from*/)
{
// std::lock_guard<std::mutex> lock(IAXVoIPLink::mutexIAX);
//TODO: implement multipart messages for IAX
// InstantMessaging::sendIaxMessage(session, getCallId(), msgs);
}
#endif
void
IAXCall::putAudioData(AudioBuffer& buf)
{
ringbuffer_->put(buf);
}
} // namespace ring

View File

@ -1,154 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#ifndef IAXCALL_H
#define IAXCALL_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "call.h"
#include "noncopyable.h"
class iax_session;
namespace ring {
class IAXAccount;
class RingBuffer;
class AudioBuffer;
/** Enumeration that contains known audio payloads */
enum {
// http://www.iana.org/assignments/rtp-parameters
// http://www.gnu.org/software/ccrtp/doc/refman/html/formats_8h.html#a0
// 0 PCMU A 8000 1 [RFC3551]
PAYLOAD_CODEC_ULAW = 0,
// 3 GSM A 8000 1 [RFC3551]
PAYLOAD_CODEC_GSM = 3,
// 8 PCMA A 8000 1 [RFC3551]
PAYLOAD_CODEC_ALAW = 8,
// 9 G722 A 8000 1 [RFC3551]
PAYLOAD_CODEC_G722 = 9,
// http://www.ietf.org/rfc/rfc3952.txt
// 97 iLBC/8000
PAYLOAD_CODEC_ILBC_20 = 97,
PAYLOAD_CODEC_ILBC_30 = 98,
// http://www.speex.org/drafts/draft-herlein-speex-rtp-profile-00.txt
// 97 speex/8000
// http://support.xten.com/viewtopic.php?p=8684&sid=3367a83d01fdcad16c7459a79859b08e
// 100 speex/16000
PAYLOAD_CODEC_SPEEX_8000 = 110,
PAYLOAD_CODEC_SPEEX_16000 = 111,
PAYLOAD_CODEC_SPEEX_32000 = 112
};
/**
* @file: iaxcall.h
* @brief IAXCall are IAX implementation of a normal 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(IAXAccount& account, const std::string& id, Call::CallType type);
public:
const char* getLinkType() const override {
return LINK_TYPE;
}
/**
* @return int The bitwise list of supported formats
*/
int getSupportedFormat(const std::string &accountID) const;
/**
* Return a format (int) with the first matching codec selected.
*
* This considers the order of the appearance in the CodecMap,
* thus, the order of preference.
*
* NOTE: Everything returned is bound to the content of the local
* CodecMap, so it won't return format values that aren't valid
* in this call context.
*
* @param needles The format(s) (bitwise) you are looking for to match
* @return int The matching format, thus 0 if none matches
*/
int getFirstMatchingFormat(int needles, const std::string &accountID) const;
int getAudioCodecPayload() const;
int format;
iax_session* session;
void answer() override;
void hangup(int reason) override;
void refuse() override;
void transfer(const std::string& to) override;
bool attendedTransfer(const std::string& to) override;
bool onhold() override;
bool offhold() override;
//TODO: implement mute for IAX
void muteMedia(const std::string& /*mediaType*/, bool /*isMuted*/) override {}
//TODO: implement restartMedia for IAX
void restartMediaSender() override {}
void peerHungup() override;
void carryingDTMFdigits(char code) override;
#if HAVE_INSTANT_MESSAGING
void sendTextMessage(const std::map<std::string, std::string>& messages,
const std::string &from) override;
#endif
void putAudioData(AudioBuffer& buf);
private:
NON_COPYABLE(IAXCall);
// Incoming audio ring buffer
std::shared_ptr<RingBuffer> ringbuffer_{};
};
} // namespace ring
#endif

View File

@ -1,450 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#include "iaxvoiplink.h"
#include <unistd.h>
#include <cmath>
#include <algorithm>
#include "manager.h"
#include "iaxcall.h"
#include "iaxaccount.h"
#include "logger.h"
#include "hooks/urlhook.h"
#include "audio/audiolayer.h"
#include "audio/resampler.h"
#include "audio/ringbufferpool.h"
#include "array_size.h"
#include "map_utils.h"
#include "call_factory.h"
#include "ring_types.h"
#include "system_codec_container.h"
#include "intrin.h" // for UNUSED
namespace ring {
std::mutex IAXVoIPLink::mutexIAX {};
IAXVoIPLink::IAXVoIPLink(IAXAccount& account) : account_(account), resampler_(new Resampler{44100})
{}
IAXVoIPLink::~IAXVoIPLink()
{
terminate();
}
void
IAXVoIPLink::init(std::mt19937_64& rand_generator)
{
if (initDone_)
return;
std::uniform_int_distribution<int> port_dist(1024, 65024);
std::lock_guard<std::mutex> lock(mutexIAX);
for (int port = IAX_DEFAULT_PORTNO, nbTry = 0; nbTry < 3 ; port = port_dist(rand_generator), nbTry++) {
if (iax_init(port) >= 0) {
Manager::instance().registerEventHandler((uintptr_t)this, std::bind(&IAXVoIPLink::handleEvents, this));
initDone_ = true;
break;
}
}
}
void
IAXVoIPLink::terminate()
{
if (!initDone_)
return;
Manager::instance().unregisterEventHandler((uintptr_t)this);
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();
}
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;
}
void
IAXVoIPLink::handleEvents()
{
iax_event *event = NULL;
{
std::lock_guard<std::mutex> lock(mutexIAX);
event = iax_get_event(0);
}
while (event != NULL) {
// If we received an 'ACK', libiax2 tells apps to ignore them.
if (event->etype == IAX_EVENT_NULL) {
std::lock_guard<std::mutex> lock(mutexIAX);
iax_event_free(event);
event = iax_get_event(0);
continue;
}
if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) {
iaxHandleCallEvent(event, *raw_call_ptr);
} else if (event->session && account_.matchRegSession(event->session)) {
// This is a registration session, deal with it
iaxHandleRegReply(event);
} else {
// We've got an event before it's associated with any call
iaxHandlePrecallEvent(event);
}
{
std::lock_guard<std::mutex> lock(mutexIAX);
iax_event_free(event);
event = iax_get_event(0);
}
}
account_.checkRegister();
sendAudioFromMic();
}
void
IAXVoIPLink::sendAudioFromMic()
{
for (const auto currentCall : Manager::instance().callFactory.getAllCalls<IAXCall>()) {
if (currentCall->getState() != Call::CallState::ACTIVE)
continue;
int codecType = currentCall->getAudioCodecPayload();
auto codec = account_.searchCodecByPayload(codecType, MEDIA_AUDIO);
auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(codec);
if (!accountAudioCodec)
continue;
Manager::instance().getRingBufferPool().setInternalSamplingRate(accountAudioCodec->audioformat.sample_rate);
unsigned int mainBufferSampleRate = Manager::instance().getRingBufferPool().getInternalSamplingRate();
// we have to get 20ms of data from the mic *20/1000 = /50
// rate/50 shall be lower than IAX__20S_48KHZ_MAX
size_t samples = mainBufferSampleRate * 20 / 1000;
if (Manager::instance().getRingBufferPool().availableForGet(currentCall->getCallId()) < samples)
continue;
// Get bytes from micRingBuffer to data_from_mic
rawBuffer_.resize(samples);
samples = Manager::instance().getRingBufferPool().getData(rawBuffer_, currentCall->getCallId());
int compSize = 0;
unsigned int audioRate = accountAudioCodec->audioformat.sample_rate;
int outSamples;
UNUSED AudioBuffer *in;
if (audioRate != mainBufferSampleRate) {
rawBuffer_.setSampleRate(audioRate);
resampledData_.setSampleRate(mainBufferSampleRate);
resampler_->resample(rawBuffer_, resampledData_);
in = &resampledData_;
outSamples = 0;
} else {
outSamples = samples;
in = &rawBuffer_;
}
/*
* TODO ebail : *
* IAX use old codec API (based on audiocodec wrapper)
* It does not use libav API
* We disable it for the moment
*/
#if 0
compSize = audioCodec->encode(in->getData(), encodedData_, RAW_BUFFER_SIZE);
#endif
if (currentCall->session and samples > 0) {
std::lock_guard<std::mutex> lock(mutexIAX);
if (iax_send_voice(currentCall->session, currentCall->format,
encodedData_, compSize, outSamples) == -1)
RING_ERR("IAX: Error sending voice data.");
}
}
}
void
IAXVoIPLink::handleReject(IAXCall& call)
{
call.setState(Call::CallState::MERROR, Call::ConnectionState::DISCONNECTED);
Manager::instance().callFailure(call);
call.removeCall();
}
void
IAXVoIPLink::handleAccept(iax_event* event, IAXCall& call)
{
if (event->ies.format)
call.format = event->ies.format;
}
void
IAXVoIPLink::handleAnswerTransfer(iax_event* event, IAXCall& call)
{
if (call.getConnectionState() == Call::ConnectionState::CONNECTED)
return;
call.setState(Call::CallState::ACTIVE, Call::ConnectionState::CONNECTED);
if (event->ies.format)
call.format = event->ies.format;
Manager::instance().addAudio(call);
Manager::instance().peerAnsweredCall(call);
Manager::instance().startAudioDriverStream();
Manager::instance().getRingBufferPool().flushAllBuffers();
}
void
IAXVoIPLink::handleBusy(IAXCall& call)
{
call.setState(Call::CallState::BUSY, Call::ConnectionState::CONNECTED);
Manager::instance().callBusy(call);
call.removeCall();
}
#if HAVE_INSTANT_MESSAGING
void
IAXVoIPLink::handleMessage(iax_event* event, IAXCall& call)
{
Manager::instance().incomingMessage(call.getCallId(), call.getPeerNumber() ,std::map<std::string, std::string>
{{"text/plain", std::string((const char*) event->data)}});
}
#endif
void
IAXVoIPLink::handleRinging(IAXCall& call)
{
call.setState(Call::ConnectionState::RINGING);
Manager::instance().peerRingingCall(call);
}
void
IAXVoIPLink::handleHangup(IAXCall& call)
{
Manager::instance().peerHungupCall(call);
call.removeCall();
}
void
IAXVoIPLink::iaxHandleCallEvent(iax_event* event, IAXCall& call)
{
switch (event->etype) {
case IAX_EVENT_HANGUP:
handleHangup(call);
break;
case IAX_EVENT_REJECT:
handleReject(call);
break;
case IAX_EVENT_ACCEPT:
handleAccept(event, call);
break;
case IAX_EVENT_ANSWER:
case IAX_EVENT_TRANSFER:
handleAnswerTransfer(event, call);
break;
case IAX_EVENT_BUSY:
handleBusy(call);
break;
case IAX_EVENT_VOICE:
iaxHandleVoiceEvent(event, call);
break;
case IAX_EVENT_TEXT:
#if HAVE_INSTANT_MESSAGING
handleMessage(event, call);
#endif
break;
case IAX_EVENT_RINGA:
handleRinging(call);
break;
case IAX_IE_MSGCOUNT:
case IAX_EVENT_TIMEOUT:
case IAX_EVENT_PONG:
default:
break;
case IAX_EVENT_URL:
if (Manager::instance().hookPreference.getIax2Enabled())
UrlHook::runAction(Manager::instance().hookPreference.getUrlCommand(), (char*) event->data);
break;
}
}
/* Handle audio event, VOICE packet received */
void
IAXVoIPLink::iaxHandleVoiceEvent(iax_event* event, IAXCall& call)
{
// Skip this empty packet.
if (!event->datalen)
return;
auto codec = account_.searchCodecByPayload(call.getAudioCodecPayload(), MEDIA_AUDIO);
auto accountAudioCodec = std::static_pointer_cast<AccountAudioCodecInfo>(codec);
if (!accountAudioCodec)
return;
Manager::instance().getRingBufferPool().setInternalSamplingRate(accountAudioCodec->audioformat.sample_rate);
unsigned int mainBufferSampleRate = Manager::instance().getRingBufferPool().getInternalSamplingRate();
if (event->subclass)
call.format = event->subclass;
unsigned int size = event->datalen;
unsigned int max = accountAudioCodec->audioformat.sample_rate * 20 / 1000;
if (size > max)
size = max;
/*
* TODO ebail : *
* IAX use old codec API (based on audiocodec wrapper)
* It does not use libav API
* We disable it for the moment
*/
#if 0
unsigned char *data = (unsigned char*) event->data;
audioCodec->decode(rawBuffer_.getData(), data , size);
#endif
AudioBuffer *out = &rawBuffer_;
unsigned int audioRate = accountAudioCodec->audioformat.sample_rate;
if (audioRate != mainBufferSampleRate) {
rawBuffer_.setSampleRate(mainBufferSampleRate);
resampledData_.setSampleRate(audioRate);
resampler_->resample(rawBuffer_, resampledData_);
out = &resampledData_;
}
call.putAudioData(*out);
}
/**
* Handle the registration process
*/
void
IAXVoIPLink::iaxHandleRegReply(iax_event* event)
{
if (event->etype != IAX_EVENT_REGREJ && event->etype != IAX_EVENT_REGACK)
return;
account_.destroyRegSession();
account_.setRegistrationState((event->etype == IAX_EVENT_REGREJ) ? RegistrationState::ERROR_AUTH : RegistrationState::REGISTERED);
if (event->etype == IAX_EVENT_REGACK)
account_.setNextRefreshStamp(time(NULL) + (event->ies.refresh ? event->ies.refresh : 60));
}
void IAXVoIPLink::iaxHandlePrecallEvent(iax_event* event)
{
const auto accountID = account_.getAccountID();
std::shared_ptr<IAXCall> call;
switch (event->etype) {
case IAX_EVENT_CONNECT:
call = account_.newIncomingCall<IAXCall>("");
if (!call) {
RING_ERR("failed to create an incoming IAXCall from account %s",
accountID.c_str());
return;
}
call->session = event->session;
call->setState(Call::ConnectionState::PROGRESSING);
if (event->ies.calling_number)
call->setPeerNumber(event->ies.calling_number);
if (event->ies.calling_name)
call->setPeerDisplayName(std::string(event->ies.calling_name));
// if peerNumber exist append it to the name string
if (event->ies.calling_number)
call->initRecFilename(std::string(event->ies.calling_number));
Manager::instance().incomingCall(*call, accountID);
call->format = call->getFirstMatchingFormat(event->ies.format, accountID);
if (!call->format)
call->format = call->getFirstMatchingFormat(event->ies.capability, accountID);
{
std::lock_guard<std::mutex> lock(mutexIAX);
iax_accept(event->session, call->format);
iax_ring_announce(event->session);
}
break;
case IAX_EVENT_HANGUP:
if (auto raw_call_ptr = iaxGetCallFromSession(event->session)) {
Manager::instance().peerHungupCall(*raw_call_ptr);
raw_call_ptr->removeCall();
}
break;
case IAX_EVENT_TIMEOUT: // timeout for an unknown session
case IAX_IE_MSGCOUNT:
case IAX_EVENT_REGACK:
case IAX_EVENT_REGREJ:
case IAX_EVENT_REGREQ:
// Received when someone wants to register to us!?!
// Asterisk receives and answers to that, not us, we're a phone.
default:
break;
}
}
} // namespace ring

View File

@ -1,163 +0,0 @@
/*
* Copyright (C) 2004-2016 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
* 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.
*/
#ifndef IAXVOIPLINK_H
#define IAXVOIPLINK_H
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include "audio/audiobuffer.h"
#include "ring_types.h"
#include <iax/iax-client.h>
#include <mutex>
#include <memory>
#include <random>
#define RAW_BUFFER_SIZE (120 * 48000 / 1000)
namespace ring {
class IAXAccount;
class IAXCall;
class AudioCodec;
class AudioLayer;
class Resampler;
/**
* @file iaxvoiplink.h
* @brief VoIPLink contains a thread that listen to external events
* and contains IAX Call related functions
*/
class IAXVoIPLink {
public:
IAXVoIPLink(IAXAccount& account);
~IAXVoIPLink();
/**
* Listen to events sent by the call manager ( asterisk, etc .. )
*/
void handleEvents();
/**
* Init the voip link
*/
void init(std::mt19937_64& rand);
/**
* Terminate a voip link by clearing the call list
*/
void terminate();
/**
* Cancel a call
* @param id The ID of the call
*/
void cancel(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;
private:
void handleAccept(iax_event* event, IAXCall& call);
void handleReject(IAXCall& call);
void handleRinging(IAXCall& call);
void handleAnswerTransfer(iax_event* event, IAXCall& call);
void handleBusy(IAXCall& call);
#if HAVE_INSTANT_MESSAGING
void handleMessage(iax_event* event, IAXCall& call);
#endif
void handleHangup(IAXCall& call);
/*
* Decode the message count IAX send.
* Returns only the new messages number
*
* @param msgcount The value sent by IAX in the REGACK message
* @return int The number of new messages waiting for the current registered user
*/
int processIAXMsgCount(int msgcount);
/**
* Find a iaxcall by iax session number
* @param session an iax_session valid pointer
* @return iaxcall or 0 if not found
*/
std::string iaxFindCallIDBySession(struct iax_session* session);
/**
* Handle IAX Event for a call
* @param event An iax_event pointer
* @param call An IAXCall pointer
*/
void iaxHandleCallEvent(iax_event* event, IAXCall& call);
/**
* Handle the VOICE events specifically
* @param event The iax_event containing the IAX_EVENT_VOICE
* @param call The associated IAXCall
*/
void iaxHandleVoiceEvent(iax_event* event, IAXCall& call);
/**
* Handle IAX Registration Reply event
* @param event An iax_event pointer
*/
void iaxHandleRegReply(iax_event* event);
/**
* Handle IAX pre-call setup-related events
* @param event An iax_event pointer
*/
void iaxHandlePrecallEvent(iax_event* event);
/**
* Work out the audio data from Microphone to IAX2 channel
*/
void sendAudioFromMic();
IAXAccount& account_;
/** encoder/decoder/resampler buffers */
AudioBuffer rawBuffer_{RAW_BUFFER_SIZE, AudioFormat::MONO()};
AudioBuffer resampledData_{RAW_BUFFER_SIZE * 4, AudioFormat::MONO()};
unsigned char encodedData_[RAW_BUFFER_SIZE] {};
std::unique_ptr<Resampler> resampler_;
/** Whether init() was called already or not
* This should be used in init() and terminate(), to
* indicate that init() was called, or reset by terminate().
*/
bool initDone_{false};
};
} // namespace ring
#endif

View File

@ -257,16 +257,4 @@ im::parseSipMessage(const pjsip_msg* msg)
return ret; return ret;
} }
#if HAVE_IAX
void
im::sendIaxMessage(iax_session* session, const std::string& /* id */,
const std::vector<std::string>& chunks)
{
//TODO: implement multipart message creation for IAX via the pjsip api and then convert
// into string for sending
for (const auto& msg: chunks)
iax_send_text(session, msg.c_str());
}
#endif
} // namespace ring } // namespace ring

View File

@ -30,10 +30,6 @@
#include "config.h" #include "config.h"
#if HAVE_IAX
#include <iax/iax-client.h>
#endif
struct pjsip_inv_session; struct pjsip_inv_session;
struct pjsip_rx_data; struct pjsip_rx_data;
struct pjsip_msg; struct pjsip_msg;
@ -77,11 +73,6 @@ void sendSipMessage(pjsip_inv_session* session, const std::map<std::string, std:
*/ */
std::map<std::string, std::string> parseSipMessage(const pjsip_msg* msg); std::map<std::string, std::string> parseSipMessage(const pjsip_msg* msg);
#if HAVE_IAX
void sendIaxMessage(iax_session* session, const std::string& id,
const std::vector<std::string>& chunks);
#endif
void fillPJSIPMessageBody(pjsip_tx_data& tdata, const std::map<std::string, std::string>& payloads); void fillPJSIPMessageBody(pjsip_tx_data& tdata, const std::map<std::string, std::string>& payloads);
}} // namespace ring::im }} // namespace ring::im

View File

@ -1609,7 +1609,7 @@ Manager::incomingCall(Call &call, const std::string& accountId)
call.setIPToIP(true); call.setIPToIP(true);
else { else {
// strip sip: which is not required and bring confusion with ip to ip calls // strip sip: which is not required and bring confusion with ip to ip calls
// when placing new call from history (if call is IAX, do nothing) // when placing new call from history.
std::string peerNumber(call.getPeerNumber()); std::string peerNumber(call.getPeerNumber());
const char SIP_PREFIX[] = "sip:"; const char SIP_PREFIX[] = "sip:";

View File

@ -87,7 +87,6 @@ static const char * const ZID_FILE_KEY = "zidFile";
// hooks preferences // hooks preferences
constexpr const char * const HookPreference::CONFIG_LABEL; constexpr const char * const HookPreference::CONFIG_LABEL;
static const char * const IAX2_ENABLED_KEY = "iax2Enabled";
static const char * const NUMBER_ADD_PREFIX_KEY = "numberAddPrefix"; static const char * const NUMBER_ADD_PREFIX_KEY = "numberAddPrefix";
static const char * const NUMBER_ENABLED_KEY = "numberEnabled"; static const char * const NUMBER_ENABLED_KEY = "numberEnabled";
static const char * const SIP_ENABLED_KEY = "sipEnabled"; static const char * const SIP_ENABLED_KEY = "sipEnabled";
@ -240,18 +239,16 @@ void VoipPreference::unserialize(const YAML::Node &in)
parseValue(node, ZID_FILE_KEY, zidFile_); parseValue(node, ZID_FILE_KEY, zidFile_);
} }
HookPreference::HookPreference() : HookPreference::HookPreference()
iax2Enabled_(false) : numberAddPrefix_("")
, numberAddPrefix_("")
, numberEnabled_(false) , numberEnabled_(false)
, sipEnabled_(false) , sipEnabled_(false)
, urlCommand_("x-www-browser") , urlCommand_("x-www-browser")
, urlSipField_("X-ring-url") , urlSipField_("X-ring-url")
{} {}
HookPreference::HookPreference(const std::map<std::string, std::string> &settings) : HookPreference::HookPreference(const std::map<std::string, std::string> &settings)
iax2Enabled_(settings.find("URLHOOK_IAX2_ENABLED")->second == "true") : numberAddPrefix_(settings.find("PHONE_NUMBER_HOOK_ADD_PREFIX")->second)
, numberAddPrefix_(settings.find("PHONE_NUMBER_HOOK_ADD_PREFIX")->second)
, numberEnabled_(settings.find("PHONE_NUMBER_HOOK_ENABLED")->second == "true") , numberEnabled_(settings.find("PHONE_NUMBER_HOOK_ENABLED")->second == "true")
, sipEnabled_(settings.find("URLHOOK_SIP_ENABLED")->second == "true") , sipEnabled_(settings.find("URLHOOK_SIP_ENABLED")->second == "true")
, urlCommand_(settings.find("URLHOOK_COMMAND")->second) , urlCommand_(settings.find("URLHOOK_COMMAND")->second)
@ -261,7 +258,6 @@ HookPreference::HookPreference(const std::map<std::string, std::string> &setting
std::map<std::string, std::string> HookPreference::toMap() const std::map<std::string, std::string> HookPreference::toMap() const
{ {
std::map<std::string, std::string> settings; std::map<std::string, std::string> settings;
settings["URLHOOK_IAX2_ENABLED"] = iax2Enabled_ ? "true" : "false";
settings["PHONE_NUMBER_HOOK_ADD_PREFIX"] = numberAddPrefix_; settings["PHONE_NUMBER_HOOK_ADD_PREFIX"] = numberAddPrefix_;
settings["PHONE_NUMBER_HOOK_ENABLED"] = numberEnabled_ ? "true" : "false"; settings["PHONE_NUMBER_HOOK_ENABLED"] = numberEnabled_ ? "true" : "false";
settings["URLHOOK_SIP_ENABLED"] = sipEnabled_ ? "true" : "false"; settings["URLHOOK_SIP_ENABLED"] = sipEnabled_ ? "true" : "false";
@ -274,7 +270,6 @@ std::map<std::string, std::string> HookPreference::toMap() const
void HookPreference::serialize(YAML::Emitter &out) void HookPreference::serialize(YAML::Emitter &out)
{ {
out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap; out << YAML::Key << CONFIG_LABEL << YAML::Value << YAML::BeginMap;
out << YAML::Key << IAX2_ENABLED_KEY << YAML::Value << iax2Enabled_;
out << YAML::Key << NUMBER_ADD_PREFIX_KEY << YAML::Value << numberAddPrefix_; out << YAML::Key << NUMBER_ADD_PREFIX_KEY << YAML::Value << numberAddPrefix_;
out << YAML::Key << SIP_ENABLED_KEY << YAML::Value << sipEnabled_; out << YAML::Key << SIP_ENABLED_KEY << YAML::Value << sipEnabled_;
out << YAML::Key << URL_COMMAND_KEY << YAML::Value << urlCommand_; out << YAML::Key << URL_COMMAND_KEY << YAML::Value << urlCommand_;
@ -286,7 +281,6 @@ void HookPreference::unserialize(const YAML::Node &in)
{ {
const auto &node = in[CONFIG_LABEL]; const auto &node = in[CONFIG_LABEL];
parseValue(node, IAX2_ENABLED_KEY, iax2Enabled_);
parseValue(node, NUMBER_ADD_PREFIX_KEY, numberAddPrefix_); parseValue(node, NUMBER_ADD_PREFIX_KEY, numberAddPrefix_);
parseValue(node, SIP_ENABLED_KEY, sipEnabled_); parseValue(node, SIP_ENABLED_KEY, sipEnabled_);
parseValue(node, URL_COMMAND_KEY, urlCommand_); parseValue(node, URL_COMMAND_KEY, urlCommand_);

View File

@ -197,14 +197,12 @@ class HookPreference : public Serializable {
return ""; return "";
} }
bool getIax2Enabled() const { return iax2Enabled_; }
const std::string & getUrlCommand() const { return urlCommand_; } const std::string & getUrlCommand() const { return urlCommand_; }
std::map<std::string, std::string> toMap() const; std::map<std::string, std::string> toMap() const;
void runHook(pjsip_msg *msg); void runHook(pjsip_msg *msg);
private: private:
bool iax2Enabled_;
std::string numberAddPrefix_; std::string numberAddPrefix_;
bool numberEnabled_; bool numberEnabled_;
bool sipEnabled_; bool sipEnabled_;

View File

@ -218,8 +218,8 @@ while getopts ":b: t a v c" opt; do
DOPTS="--disable-video $DOPTS" DOPTS="--disable-video $DOPTS"
;; ;;
m) m)
echo "-m is set, disabling dbus, video, iax, nm and pulse" >&2 echo "-m is set, disabling dbus, video, nm and pulse" >&2
DOPTS="--disable-video --without-iax --without-dbus --without-pulse --without-networkmanager $DOPTS" DOPTS="--disable-video --without-dbus --without-pulse --without-networkmanager $DOPTS"
;; ;;
c) c)
echo "-c is set, clang compiler is used" >&2 echo "-c is set, clang compiler is used" >&2

View File

@ -279,7 +279,6 @@ END
pushd contrib/native pushd contrib/native
../bootstrap ../bootstrap
# only fetch it, don't build it # only fetch it, don't build it
make iax
make dht make dht
else else
pushd libs pushd libs

View File

@ -173,7 +173,6 @@ addressbook:
mobile: true mobile: true
photo: true photo: true
hooks: hooks:
iax2Enabled: false
numberAddPrefix: numberAddPrefix:
numberEnabled: false numberEnabled: false
sipEnabled: false sipEnabled: false

View File

@ -63,9 +63,6 @@ class SflPhoneTests():
for account in self.getAllSipAccounts(): for account in self.getAllSipAccounts():
print " " + account print " " + account
for account in self.getAllIaxAccounts():
print " " + account
def test_create_account(self): def test_create_account(self):
"""Create a new sip account""" """Create a new sip account"""