mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
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:

committed by
gerrit2

parent
7479d74ce5
commit
36e857fcf0
2
README
2
README
@ -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
|
||||||
|
|
||||||
|
@ -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>
|
||||||
|
@ -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())
|
||||||
{
|
{
|
||||||
|
@ -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();
|
||||||
|
17
configure.ac
17
configure.ac
@ -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 \
|
||||||
|
@ -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 $@
|
|
@ -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)
|
||||||
|
|
||||||
|
@ -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_);
|
||||||
|
@ -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)
|
||||||
*/
|
*/
|
||||||
|
@ -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));
|
||||||
|
@ -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()
|
||||||
{
|
{
|
||||||
|
@ -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";
|
||||||
|
|
||||||
|
@ -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();
|
||||||
|
@ -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
|
|
||||||
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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:";
|
||||||
|
@ -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_);
|
||||||
|
@ -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_;
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
|
@ -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"""
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user