Commit 3fedb0c1 authored by Rafaël Carré's avatar Rafaël Carré
Browse files

* #6269 : refactor AudioRtpSession

Now AudioZrtpSession and AudioSymmetricRtpSession are derived from it, and AudioSrtpSession is derived from AudioSymmetricRtpSession
AudioRtpSession class keeps a pointer to the RTPDataQueue and Thread casts of the 2 specialized classes to access a few, because AudioRtpSession doesn't derive from RTPDataQueue or Thread directly.
parent 09e66d31
......@@ -115,7 +115,6 @@ void AudioRtpFactory::initAudioSymmetricRtpSession (SIPCall * ca)
case Zrtp:
_rtpSession = new AudioZrtpSession (ca, zidFilename);
_rtpSessionType = Zrtp;
if (_helloHashEnabled) {
// TODO: be careful with that. The hello hash is computed asynchronously. Maybe it's
......@@ -129,7 +128,6 @@ void AudioRtpFactory::initAudioSymmetricRtpSession (SIPCall * ca)
case Sdes:
_rtpSession = new AudioSrtpSession (ca);
_rtpSessionType = Sdes;
break;
default:
......@@ -137,7 +135,6 @@ void AudioRtpFactory::initAudioSymmetricRtpSession (SIPCall * ca)
throw UnsupportedRtpSessionType();
}
} else {
_rtpSessionType = Symmetric;
_rtpSession = new AudioSymmetricRtpSession (ca);
_debug ("AudioRtpFactory: Starting a symmetric unencrypted rtp session");
}
......@@ -149,37 +146,15 @@ void AudioRtpFactory::start (AudioCodec* audiocodec)
throw AudioRtpFactoryException ("AudioRtpFactory: Error: RTP session was null when trying to start audio thread");
}
switch (_rtpSessionType) {
case Sdes:
if(localContext && remoteContext) {
static_cast<AudioSrtpSession *> (_rtpSession)->restoreCryptoContext(localContext, remoteContext);
}
if (static_cast<AudioSrtpSession *> (_rtpSession)->startRtpThread (audiocodec) != 0) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: Failed to start AudioSRtpSession thread");
}
break;
case Symmetric:
_debug ("Starting symmetric rtp thread");
if (static_cast<AudioSymmetricRtpSession *> (_rtpSession)->startRtpThread (audiocodec) != 0) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: Failed to start AudioSymmetricRtpSession thread");
}
break;
case Zrtp:
if (static_cast<AudioZrtpSession *> (_rtpSession)->startRtpThread (audiocodec) != 0) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: Failed to start AudioZrtpSession thread");
}
break;
if (_rtpSession->getAudioRtpType() == Sdes) {
if(localContext && remoteContext) {
static_cast<AudioSrtpSession *> (_rtpSession)->restoreCryptoContext(localContext, remoteContext);
}
}
if (_rtpSession->startRtpThread (audiocodec) != 0) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: Failed to start AudioZrtpSession thread");
}
}
void AudioRtpFactory::stop (void)
......@@ -193,23 +168,13 @@ void AudioRtpFactory::stop (void)
}
try {
switch (_rtpSessionType) {
case Sdes:
localContext = static_cast<AudioSrtpSession *> (_rtpSession)->_localCryptoCtx;
remoteContext = static_cast<AudioSrtpSession *> (_rtpSession)->_remoteCryptoCtx;
static_cast<AudioSrtpSession *> (_rtpSession)->stopRtpThread();
break;
case Symmetric:
static_cast<AudioSymmetricRtpSession *> (_rtpSession)->stopRtpThread();
break;
case Zrtp:
static_cast<AudioZrtpSession *> (_rtpSession)->stopRtpThread();
break;
if (_rtpSession->getAudioRtpType() == Sdes) {
localContext = static_cast<AudioSrtpSession *> (_rtpSession)->_localCryptoCtx;
remoteContext = static_cast<AudioSrtpSession *> (_rtpSession)->_remoteCryptoCtx;
}
_rtpSession->stopRtpThread();
_rtpSession = NULL;
} catch (...) {
_debugException ("AudioRtpFactory: Error: Exception caught when stopping the audio rtp session");
......@@ -225,21 +190,7 @@ int AudioRtpFactory::getSessionMedia()
throw AudioRtpFactoryException ("AudioRtpFactory: Error: RTP session was null when trying to get session media type");
}
int payloadType = 0;
switch (_rtpSessionType) {
case Sdes:
payloadType = static_cast<AudioSrtpSession *> (_rtpSession)->getCodecPayloadType();
break;
case Symmetric:
payloadType = static_cast<AudioSymmetricRtpSession *> (_rtpSession)->getCodecPayloadType();
break;
case Zrtp:
payloadType = static_cast<AudioZrtpSession *> (_rtpSession)->getCodecPayloadType();
break;
}
return payloadType;
return _rtpSession->getCodecPayloadType();
}
void AudioRtpFactory::updateSessionMedia (AudioCodec *audiocodec)
......@@ -249,21 +200,7 @@ void AudioRtpFactory::updateSessionMedia (AudioCodec *audiocodec)
if (_rtpSession == NULL) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: _rtpSession was null when trying to update IP address");
}
switch (_rtpSessionType) {
case Sdes:
static_cast<AudioSrtpSession *> (_rtpSession)->updateSessionMedia (audiocodec);
break;
case Symmetric:
static_cast<AudioSymmetricRtpSession *> (_rtpSession)->updateSessionMedia (audiocodec);
break;
case Zrtp:
static_cast<AudioZrtpSession *> (_rtpSession)->updateSessionMedia (audiocodec);
break;
default:
_debug("AudioRtpFactory: Unknown session type");
break;
}
_rtpSession->updateSessionMedia (audiocodec);
}
void AudioRtpFactory::updateDestinationIpAddress (void)
......@@ -273,26 +210,12 @@ void AudioRtpFactory::updateDestinationIpAddress (void)
if (_rtpSession == NULL) {
throw AudioRtpFactoryException ("AudioRtpFactory: Error: RtpSession was null when trying to update IP address");
}
switch (_rtpSessionType) {
case Sdes:
static_cast<AudioSrtpSession *> (_rtpSession)->updateDestinationIpAddress();
break;
case Symmetric:
static_cast<AudioSymmetricRtpSession *> (_rtpSession)->updateDestinationIpAddress();
break;
case Zrtp:
static_cast<AudioZrtpSession *> (_rtpSession)->updateDestinationIpAddress();
break;
}
_rtpSession->updateDestinationIpAddress();
}
sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession()
{
if ( (_rtpSessionType == Zrtp) && (_rtpSessionType != 0)) {
if (_rtpSession->getAudioRtpType() == Zrtp) {
return static_cast<AudioZrtpSession *> (_rtpSession);
} else {
throw AudioRtpFactoryException ("RTP: Error: _rtpSession is NULL in getAudioZrtpSession");
......@@ -301,7 +224,7 @@ sfl::AudioZrtpSession * AudioRtpFactory::getAudioZrtpSession()
void sfl::AudioRtpFactory::initLocalCryptoInfo (SIPCall * ca)
{
if (_rtpSession && _rtpSessionType && (_rtpSessionType == Sdes)) {
if (_rtpSession && _rtpSession->getAudioRtpType() == Sdes) {
static_cast<AudioSrtpSession *> (_rtpSession)->initLocalCryptoInfo ();
ca->getLocalSDP()->setLocalSdpCrypto (static_cast<AudioSrtpSession *> (_rtpSession)->getLocalCryptoInfo());
......@@ -310,7 +233,7 @@ void sfl::AudioRtpFactory::initLocalCryptoInfo (SIPCall * ca)
void AudioRtpFactory::setRemoteCryptoInfo (sfl::SdesNegotiator& nego)
{
if (_rtpSession && _rtpSessionType && (_rtpSessionType == Sdes)) {
if (_rtpSession && _rtpSession->getAudioRtpType() == Sdes) {
static_cast<AudioSrtpSession *> (_rtpSession)->setRemoteCryptoInfo (nego);
} else {
throw AudioRtpFactoryException ("RTP: Error: _rtpSession is NULL in setRemoteCryptoInfo");
......@@ -319,13 +242,14 @@ void AudioRtpFactory::setRemoteCryptoInfo (sfl::SdesNegotiator& nego)
void AudioRtpFactory::setDtmfPayloadType(unsigned int payloadType)
{
static_cast<AudioRtpRecordHandler *> (_rtpSession)->setDtmfPayloadType(payloadType);
_rtpSession->setDtmfPayloadType(payloadType);
}
void AudioRtpFactory::sendDtmfDigit (int digit)
{
static_cast<AudioRtpRecordHandler*> (_rtpSession)->putDtmfEvent (digit);
_rtpSession->putDtmfEvent (digit);
}
}
......@@ -35,6 +35,7 @@
#include <cc++/thread.h>
#include "account.h" // for typedef of std::string (std::string)
#include <ccrtp/CryptoContext.h>
#include "AudioRtpSession.h"
#include "sip/SdesNegotiator.h"
......@@ -47,17 +48,8 @@ namespace sfl
{
class AudioZrtpSession;
class AudioSrtpSession;
class AudioCodec;
// Possible kind of rtp session
typedef enum RtpMethod {
Symmetric,
Zrtp,
Sdes
} RtpMethod;
class UnsupportedRtpSessionType : public std::logic_error
{
public:
......@@ -116,15 +108,6 @@ class AudioRtpFactory
*/
void updateDestinationIpAddress (void);
/**
* @param None
* @return The internal audio rtp thread of the type specified in the configuration
* file. initAudioSymmetricRtpSession must have been called prior to that.
*/
void * getAudioSymmetricRtpSession (void) const {
return _rtpSession;
}
/**
* @param None
* @return The internal audio rtp session type
......@@ -133,14 +116,7 @@ class AudioRtpFactory
* Sdes = 2
*/
RtpMethod getAudioRtpType (void) const {
return _rtpSessionType;
}
/**
* @param Set internal audio rtp session type (Symmetric, Zrtp, Sdes)
*/
void setAudioRtpType (RtpMethod type) {
_rtpSessionType = type;
return _rtpSession->getAudioRtpType();
}
/**
......@@ -192,8 +168,7 @@ class AudioRtpFactory
private:
void registerAccount(Account *account, const std::string &id);
void registerAccount(SIPAccount *account, const std::string &id);
void * _rtpSession;
RtpMethod _rtpSessionType;
AudioRtpSession *_rtpSession;
ost::Mutex _audioRtpThreadMutex;
// Field used when initializinga udio rtp session
......
......@@ -126,7 +126,7 @@ AudioRtpRecord::~AudioRtpRecord()
}
AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _ca (ca), echoCanceller(ca->getMemoryPool()), gainController(8000, -10.0)
AudioRtpRecordHandler::AudioRtpRecordHandler (SIPCall *ca) : _audioRtpRecord (), _id (ca->getCallId()), echoCanceller(ca->getMemoryPool()), gainController(8000, -10.0)
{
}
......@@ -227,7 +227,7 @@ void AudioRtpRecordHandler::updateNoiseSuppress()
_audioRtpRecord._noiseSuppress = NULL;
_debug ("AudioSymmetricRtpSession: Update noise suppressor with sampling rate %d and frame size %d", getCodecSampleRate(), getCodecFrameSize());
_debug ("AudioRtpSession: Update noise suppressor with sampling rate %d and frame size %d", getCodecSampleRate(), getCodecFrameSize());
NoiseSuppress *noiseSuppress = new NoiseSuppress (getCodecFrameSize(), getCodecSampleRate());
AudioProcessing *processing = new AudioProcessing (noiseSuppress);
......@@ -249,7 +249,7 @@ void AudioRtpRecordHandler::putDtmfEvent (int digit)
dtmf->newevent = true;
dtmf->length = 1000;
getEventQueue()->push_back (dtmf);
_debug ("AudioSymmetricRtpSession: Put Dtmf Event %d", digit);
_debug ("AudioRtpSession: Put Dtmf Event %d", digit);
}
#ifdef DUMP_PROCESS_DATA_ENCODE
......@@ -275,13 +275,13 @@ int AudioRtpRecordHandler::processDataEncode (void)
int bytesToGet = computeNbByteAudioLayer (mainBufferSampleRate, fixedCodecFramesize);
// available bytes inside ringbuffer
int availBytesFromMic = Manager::instance().getMainBuffer()->availForGet (_ca->getCallId());
int availBytesFromMic = Manager::instance().getMainBuffer()->availForGet (_id);
if (availBytesFromMic < bytesToGet)
return 0;
// Get bytes from micRingBuffer to data_from_mic
int nbSample = Manager::instance().getMainBuffer()->getData (micData, bytesToGet, 100, _ca->getCallId()) / sizeof (SFLDataFormat);
int nbSample = Manager::instance().getMainBuffer()->getData (micData, bytesToGet, 100, _id) / sizeof (SFLDataFormat);
// process mic fade in
if (!_audioRtpRecord._micFadeInComplete)
......@@ -393,7 +393,7 @@ void AudioRtpRecordHandler::processDataDecode (unsigned char *spkrData, unsigned
}
// put data in audio layer, size in byte
Manager::instance().getMainBuffer()->putData (spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _ca->getCallId());
Manager::instance().getMainBuffer()->putData (spkrDataConverted, nbSample * sizeof (SFLDataFormat), 100, _id);
} else {
......@@ -401,7 +401,7 @@ void AudioRtpRecordHandler::processDataDecode (unsigned char *spkrData, unsigned
echoCanceller.putData(spkrDataDecoded, expandedSize);
}
// put data in audio layer, size in byte
Manager::instance().getMainBuffer()->putData (spkrDataDecoded, expandedSize, 100, _ca->getCallId());
Manager::instance().getMainBuffer()->putData (spkrDataDecoded, expandedSize, 100, _id);
}
}
......
......@@ -225,7 +225,7 @@ class AudioRtpRecordHandler
private:
SIPCall *_ca;
CallID& _id;
EchoSuppress echoCanceller;
......
/*
* Copyright (C) 2004, 2005, 2006, 2009, 2008, 2009, 2010, 2011 Savoir-Faire Linux Inc.
* Author: Pierre-Luc Bacon <pierre-luc.bacon@savoirfairelinux.com>
* Author: Alexandre Bourget <alexandre.bourget@savoirfairelinux.com>
* Author: Laurielle Lea <laurielle.lea@savoirfairelinux.com>
* Author: Emmanuel Milou <emmanuel.milou@savoirfairelinux.com>
* Author: Yan Morin <yan.morin@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.
*
* Additional permission under GNU GPL version 3 section 7:
*
* If you modify this program, or any covered work, by linking or
* combining it with the OpenSSL project's OpenSSL library (or a
* modified version of that library), containing parts covered by the
* terms of the OpenSSL or SSLeay licenses, Savoir-Faire Linux Inc.
* grants you additional permission to convey the resulting work.
* Corresponding Source for a non-source form of such a combination
* shall include the source code for the parts of OpenSSL used as well
* as that of the covered work.
*/
#include "AudioRtpSession.h"
#include "AudioSymmetricRtpSession.h"
#include "sip/sdp.h"
#include "audio/audiolayer.h"
#include <ccrtp/rtp.h>
#include <ccrtp/oqueue.h>
namespace sfl
{
AudioRtpSession::AudioRtpSession (SIPCall * sipcall, RtpMethod type, ost::RTPDataQueue *queue, ost::Thread *thread) :
_ca (sipcall)
, AudioRtpRecordHandler (sipcall)
, _timestamp (0)
, _timestampIncrement (0)
, _timestampCount (0)
, _type(type)
, _queue(queue)
, _thread(thread)
{
assert (_ca);
_queue->setTypeOfService (ost::RTPDataQueue::tosEnhanced);
}
AudioRtpSession::~AudioRtpSession()
{
_info ("AudioRtpSession: Delete AudioRtpSession instance");
}
void AudioRtpSession::updateSessionMedia (AudioCodec *audioCodec)
{
_debug ("AudioSymmetricRtpSession: Update session media");
// Update internal codec for this session
updateRtpMedia (audioCodec);
int payloadType = getCodecPayloadType();
int frameSize = getCodecFrameSize();
int smplRate = getCodecSampleRate();
int dynamic = getHasDynamicPayload();
// G722 requires timetamp to be incremented at 8khz
if (payloadType == g722PayloadType)
_timestampIncrement = g722RtpTimeincrement;
else
_timestampIncrement = frameSize;
_debug ("AudioRptSession: Codec payload: %d", payloadType);
_debug ("AudioSymmetricRtpSession: Codec sampling rate: %d", smplRate);
_debug ("AudioSymmetricRtpSession: Codec frame size: %d", frameSize);
_debug ("AudioSymmetricRtpSession: RTP timestamp increment: %d", _timestampIncrement);
if (payloadType == g722PayloadType) {
_debug ("AudioSymmetricRtpSession: Setting G722 payload format");
_queue->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) payloadType, g722RtpClockRate));
} else {
if (dynamic) {
_debug ("AudioSymmetricRtpSession: Setting dynamic payload format");
_queue->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) payloadType, smplRate));
} else {
_debug ("AudioSymmetricRtpSession: Setting static payload format");
_queue->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) payloadType));
}
}
if (_type != Zrtp) {
_ca->setRecordingSmplRate (getCodecSampleRate());
_timestamp = _queue->getCurrentTimestamp();
}
}
void AudioRtpSession::setSessionMedia (AudioCodec *audioCodec)
{
_debug ("AudioSymmetricRtpSession: Set session media");
// set internal codec info for this session
setRtpMedia (audioCodec);
// store codec info locally
int payloadType = getCodecPayloadType();
int frameSize = getCodecFrameSize();
int smplRate = getCodecSampleRate();
bool dynamic = getHasDynamicPayload();
// G722 requires timestamp to be incremented at 8 kHz
if (payloadType == g722PayloadType)
_timestampIncrement = g722RtpTimeincrement;
else
_timestampIncrement = frameSize;
_debug ("AudioRptSession: Codec payload: %d", payloadType);
_debug ("AudioSymmetricRtpSession: Codec sampling rate: %d", smplRate);
_debug ("AudioSymmetricRtpSession: Codec frame size: %d", frameSize);
_debug ("AudioSymmetricRtpSession: RTP timestamp increment: %d", _timestampIncrement);
if (payloadType == g722PayloadType) {
_debug ("AudioSymmetricRtpSession: Setting G722 payload format");
_queue->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) payloadType, g722RtpClockRate));
} else {
if (dynamic) {
_debug ("AudioSymmetricRtpSession: Setting dynamic payload format");
_queue->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) payloadType, smplRate));
} else {
_debug ("AudioSymmetricRtpSession: Setting static payload format");
_queue->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) payloadType));
}
}
if (_type != Zrtp) {
_ca->setRecordingSmplRate (getCodecSampleRate());
}
}
void AudioRtpSession::sendDtmfEvent (sfl::DtmfEvent *dtmf)
{
const int increment = (_type == Zrtp) ? 160 : _timestampIncrement;
_debug ("AudioRtpSession: Send Dtmf");
_timestamp += increment;
// discard equivalent size of audio
processDataEncode();
// change Payload type for DTMF payload
_queue->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) getDtmfPayloadType(), 8000));
// Set marker in case this is a new Event
if (dtmf->newevent)
_queue->setMark (true);
// putData (_timestamp, (const unsigned char*) (& (dtmf->payload)), sizeof (ost::RTPPacket::RFC2833Payload));
_queue->sendImmediate (_timestamp, (const unsigned char *) (& (dtmf->payload)), sizeof (ost::RTPPacket::RFC2833Payload));
// This is no more a new event
if (dtmf->newevent) {
dtmf->newevent = false;
_queue->setMark (false);
}
// get back the payload to audio
_queue->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) getCodecPayloadType()));
// decrease length remaining to process for this event
dtmf->length -= increment;
dtmf->payload.duration++;
// next packet is going to be the last one
if ( (dtmf->length - increment) < increment)
dtmf->payload.ebit = true;
if (dtmf->length < increment) {
delete dtmf;
getEventQueue()->pop_front();
}
}
void AudioRtpSession::receiveSpeakerData ()
{
const ost::AppDataUnit* adu = NULL;
int packetTimestamp = _queue->getFirstTimestamp();
adu = _queue->getData (packetTimestamp);
if (!adu) {
return;
}
unsigned char* spkrDataIn = NULL;
unsigned int size = 0;
spkrDataIn = (unsigned char*) adu->getData(); // data in char
size = adu->getSize(); // size in char
// DTMF over RTP, size must be over 4 in order to process it as voice data
if (size > 4) {
processDataDecode (spkrDataIn, size);
}
delete adu;
}
void AudioRtpSession::sendMicData()
{
int compSize = processDataEncode();
// if no data return
if (!compSize)
return;
// Increment timestamp for outgoing packet
_timestamp += _timestampIncrement;
if (_type == Zrtp)
_queue->putData (_timestamp, getMicDataEncoded(), compSize);
// putData put the data on RTP queue, sendImmediate bypass this queue
_queue->sendImmediate (_timestamp, getMicDataEncoded(), compSize);
}
void AudioRtpSession::setSessionTimeouts (void)
{
_debug ("AudioZrtpSession: Set session scheduling timeout (%d) and expireTimeout (%d)", sfl::schedulingTimeout, sfl::expireTimeout);
_queue->setSchedulingTimeout (sfl::schedulingTimeout);
_queue->setExpireTimeout (sfl::expireTimeout);
}
void AudioRtpSession::setDestinationIpAddress (void)
{
_info ("AudioZrtpSession: Setting IP address for the RTP session");
// Store remote ip in case we would need to forget current destination
_remote_ip = ost::InetHostAddress (_ca->getLocalSDP()->getRemoteIP().c_str());
if (!_remote_ip) {
_warn ("AudioZrtpSession: Target IP address (%s) is not correct!",