Commit 3d54b92f authored by pierre-luc's avatar pierre-luc
Browse files

[#811] First commit toward re-integration and refactoring of ZRTP

support from the 0.9.5beta version into the 0.9.7 branch. The ZRTP session
object can be instanciated but nothing else was re-implemented so far
in the GUI or over dbus.
parent 1d9f1edb
......@@ -46,6 +46,7 @@ AC_CONFIG_FILES([Makefile])
AC_CONFIG_FILES([src/Makefile \
src/audio/Makefile \
src/audio/audiortp/Makefile \
src/audio/codecs/Makefile \
src/config/Makefile \
src/dbus/Makefile \
......@@ -189,6 +190,13 @@ AC_SUBST(CCEXT2_CFLAGS)
AC_SUBST(CCRTP_LIBS)
AC_SUBST(CCRTP_CFLAGS)
dnl Check for libzrtpcpp, a ccRTP extension providing zrtp key exchange
LIBZRTPCPP_MIN_VERSION=1.3.0
PKG_CHECK_MODULES(ZRTPCPP, libzrtpcpp >= ${LIBZRTPCPP_MIN_VERSION})
AC_SUBST(ZRTPCPP_LIBS)
AC_SUBST(ZRTPCPP_CFLAGS)
dnl DBus-C++ detection (used to be in library own build system)
DBUS_REQUIRED_VERSION=0.60
PKG_CHECK_MODULES(dbus, [dbus-1 >= $DBUS_REQUIRED_VERSION],,
......
......@@ -39,7 +39,8 @@ sflphoned_SOURCES = \
sflphoned_CXXFLAGS = \
-DPREFIX=\"$(prefix)\" -DPROGSHAREDIR=\"${datadir}/sflphone\" \
$(IAX_FLAGS)
$(IAX_FLAGS) \
@ZRTPCPP_CFLAGS@
# Add here the dynamic libraries sflphoned should be linked against
......@@ -47,6 +48,7 @@ sflphoned_LDADD = \
./libsflphone.la \
@CCGNU2_LIBS@ \
@CCEXT2_LIBS@ \
@ZRTPCPP_LIBS@ \
$(PJSIP_LIBS) \
@CCRTP_LIBS@ \
@ALSA_LIBS@ \
......@@ -82,6 +84,7 @@ libsflphone_la_LIBADD = \
$(src)/libs/utilspp/libutilspp.la \
$(src)/libs/iax2/libiax2.la \
./audio/libaudio.la \
./audio/audiortp/libaudiortp.la \
./dbus/libdbus.la \
./config/libconfig.la \
./plug-in/libplugin.la \
......
......@@ -54,25 +54,34 @@ typedef enum RegistrationState {
#define AccountNULL ""
// Common account parameters
#define CONFIG_ACCOUNT_TYPE "Account.type"
#define CONFIG_ACCOUNT_ALIAS "Account.alias"
#define CONFIG_ACCOUNT_MAILBOX "Account.mailbox"
#define CONFIG_ACCOUNT_ENABLE "Account.enable"
#define CONFIG_ACCOUNT_RESOLVE_ONCE "Account.resolveOnce"
#define CONFIG_ACCOUNT_REGISTRATION_EXPIRE "Account.expire"
#define CONFIG_CREDENTIAL_NUMBER "Credential.count"
#define HOSTNAME "hostname"
#define USERNAME "username"
#define AUTHENTICATION_USERNAME "authenticationUsername"
#define PASSWORD "password"
#define REALM "realm"
#define CONFIG_ACCOUNT_TYPE "Account.type"
#define CONFIG_ACCOUNT_ALIAS "Account.alias"
#define CONFIG_ACCOUNT_MAILBOX "Account.mailbox"
#define CONFIG_ACCOUNT_ENABLE "Account.enable"
#define CONFIG_ACCOUNT_RESOLVE_ONCE "Account.resolveOnce"
#define CONFIG_ACCOUNT_REGISTRATION_EXPIRE "Account.expire"
#define CONFIG_CREDENTIAL_NUMBER "Credential.count"
#define HOSTNAME "hostname"
#define USERNAME "username"
#define AUTHENTICATION_USERNAME "authenticationUsername"
#define PASSWORD "password"
#define REALM "realm"
// SIP specific parameters
#define SIP_PROXY "SIP.proxy"
#define SIP_STUN_SERVER "STUN.server"
#define SIP_USE_STUN "STUN.enable"
#define SIP_STUN_PORT "STUN.port"
#define SIP_PROXY "SIP.proxy"
#define SIP_STUN_SERVER "STUN.server"
#define SIP_USE_STUN "STUN.enable"
#define SIP_STUN_PORT "STUN.port"
// SRTP specific parameters
#define SRTP_ENABLE "SRTP.enable"
#define SRTP_KEY_EXCHANGE "SRTP.keyExchange"
#define SRTP_ENCRYPTION_ALGO "SRTP.encryptionAlgorithm" // Provided by ccRTP,0=NULL,1=AESCM,2=AESF8
#define ZRTP_HELLO_HASH "ZRTP.helloHashEnable"
#define ZRTP_DISPLAY_SAS "ZRTP.displaySAS"
#define ZRTP_NOT_SUPP_WARNING "ZRTP.notSuppWarning"
#define ZRTP_DISPLAY_SAS_ONCE "ZRTP.displaySasOnce"
class Account{
......
......@@ -9,12 +9,11 @@ else
ILBC_FLAG =
endif
SUBDIRS = codecs
SUBDIRS = codecs audiortp
libaudio_la_SOURCES = \
audiofile.cpp \
tonelist.cpp \
audiortp.cpp \
audiostream.cpp \
dtmf.cpp \
tone.cpp \
......@@ -36,7 +35,6 @@ noinst_HEADERS = \
ringbuffer.h \
audiofile.h \
tonelist.h \
audiortp.h \
audiolayer.h \
alsalayer.h \
pulselayer.h \
......
/*
* Copyright (C) 2004-2008 Savoir-Faire Linux inc.
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* Author: Alexandre Savard <alexandre.savard@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., 675 Mass Ave, Cambridge, MA 02139, USA.
*/
#include <cstdio>
#include <cstdlib>
#include <ccrtp/rtp.h>
#include <assert.h>
#include <cstring>
#include <math.h>
#include <dlfcn.h>
#include <iostream>
#include <sstream>
#include "../global.h"
#include "../manager.h"
#include "codecDescriptor.h"
#include "audiortp.h"
#include "audiolayer.h"
#include "ringbuffer.h"
#include "../user_cfg.h"
#include "../sipcall.h"
////////////////////////////////////////////////////////////////////////////////
// AudioRtp
////////////////////////////////////////////////////////////////////////////////
AudioRtp::AudioRtp() :_RTXThread (0), _symmetric(), _threadMutex()
{
}
AudioRtp::~AudioRtp (void)
{
delete _RTXThread;
_RTXThread = 0;
}
void
AudioRtp::createNewSession (SIPCall *ca)
{
ost::MutexLock m (_threadMutex);
_debug ("AudioRtp::Create new rtp session\n");
// something should stop the thread before...
if (_RTXThread != 0) {
_debug ("**********************************************************\n");
_debug ("! ARTP Failure: Thread already exists..., stopping it\n");
_debug ("**********************************************************\n");
delete _RTXThread;
_RTXThread = 0;
}
// Start RTP Send/Receive threads
_symmetric = Manager::instance().getConfigInt (SIGNALISATION,SYMMETRIC) ? true : false;
_RTXThread = new AudioRtpRTX (ca, _symmetric);
}
int
AudioRtp::start (void)
{
if (_RTXThread == 0) {
_debug ("! ARTP Failure: Cannot start audiortp thread since not yet created\n");
throw AudioRtpException();
}
try {
if (_RTXThread->start() != 0) {
_debug ("! ARTP Failure: unable to start RTX Thread\n");
return -1;
}
} catch (...) {
_debugException ("! ARTP Failure: when trying to start a thread");
throw;
}
return 0;
}
bool
AudioRtp::closeRtpSession ()
{
ost::MutexLock m (_threadMutex);
// This will make RTP threads finish.
_debug ("AudioRtp::Stopping rtp session\n");
try {
delete _RTXThread;
_RTXThread = 0;
} catch (...) {
_debugException ("! ARTP Exception: when stopping audiortp\n");
throw;
}
_debug ("AudioRtp::Audio rtp stopped\n");
return true;
}
void
AudioRtp::setRecording()
{
_debug ("AudioRtp::setRecording\n");
_RTXThread->_ca->setRecording();
}
////////////////////////////////////////////////////////////////////////////////
// AudioRtpRTX Class //
////////////////////////////////////////////////////////////////////////////////
AudioRtpRTX::AudioRtpRTX (SIPCall *sipcall, bool sym) : time (new ost::Time()), _ca (sipcall), _sessionSend (NULL), _sessionRecv (NULL), _session (NULL),
_sym (sym), micData (NULL), micDataConverted (NULL), micDataEncoded (NULL), spkrDataDecoded (NULL), spkrDataConverted (NULL),
converter (NULL), _layerSampleRate(),_codecSampleRate(), _layerFrameSize(), _audiocodec (NULL)
{
setCancel (cancelDefault);
// AudioRtpRTX should be close if we change sample rate
// TODO: Change bind address according to user settings.
// TODO: this should be the local ip not the external (router) IP
std::string localipConfig = _ca->getLocalIp(); // _ca->getLocalIp();
ost::InetHostAddress local_ip (localipConfig.c_str());
_debug ("%i\n", _ca->getLocalAudioPort());
_session = new ost::SymmetricRTPSession (local_ip, _ca->getLocalAudioPort());
// _session = new ost::RTPSessionBase(local_ip, _ca->getLocalAudioPort());
_sessionRecv = NULL;
_sessionSend = NULL;
//mic, we receive from soundcard in stereo, and we send encoded
//encoding before sending
_audiolayer = Manager::instance().getAudioDriver();
_layerFrameSize = _audiolayer->getFrameSize(); // in ms
_layerSampleRate = _audiolayer->getSampleRate();
// initBuffers();
// initAudioRtpSession();
_payloadIsSet = false;
_remoteIpIsSet = false;
}
AudioRtpRTX::~AudioRtpRTX ()
{
_debug ("Delete AudioRtpRTX instance\n");
try {
this->terminate();
} catch (...) {
_debugException ("! ARTP: Thread destructor didn't terminate correctly");
throw;
}
_ca = 0;
delete [] micData;
micData = NULL;
delete [] micDataConverted;
micDataConverted = NULL;
delete [] micDataEncoded;
micDataEncoded = NULL;
delete [] spkrDataDecoded;
spkrDataDecoded = NULL;
delete [] spkrDataConverted;
spkrDataConverted = NULL;
delete time;
time = NULL;
delete converter;
converter = NULL;
// _session->terminate();
delete _session;
_session = NULL;
_debug ("AudioRtpRTX instance deleted\n");
}
void
AudioRtpRTX::initBuffers()
{
converter = new SamplerateConverter (_layerSampleRate , _layerFrameSize);
int nbSamplesMax = (int) (_layerSampleRate * _layerFrameSize /1000);
micData = new SFLDataFormat[nbSamplesMax];
micDataConverted = new SFLDataFormat[nbSamplesMax];
micDataEncoded = new unsigned char[nbSamplesMax];
spkrDataConverted = new SFLDataFormat[nbSamplesMax];
spkrDataDecoded = new SFLDataFormat[nbSamplesMax];
}
void
AudioRtpRTX::initAudioRtpSession (void)
{
try {
_session->setSchedulingTimeout (100000);
_session->setExpireTimeout (1000000);
} catch (...) {
_debugException ("! ARTP Failure: initialisation failed");
throw;
}
}
void
AudioRtpRTX::setRtpSessionMedia (void)
{
if (_ca == 0) {
_debug (" !ARTP: No call, can't init RTP media\n");
return;
}
_audiocodec = _ca->getLocalSDP()->get_session_media ();
if (_audiocodec == NULL) {
_debug (" !ARTP: No audiocodec, can't init RTP media\n");
return;
}
_debug ("Init audio RTP session: codec payload %i\n", _audiocodec->getPayload());
if (_audiocodec == NULL) {
return;
}
_codecSampleRate = _audiocodec->getClockRate();
_codecFrameSize = _audiocodec->getFrameSize();
if (_audiocodec->getPayload() == 9) {
_debug ("We Are G722\n");
_payloadIsSet = _session->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
} else if (_audiocodec->hasDynamicPayload()) {
_debug ("We Are Dynamic\n");
_payloadIsSet = _session->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) _audiocodec->getPayload(), _audiocodec->getClockRate()));
} else if (!_audiocodec->hasDynamicPayload() && _audiocodec->getPayload() != 9) {
_debug ("We Are Static\n");
_payloadIsSet = _session->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) _audiocodec->getPayload()));
}
}
void
AudioRtpRTX::setRtpSessionRemoteIp (void)
{
if (!_remoteIpIsSet) {
_debug ("++++++++++++++++++++++++++ SET IP ADDRESS ++++++++++++++++++++++++++++\n");
if (_ca == 0) {
_debug (" !ARTP: No call, can't init RTP media \n");
return;
}
ost::InetHostAddress remote_ip (_ca->getLocalSDP()->get_remote_ip().c_str());
_debug ("Init audio RTP session: remote ip %s\n", _ca->getLocalSDP()->get_remote_ip().data());
if (!remote_ip) {
_debug (" !ARTP Thread Error: Target IP address [%s] is not correct!\n", _ca->getLocalSDP()->get_remote_ip().data());
return;
}
_debug ("++++Address: %s, audioport: %d\n", _ca->getLocalSDP()->get_remote_ip().c_str(), _ca->getLocalSDP()->get_remote_audio_port());
_debug ("++++Audioport: %d\n", (int) _ca->getLocalSDP()->get_remote_audio_port());
if (!_session->addDestination (remote_ip, (unsigned short) _ca->getLocalSDP()->get_remote_audio_port())) {
_debug (" !ARTP Thread Error: can't add destination to session!\n");
return;
}
_remoteIpIsSet = true;
} else {
_debug ("+++++++++++++++++++++++ IP ADDRESS ALREADY SET ++++++++++++++++++++++++\n");
}
}
float
AudioRtpRTX::computeCodecFrameSize (int codecSamplePerFrame, int codecClockRate)
{
return ( (float) codecSamplePerFrame * 1000.0) / (float) codecClockRate;
}
int
AudioRtpRTX::computeNbByteAudioLayer (float codecFrameSize)
{
return (int) ( (float) _layerSampleRate * codecFrameSize * (float) sizeof (SFLDataFormat) / 1000.0);
}
int
AudioRtpRTX::processDataEncode()
{
// compute codec framesize in ms
float fixed_codec_framesize = computeCodecFrameSize (_audiocodec->getFrameSize(), _audiocodec->getClockRate());
// compute nb of byte to get coresponding to 20 ms at audio layer frame size (44.1 khz)
int maxBytesToGet = computeNbByteAudioLayer (fixed_codec_framesize);
// available bytes inside ringbuffer
int availBytesFromMic = _audiolayer->canGetMic();
// set available byte to maxByteToGet
int bytesAvail = (availBytesFromMic < maxBytesToGet) ? availBytesFromMic : maxBytesToGet;
if (bytesAvail == 0)
return 0;
// Get bytes from micRingBuffer to data_from_mic
int nbSample = _audiolayer->getMic (micData , bytesAvail) / sizeof (SFLDataFormat);
// nb bytes to be sent over RTP
int compSize = 0;
// test if resampling is required
if (_audiocodec->getClockRate() != _layerSampleRate) {
int nb_sample_up = nbSample;
//_debug("_nbSample audiolayer->getMic(): %i \n", nbSample);
// Store the length of the mic buffer in samples for recording
_nSamplesMic = nbSample;
nbSample = reSampleData (micData , micDataConverted, _audiocodec->getClockRate(), nb_sample_up, DOWN_SAMPLING);
compSize = _audiocodec->codecEncode (micDataEncoded, micDataConverted, nbSample*sizeof (int16));
} else {
// no resampling required
compSize = _audiocodec->codecEncode (micDataEncoded, micData, nbSample*sizeof (int16));
}
return compSize;
}
void
AudioRtpRTX::processDataDecode (unsigned char* spkrData, unsigned int size, int& countTime)
{
if (_audiocodec != NULL) {
// Return the size of data in bytes
int expandedSize = _audiocodec->codecDecode (spkrDataDecoded , spkrData , size);
// buffer _receiveDataDecoded ----> short int or int16, coded on 2 bytes
int nbSample = expandedSize / sizeof (SFLDataFormat);
// test if resampling is required
if (_audiocodec->getClockRate() != _layerSampleRate) {
// Do sample rate conversion
int nb_sample_down = nbSample;
nbSample = reSampleData (spkrDataDecoded, spkrDataConverted, _codecSampleRate, nb_sample_down, UP_SAMPLING);
// Store the number of samples for recording
_nSamplesSpkr = nbSample;
// put data in audio layer, size in byte
_audiolayer->putMain (spkrDataConverted, nbSample * sizeof (SFLDataFormat));
} else {
// Stor the number of samples for recording
_nSamplesSpkr = nbSample;
// put data in audio layer, size in byte
_audiolayer->putMain (spkrDataDecoded, nbSample * sizeof (SFLDataFormat));
}
// Notify (with a beep) an incoming call when there is already a call
countTime += time->getSecond();
if (Manager::instance().incomingCallWaiting() > 0) {
countTime = countTime % 500; // more often...
if (countTime == 0) {
Manager::instance().notificationIncomingCall();
}
}
} else {
countTime += time->getSecond();
}
}
void
AudioRtpRTX::sendSessionFromMic (int timestamp)
{
// STEP:
// 1. get data from mic
// 2. convert it to int16 - good sample, good rate
// 3. encode it
// 4. send it
timestamp += time->getSecond();
// no call, so we do nothing
if (_ca==0) {
_debug (" !ARTP: No call associated (mic)\n");
return;
}
// AudioLayer* audiolayer = Manager::instance().getAudioDriver();
if (!_audiolayer) {
_debug (" !ARTP: No audiolayer available for MIC\n");
return;
}
if (!_audiocodec) {
_debug (" !ARTP: No audiocodec available for MIC\n");
return;
}
int compSize = processDataEncode();
// putData put the data on RTP queue, sendImmediate bypass this queue
_session->putData (timestamp, micDataEncoded, compSize);
// _session->sendImmediate(timestamp, micDataEncoded, compSize);
}
void
AudioRtpRTX::receiveSessionForSpkr (int& countTime)
{
if (_ca == 0) {
return;
}
if (!_audiolayer) {
_debug (" !ARTP: No audiolayer available for SPEAKER\n");
return;
}
if (!_audiocodec) {
_debug (" !ARTP: No audiocodec available for SPEAKER\n");
return;
}
const ost::AppDataUnit* adu = NULL;
adu = _session->getData (_session->getFirstTimestamp());