Merge branch 'master' of git+ssh://repos-sflphone-git@git.sflphone.org/var/repos/sflphone/git/sflphone

This commit is contained in:
Emmanuel Milou
2010-03-05 17:48:33 -05:00
22 changed files with 1517 additions and 188 deletions

View File

@ -90,6 +90,8 @@ GtkWidget * displayNameEntry;
GtkWidget * security_tab;
GtkWidget * advanced_tab;
GtkWidget * overrtp;
GHashTable * directIpCallsProperties = NULL;
// Credentials
@ -134,6 +136,25 @@ is_iax_enabled(void)
}
void
select_dtmf_type( void )
{
DEBUG("DTMF selection changed\n");
if( gtk_toggle_button_get_active( GTK_TOGGLE_BUTTON(overrtp) ) )
{
// dbus_set_audio_manager( ALSA );
DEBUG("Selected DTMF over RTP");
}
else {
// dbus_set_audio_manager( PULSEAUDIO );
DEBUG("Selected DTMF over SIP");
}
}
static GPtrArray* getNewCredential (GHashTable * properties) {
GtkTreeIter iter;
@ -1119,6 +1140,53 @@ GtkWidget* create_advanced_tab (account_t **a) {
return ret;
}
GtkWidget* create_codecs_configuration (account_t **a) {
// Main widget
GtkWidget *ret, *codecs, *dtmf, *box, *frame, *sipinfo, *table;
account_t *currentAccount = *a;
gchar *currentDtmfType = "";
gboolean dtmf_are_rtp = TRUE;
ret = gtk_vbox_new(FALSE, 10);
gtk_container_set_border_width(GTK_CONTAINER(ret), 10);
box = codecs_box (a);
// Box for the codecs
gnome_main_section_new (_("Codecs"), &codecs);
gtk_box_pack_start (GTK_BOX(ret), codecs, FALSE, FALSE, 0);
gtk_widget_set_size_request (GTK_WIDGET (codecs), -1, 200);
gtk_widget_show (codecs);
gtk_container_add (GTK_CONTAINER (codecs) , box);
// Box for dtmf
gnome_main_section_new_with_table (_("DTMF"), &dtmf, &table, 1, 2);
gtk_box_pack_start (GTK_BOX(ret), dtmf, FALSE, FALSE, 0);
gtk_widget_show (dtmf);
currentDtmfType = g_hash_table_lookup (currentAccount->properties, g_strdup(ACCOUNT_DTMF_TYPE));
if (g_strcasecmp(currentDtmfType, OVERRTP) != 0) {
dtmf_are_rtp = FALSE;
}
overrtp = gtk_radio_button_new_with_label( NULL, _("RTP") );
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(overrtp), dtmf_are_rtp);
gtk_table_attach ( GTK_TABLE( table ), overrtp, 0, 1, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
sipinfo = gtk_radio_button_new_with_label_from_widget(GTK_RADIO_BUTTON(overrtp), _("SIP"));
gtk_toggle_button_set_active( GTK_TOGGLE_BUTTON(sipinfo), !dtmf_are_rtp);
g_signal_connect(G_OBJECT(sipinfo), "clicked", G_CALLBACK(select_dtmf_type), NULL);
gtk_table_attach ( GTK_TABLE( table ), sipinfo, 1, 2, 0, 1, GTK_EXPAND | GTK_FILL, GTK_EXPAND | GTK_FILL, 0, 0);
gtk_widget_show_all(ret);
return ret;
}
void show_account_window (account_t * a) {
GtkWidget * notebook;
@ -1277,6 +1345,13 @@ void show_account_window (account_t * a) {
}
if(gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(overrtp))) {
g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_DTMF_TYPE), g_strdup(OVERRTP));
}
else {
g_hash_table_replace(currentAccount->properties, g_strdup(ACCOUNT_DTMF_TYPE), g_strdup(SIPINFO));
}
gchar* keyExchange = (gchar *)gtk_combo_box_get_active_text(GTK_COMBO_BOX(keyExchangeCombo));
if (g_strcasecmp(keyExchange, "ZRTP") == 0) {

View File

@ -900,7 +900,7 @@ GtkWidget* create_audio_configuration()
return ret;
}
/*
GtkWidget* create_codecs_configuration (account_t **a) {
// Main widget
@ -922,3 +922,4 @@ GtkWidget* create_codecs_configuration (account_t **a) {
return ret;
}
*/

View File

@ -62,6 +62,7 @@
#define ACCOUNT_REGISTRATION_EXPIRE "Account.expire"
#define ACCOUNT_SIP_STUN_SERVER "STUN.server"
#define ACCOUNT_SIP_STUN_ENABLED "STUN.enable"
#define ACCOUNT_DTMF_TYPE "Account.dtmfType"
#define ACCOUNT_HOSTNAME "hostname"
#define ACCOUNT_USERNAME "username"
#define ACCOUNT_PASSWORD "password"
@ -135,6 +136,10 @@ log4c_category_t* log4c_sfl_gtk_category;
#define ALSA 0
#define PULSEAUDIO 1
/** DTMF type */
#define OVERRTP "overrtp"
#define SIPINFO "sipinfo"
/** Notification levels */
#define __NOTIF_LEVEL_MIN 0
#define __NOTIF_LEVEL_MED 1

View File

@ -65,6 +65,7 @@ typedef enum RegistrationState {
#define CONFIG_ACCOUNT_RESOLVE_ONCE "Account.resolveOnce"
#define CONFIG_ACCOUNT_REGISTRATION_EXPIRE "Account.expire"
#define CONFIG_CREDENTIAL_NUMBER "Credential.count"
#define ACCOUNT_DTMF_TYPE "Account.dtmfType"
#define HOSTNAME "hostname"
#define USERNAME "username"
@ -117,6 +118,7 @@ typedef enum RegistrationState {
#define REGISTRATION_STATE_CODE "Registration.code"
#define REGISTRATION_STATE_DESCRIPTION "Registration.description"
class Account{
public:

View File

@ -229,6 +229,22 @@ void AudioRtpFactory::setRemoteCryptoInfo(sfl::SdesNegotiator& nego)
}
}
void AudioRtpFactory::sendDtmfDigit(int digit) {
switch(_rtpSessionType) {
case Sdes:
static_cast<AudioSrtpSession *> (_rtpSession)->putDtmfEvent(digit);
break;
case Symmetric:
static_cast<AudioSymmetricRtpSession *> (_rtpSession)->putDtmfEvent(digit);
break;
case Zrtp:
static_cast<AudioZrtpSession *> (_rtpSession)->putDtmfEvent(digit);
break;
}
}
}

View File

@ -86,31 +86,31 @@ namespace sfl {
void stop();
/**
* Update current RTP destination address with one stored in call
* @param None
*/
* Update current RTP destination address with one stored in call
* @param None
*/
void updateDestinationIpAddress (void);
/**
* @param None
* @return The internal audio rtp thread of the type specified in the configuration
* file. initAudioRtpSession must have been called prior to that.
*/
inline void * getAudioRtpSession(void) { return _rtpSession; }
/**
* @param None
* @return The internal audio rtp thread of the type specified in the configuration
* file. initAudioRtpSession must have been called prior to that.
*/
inline void * getAudioRtpSession(void) { return _rtpSession; }
/**
* @param None
* @return The internal audio rtp session type
* Symmetric = 0
* Zrtp = 1
* Sdes = 2
*/
inline RtpMethod getAudioRtpType(void) { return _rtpSessionType; }
* @param None
* @return The internal audio rtp session type
* Symmetric = 0
* Zrtp = 1
* Sdes = 2
*/
inline RtpMethod getAudioRtpType(void) { return _rtpSessionType; }
/**
* @param Set internal audio rtp session type (Symmetric, Zrtp, Sdes)
*/
inline void setAudioRtpType(RtpMethod type) { _rtpSessionType = type; }
/**
* @param Set internal audio rtp session type (Symmetric, Zrtp, Sdes)
*/
inline void setAudioRtpType(RtpMethod type) { _rtpSessionType = type; }
/**
* Manually set the srtpEnable option (usefull for RTP fallback)
@ -127,35 +127,43 @@ namespace sfl {
*/
void setHelloHashEnabled(bool enable){ _helloHashEnabled = enable; }
/**
* Get the current AudioZrtpSession. Throws an AudioRtpFactoryException
* if the current rtp thread is null, or if it's not of the correct type.
* @return The current AudioZrtpSession thread.
*/
sfl::AudioZrtpSession * getAudioZrtpSession();
/**
* Get the current AudioZrtpSession. Throws an AudioRtpFactoryException
* if the current rtp thread is null, or if it's not of the correct type.
* @return The current AudioZrtpSession thread.
*/
sfl::AudioZrtpSession * getAudioZrtpSession();
/**
* Set remote cryptographic info. Should be called after negotiation in SDP
* Set remote cryptographic info. Should be called after negotiation in SDP
* offer/answer session.
*/
void setRemoteCryptoInfo(sfl::SdesNegotiator& nego);
*/
void setRemoteCryptoInfo(sfl::SdesNegotiator& nego);
/**
* Send DTMF over RTP (RFC2833). The timestamp and sequence number must be
* incremented as if it was microphone audio. This function change the payload type of the rtp session,
* send the appropriate DTMF digit using this payload, discard coresponding data from mainbuffer and get
* back the codec payload for further audio processing.
*/
void sendDtmfDigit(int digit);
private:
void * _rtpSession;
RtpMethod _rtpSessionType;
ost::Mutex _audioRtpThreadMutex;
private:
void * _rtpSession;
RtpMethod _rtpSessionType;
ost::Mutex _audioRtpThreadMutex;
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
bool _srtpEnabled;
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
bool _srtpEnabled;
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
int _keyExchangeProtocol;
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
int _keyExchangeProtocol;
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
bool _helloHashEnabled;
};
// Field used when initializinga udio rtp session
// May be set manually or from config using initAudioRtpConfig
bool _helloHashEnabled;
};
}
#endif // __AUDIO_RTP_FACTORY_H__

View File

@ -25,6 +25,7 @@
#include <iostream>
#include <exception>
#include <list>
#include "global.h"
@ -43,6 +44,7 @@ namespace sfl {
static const int schedulingTimeout = 100000;
static const int expireTimeout = 1000000;
class AudioRtpSessionException: public std::exception
{
virtual const char* what() const throw()
@ -51,6 +53,14 @@ namespace sfl {
}
};
typedef struct DtmfEvent {
ost::RTPPacket::RFC2833Payload payload;
int length;
bool newevent;
} DtmfEvent;
typedef list<DtmfEvent *> EventQueue;
template <typename D>
class AudioRtpSession : public ost::Thread, public ost::TimerPort {
public:
@ -72,6 +82,16 @@ namespace sfl {
*/
void updateDestinationIpAddress(void);
void putDtmfEvent(int digit);
/**
* Send DTMF over RTP (RFC2833). The timestamp and sequence number must be
* incremented as if it was microphone audio. This function change the payload type of the rtp session,
* send the appropriate DTMF digit using this payload, discard coresponding data from mainbuffer and get
* back the codec payload for further audio processing.
*/
void sendDtmfEvent(sfl::DtmfEvent *dtmf);
private:
void initBuffers(void);
@ -178,6 +198,11 @@ namespace sfl {
* Time counter used to trigger incoming call notification
*/
int _countNotificationTime;
/**
* EventQueue used to store list of DTMF-
*/
EventQueue _eventQueue;
protected:
SIPCall * _ca;
@ -316,8 +341,8 @@ namespace sfl {
void AudioRtpSession<D>::setDestinationIpAddress(void)
{
if (_ca == NULL) {
_warn ("Rtp: Sipcall is gone.");
throw AudioRtpSessionException();
_warn ("Rtp: Sipcall is gone.");
throw AudioRtpSessionException();
}
_info ("RTP: Setting IP address for the RTP session");
@ -338,8 +363,8 @@ namespace sfl {
_ca->getLocalSDP()->get_remote_ip().data(), _remote_port);
if (! static_cast<D*>(this)->addDestination (_remote_ip, _remote_port)) {
_warn("Rtp: Can't add new destination to session!");
return;
_warn("Rtp: Can't add new destination to session!");
return;
}
}
@ -357,6 +382,68 @@ namespace sfl {
setDestinationIpAddress();
}
template<typename D>
void AudioRtpSession<D>::putDtmfEvent(int digit)
{
sfl::DtmfEvent *dtmf = new sfl::DtmfEvent();
dtmf->payload.event = digit;
dtmf->payload.ebit = false; // end of event bit
dtmf->payload.rbit = false; // reserved bit
dtmf->payload.duration = 1; // duration for this event
dtmf->newevent = true;
dtmf->length = 1000;
_eventQueue.push_back(dtmf);
_debug("RTP: Put Dtmf Event %d", _eventQueue.size());
}
template<typename D>
void AudioRtpSession<D>::sendDtmfEvent(sfl::DtmfEvent *dtmf)
{
_debug("RTP: Send Dtmf %d", _eventQueue.size());
_timestamp += 160;
// discard equivalent size of audio
processDataEncode();
// change Payload type for DTMF payload
static_cast<D*>(this)->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) 101, 8000));
// Set marker in case this is a new Event
if(dtmf->newevent)
static_cast<D*>(this)->setMark (true);
static_cast<D*>(this)->putData (_timestamp, (const unsigned char*)(&(dtmf->payload)), sizeof(ost::RTPPacket::RFC2833Payload));
// This is no more a new event
if(dtmf->newevent) {
dtmf->newevent = false;
static_cast<D*>(this)->setMark (false);
}
// get back the payload to audio
static_cast<D*>(this)->setPayloadFormat (ost::StaticPayloadFormat ( (ost::StaticPayloadType) _audiocodec->getPayload()));
// decrease length remaining to process for this event
dtmf->length -= 160;
dtmf->payload.duration += 1;
// next packet is going to be the last one
if((dtmf->length - 160) < 160)
dtmf->payload.ebit = true;
if(dtmf->length < 160) {
delete dtmf;
_eventQueue.pop_front();
}
}
template <typename D>
int AudioRtpSession<D>::processDataEncode(void)
{
@ -364,7 +451,7 @@ namespace sfl {
assert(_audiolayer);
int _mainBufferSampleRate = _manager->getAudioDriver()->getMainBuffer()->getInternalSamplingRate();
int _mainBufferSampleRate = _manager->getAudioDriver()->getMainBuffer()->getInternalSamplingRate();
// compute codec framesize in ms
float fixed_codec_framesize = computeCodecFrameSize (_audiocodec->getFrameSize(), _audiocodec->getClockRate());
@ -399,7 +486,7 @@ namespace sfl {
} else {
_nSamplesMic = nbSample;
_nSamplesMic = nbSample;
// no resampling required
compSize = _audiocodec->codecEncode (_micDataEncoded, _micData, nbSample*sizeof (int16));
@ -472,7 +559,6 @@ namespace sfl {
// 4. send it
// Increment timestamp for outgoing packet
_timestamp += _codecFrameSize;
if (!_audiolayer) {
@ -518,10 +604,16 @@ namespace sfl {
unsigned int 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 (spkrData, size);
}
// DTMF over RTP, size must be over 4 in order to process it as voice data
if(size > 4) {
processDataDecode (spkrData, size);
}
else {
_debug("RTP: Received an RTP event with payload: %d", adu->getType());
ost::RTPPacket::RFC2833Payload *dtmf = (ost::RTPPacket::RFC2833Payload *)adu->getData();
_debug("RTP: Data received %d", dtmf->event);
}
}
template <typename D>
@ -580,7 +672,12 @@ namespace sfl {
// Send session
sessionWaiting = static_cast<D*>(this)->isWaiting();
sendMicData ();
if(_eventQueue.size() > 0) {
sendDtmfEvent(_eventQueue.front());
}
else {
sendMicData ();
}
// Recv session
receiveSpeakerData ();
@ -594,8 +691,7 @@ namespace sfl {
_ca->recAudio.recData (_micData,_nSamplesMic);
}
// ost::MutexLock unlock(*(_manager->getAudioLayerMutex()));
_manager->getAudioLayerMutex()->leave();
_manager->getAudioLayerMutex()->leave();
// Let's wait for the next transmit cycle
Thread::sleep (TimerPort::getTimer());

View File

@ -33,12 +33,6 @@
#include <cstring>
#include <cerrno>
static uint8 mk[] = { 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f };
static uint8 ms[] = { 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d };
namespace sfl
{

View File

@ -1461,22 +1461,8 @@ bool ManagerImpl::sendDtmf (const CallID& id, char code) {
bool returnValue = false;
switch (sendType) {
case 0: // SIP INFO
playDtmf(code);
returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
break;
case 1: // Audio way
break;
case 2: // rfc 2833
break;
default: // unknown - error config?
break;
}
playDtmf(code);
returnValue = getAccountLink(accountid)->carryingDTMFdigits(id, code);
return returnValue;
}
@ -3291,6 +3277,8 @@ std::map<std::string, std::string> ManagerImpl::getAccountDetails (
accountID, STUN_ENABLE)));
a.insert(std::pair<std::string, std::string>(STUN_SERVER, getConfigString(
accountID, STUN_SERVER)));
a.insert(std::pair<std::string, std::string>(ACCOUNT_DTMF_TYPE, getConfigString(
accountID, ACCOUNT_DTMF_TYPE)));
RegistrationState state;
std::string registrationStateCode;
@ -3575,6 +3563,7 @@ void ManagerImpl::setAccountDetails (const std::string& accountID,
std::string publishedPort;
std::string stunEnable;
std::string stunServer;
std::string dtmfType;
std::string srtpEnable;
std::string srtpRtpFallback;
std::string zrtpDisplaySas;
@ -3634,6 +3623,10 @@ void ManagerImpl::setAccountDetails (const std::string& accountID,
stunServer = iter->second;
}
if((iter = map_cpy.find(ACCOUNT_DTMF_TYPE)) != map_cpy.end()) {
dtmfType = iter->second;
}
if ((iter = map_cpy.find(SRTP_ENABLE)) != map_cpy.end()) {
srtpEnable = iter->second;
}
@ -3763,6 +3756,7 @@ void ManagerImpl::setAccountDetails (const std::string& accountID,
setConfig(accountID, STUN_ENABLE, stunEnable);
setConfig(accountID, STUN_SERVER, stunServer);
setConfig(accountID, ACCOUNT_DTMF_TYPE, dtmfType);
// The TLS listener is unique and globally defined through IP2IP_PROFILE
if (accountID == IP2IP_PROFILE)

View File

@ -134,7 +134,7 @@ int Sdp::create_local_offer (CodecOrder selectedCodecs) {
pj_status_t status;
_debug ("Create local offer");
_info("SDP: Create local offer");
// Build local media capabilities
set_local_media_capabilities (selectedCodecs);
@ -173,12 +173,12 @@ int Sdp::create_initial_offer (CodecOrder selectedCodecs) {
pj_status_t status;
pjmedia_sdp_neg_state state;
_debug ("Create initial offer");
_info("SDP: Create initial offer");
// Build the SDP session descriptor
status = create_local_offer (selectedCodecs);
if (status != PJ_SUCCESS) {
_warn (" Error: Failed to create initial offer");
_error ("SDP: Error: Failed to create initial offer");
return status;
}
@ -186,7 +186,7 @@ int Sdp::create_initial_offer (CodecOrder selectedCodecs) {
status = pjmedia_sdp_neg_create_w_local_offer (_pool, get_local_sdp_session(), &_negociator);
if (status != PJ_SUCCESS) {
_error (" Error: Failed to create an initial SDP negociator");
_error ("SDP: Error: Failed to create an initial SDP negociator");
return status;
}
@ -194,8 +194,6 @@ int Sdp::create_initial_offer (CodecOrder selectedCodecs) {
PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1);
_debug (" Initial offer created succesfully");
return PJ_SUCCESS;
}
@ -213,6 +211,7 @@ int Sdp::receiving_initial_offer (pjmedia_sdp_session* remote, CodecOrder select
status = create_local_offer (selectedCodecs);
if (status != PJ_SUCCESS) {
_error ("SDP: Error: Failed to create initial offer");
return status;
}
@ -220,7 +219,7 @@ int Sdp::receiving_initial_offer (pjmedia_sdp_session* remote, CodecOrder select
this->set_media_transport_info_from_remote_sdp (remote);
status = pjmedia_sdp_neg_create_w_remote_offer (_pool,
get_local_sdp_session(), remote, &_negociator);
get_local_sdp_session(), remote, &_negociator);
PJ_ASSERT_RETURN (status == PJ_SUCCESS, 1);
@ -240,17 +239,17 @@ pj_status_t Sdp::check_sdp_answer (pjsip_inv_session *inv, pjsip_rx_data *rdata)
message = rdata->msg_info.msg;
if (message == NULL) {
_error ("No message");
_error ("SDP: No message");
return PJMEDIA_SDP_EINSDP;
}
if (message->body == NULL) {
_error ("Empty message body");
_error ("SDP: Empty message body");
return PJMEDIA_SDP_EINSDP;
}
if (pj_stricmp (&message->body->content_type.type, &str_application) || pj_stricmp (&message->body->content_type.subtype, &str_sdp)) {
_error ("Incoming Message does not contain SDP");
_error ("SDP: Incoming Message does not contain SDP");
return PJMEDIA_SDP_EINSDP;
}
@ -262,17 +261,17 @@ pj_status_t Sdp::check_sdp_answer (pjsip_inv_session *inv, pjsip_rx_data *rdata)
}
if (status != PJ_SUCCESS) {
_debug ("SDP cannot be validated");
_warn ("SDP: cannot be validated");
return PJMEDIA_SDP_EINSDP;
}
// This is an answer
_debug ("Got SDP answer %s", pjsip_rx_data_get_info (rdata));
_debug ("SDP: Got SDP answer %s", pjsip_rx_data_get_info (rdata));
status = pjmedia_sdp_neg_set_remote_answer (inv->pool, inv->neg, remote_sdp);
if (status != PJ_SUCCESS) {
_debug ("An error occured while processing remote answer %s", pjsip_rx_data_get_info (rdata));
_error ("SDP: Error: while processing remote answer %s", pjsip_rx_data_get_info (rdata));
return PJMEDIA_SDP_EINSDP;
}
@ -359,7 +358,6 @@ void Sdp::sdp_add_media_description()
}
}
// @TODO crypto should be a vector of string
void Sdp::sdp_add_sdes_attribute (std::vector<std::string>& crypto)
{

View File

@ -33,7 +33,7 @@ SIPAccount::SIPAccount (const AccountID& accountID)
, _publishedIpAddress ("")
, _localPort (atoi (DEFAULT_SIP_PORT))
, _publishedPort (atoi (DEFAULT_SIP_PORT))
, _tlsListenerPort (atoi (DEFAULT_SIP_TLS_PORT))
, _tlsListenerPort (atoi (DEFAULT_SIP_TLS_PORT))
, _transportType (PJSIP_TRANSPORT_UNSPECIFIED)
, _transport (NULL)
, _resolveOnce (false)
@ -42,6 +42,7 @@ SIPAccount::SIPAccount (const AccountID& accountID)
, _realm (DEFAULT_REALM)
, _authenticationUsername ("")
, _tlsSetting (NULL)
, _dtmfType(OVERRTP)
, _displayName ("")
{
@ -362,6 +363,11 @@ void SIPAccount::loadConfig()
setPublishedAddress (Manager::instance().getConfigString (_accountID, PUBLISHED_ADDRESS));
if(Manager::instance().getConfigString (_accountID, ACCOUNT_DTMF_TYPE) == OVERRTPSTR)
_dtmfType = OVERRTP;
else
_dtmfType = SIPINFO;
// Init TLS settings if the user wants to use TLS
bool tlsEnabled = Manager::instance().getConfigBool (_accountID, TLS_ENABLE);

View File

@ -31,6 +31,11 @@
#include "pjsip/sip_transport_tls.h"
#include "pjsip/sip_types.h"
enum DtmfType { OVERRTP, SIPINFO};
#define OVERRTPSTR "overrtp"
#define SIPINFOSTR "sipinfo"
class SIPVoIPLink;
/**
@ -95,7 +100,7 @@ class SIPAccount : public Account
*
* @return A string describing the expiration value.
*/
inline std::string& getRegistrationExpire(void) { return _registrationExpire; }
inline std::string& getRegistrationExpire(void) { return _registrationExpire; }
/**
* Setting the Expiration Interval of Contact Addresses.
@ -297,11 +302,15 @@ class SIPAccount : public Account
*/
inline pjsip_transport_type_e getTransportType(void) { return _transportType; }
inline pjsip_transport* getAccountTransport (void) { return _transport; }
inline pjsip_transport* getAccountTransport (void) { return _transport; }
inline void setAccountTransport (pjsip_transport *transport) { _transport = transport; }
inline void setAccountTransport (pjsip_transport *transport) { _transport = transport; }
std::string getTransportMapKey(void);
std::string getTransportMapKey(void);
DtmfType getDtmfType(void) { return _dtmfType; }
void setDtmfType(DtmfType type) { _dtmfType = type; }
private:
@ -353,22 +362,22 @@ class SIPAccount : public Account
// Network settings
std::string _registrationExpire;
// interface name on which this account is bound
std::string _interface;
// interface name on which this account is bound
std::string _interface;
// Flag which determine if _localIpAddress or _publishedIpAddress is used in
// Flag which determine if _localIpAddress or _publishedIpAddress is used in
// sip headers
bool _publishedSameasLocal;
bool _publishedSameasLocal;
std::string _publishedIpAddress;
pj_uint16_t _localPort;
pj_uint16_t _publishedPort;
/**
* The global TLS listener port which can be configured through the IP2IP_PROFILE
*/
pj_uint16_t _tlsListenerPort;
/**
* The global TLS listener port which can be configured through the IP2IP_PROFILE
*/
pj_uint16_t _tlsListenerPort;
pjsip_transport_type_e _transportType;
@ -391,8 +400,10 @@ class SIPAccount : public Account
// The STUN server name, if applicable
pj_str_t _stunServerName;
// The STUN server port, if applicable
pj_uint16_t _stunPort;
// The STUN server port, if applicable
pj_uint16_t _stunPort;
DtmfType _dtmfType;
// Display Name that can be used in SIP URI.
std::string _displayName;

View File

@ -738,7 +738,7 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl)
account = dynamic_cast<SIPAccount *> (Manager::instance().getAccount (Manager::instance().getAccountFromCall (id)));
if (account == NULL) {
_debug ("Error retrieving the account to the make the call with");
_error ("UserAgent: Error: Could not retrieving account to make call with");
call->setConnectionState (Call::Disconnected);
call->setState (Call::Error);
delete call;
@ -764,16 +764,17 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl)
loadSIPLocalIP (&addrSdp);
try {
_debug ("Creating new rtp session in newOutgoingCall");
call->getAudioRtp()->initAudioRtpConfig (call);
_info ("UserAgent: Creating new rtp session");
call->getAudioRtp()->initAudioRtpConfig (call);
call->getAudioRtp()->initAudioRtpSession (call);
} catch (...) {
_error ("Failed to create rtp thread from newOutGoingCall");
_error ("UserAgent: Error: Failed to create rtp thread from newOutGoingCall");
}
call->initRecFileName();
_debug ("Try to make a call to: %s with call ID: %s", toUrl.data(), id.data());
_debug ("UserAgent: Try to make a call to: %s with call ID: %s", toUrl.data(), id.data());
// Building the local SDP offer
call->getLocalSDP()->set_ip_address (addrSdp);
status = call->getLocalSDP()->create_initial_offer (account->getActiveCodecs ());
@ -1234,68 +1235,104 @@ SIPVoIPLink::getCurrentCodecName()
bool
SIPVoIPLink::carryingDTMFdigits (const CallID& id, char code)
{
SIPCall *call = getSIPCall (id);
SIPCall *call;
int duration;
const int body_len = 1000;
char *dtmf_body;
pj_status_t status;
pjsip_tx_data *tdata;
pj_str_t methodName, content;
pjsip_method method;
pjsip_media_type ctype;
call = getSIPCall (id);
if (call==0) {
_debug ("Call doesn't exist");
if (!call) {
_error ("UserAgent: Error: Call doesn't exist while sending DTMF");
return false;
}
duration = Manager::instance().getConfigInt (SIGNALISATION, PULSE_LENGTH);
AccountID accountID = Manager::instance().getAccountFromCall(id);
SIPAccount *account = static_cast<SIPAccount *>(Manager::instance().getAccount(accountID));
dtmf_body = new char[body_len];
snprintf (dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", code, duration);
pj_strdup2 (_pool, &methodName, "INFO");
pjsip_method_init_np (&method, &methodName);
/* Create request message. */
status = pjsip_dlg_create_request (call->getInvSession()->dlg, &method, -1, &tdata);
if (status != PJ_SUCCESS) {
_debug ("UserAgent: Unable to create INFO request -- %d", status);
return false;
if(!account) {
_error ("UserAgent: Error: Account not found while sending DTMF");
return false;
}
/* Get MIME type */
pj_strdup2 (_pool, &ctype.type, "application");
DtmfType type = account->getDtmfType();
pj_strdup2 (_pool, &ctype.subtype, "dtmf-relay");
/* Create "application/dtmf-relay" message body. */
pj_strdup2 (_pool, &content, dtmf_body);
tdata->msg->body = pjsip_msg_body_create (tdata->pool, &ctype.type, &ctype.subtype, &content);
if (tdata->msg->body == NULL) {
_debug ("UserAgent: Unable to create msg body!");
pjsip_tx_data_dec_ref (tdata);
return false;
}
/* Send the request. */
status = pjsip_dlg_send_request (call->getInvSession()->dlg, tdata, getModId(), NULL);
if (status != PJ_SUCCESS) {
_debug ("UserAgent: Unable to send MESSAGE request -- %d", status);
return false;
if(type == OVERRTP)
dtmfOverRtp(call, code);
else if(type == SIPINFO)
dtmfSipInfo(call, code);
else {
_error("UserAgent: Error: Dtmf type does not exist");
return false;
}
return true;
}
bool
SIPVoIPLink::dtmfSipInfo(SIPCall *call, char code)
{
int duration;
const int body_len = 1000;
char *dtmf_body;
pj_status_t status;
pjsip_tx_data *tdata;
pj_str_t methodName, content;
pjsip_method method;
pjsip_media_type ctype;
duration = Manager::instance().getConfigInt (SIGNALISATION, PULSE_LENGTH);
dtmf_body = new char[body_len];
snprintf (dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", code, duration);
pj_strdup2 (_pool, &methodName, "INFO");
pjsip_method_init_np (&method, &methodName);
/* Create request message. */
status = pjsip_dlg_create_request (call->getInvSession()->dlg, &method, -1, &tdata);
if (status != PJ_SUCCESS) {
_debug ("UserAgent: Unable to create INFO request -- %d", status);
return false;
}
/* Get MIME type */
pj_strdup2 (_pool, &ctype.type, "application");
pj_strdup2 (_pool, &ctype.subtype, "dtmf-relay");
/* Create "application/dtmf-relay" message body. */
pj_strdup2 (_pool, &content, dtmf_body);
tdata->msg->body = pjsip_msg_body_create (tdata->pool, &ctype.type, &ctype.subtype, &content);
if (tdata->msg->body == NULL) {
_debug ("UserAgent: Unable to create msg body!");
pjsip_tx_data_dec_ref (tdata);
return false;
}
/* Send the request. */
status = pjsip_dlg_send_request (call->getInvSession()->dlg, tdata, getModId(), NULL);
if (status != PJ_SUCCESS) {
_debug ("UserAgent: Unable to send MESSAGE request -- %d", status);
return false;
}
return true;
}
bool
SIPVoIPLink::dtmfOverRtp(SIPCall* call, char code)
{
call->getAudioRtp()->sendDtmfDigit(atoi(&code));
return true;
}
bool
SIPVoIPLink::SIPOutgoingInvite (SIPCall* call)
{
@ -1497,20 +1534,20 @@ void
SIPVoIPLink::SIPCallAnswered (SIPCall *call, pjsip_rx_data *rdata)
{
_debug ("SIPCallAnswered");
_info ("UserAgent: SIP call answered");
if (!call) {
_debug ("! SIP Failure: unknown call");
_warn ("UserAgent: Error: SIP failure, unknown call");
return;
}
if (call->getConnectionState() != Call::Connected) {
_debug ("Update call state , id = %s", call->getCallId().c_str());
_debug ("UserAgent: Update call state , id = %s", call->getCallId().c_str());
call->setConnectionState (Call::Connected);
call->setState (Call::Active);
Manager::instance().peerAnsweredCall (call->getCallId());
} else {
_debug ("* SIP Info: Answering call (on/off hold to send ACK)");
_debug ("UserAgent: Answering call (on/off hold to send ACK)");
}
}
@ -2367,7 +2404,10 @@ int SIPVoIPLink::createUdpTransport (AccountID id)
}
if(listeningAddress == "" || listeningPort == 0) {
_error("UserAgent: Error invalid address for new udp transport");
return !PJ_SUCCESS;
}
//strcpy (tmpIP, listeningAddress.data());
/* Init published name */
pj_bzero (&a_name, sizeof (pjsip_host_port));
@ -2782,6 +2822,7 @@ void SIPVoIPLink::shutdownSipTransport(const AccountID& accountID)
}
bool SIPVoIPLink::loadSIPLocalIP (std::string *addr)
{
@ -3076,7 +3117,7 @@ void call_on_state_changed (pjsip_inv_session *inv, pjsip_event *e)
status = call->getLocalSDP()->check_sdp_answer (inv, rdata);
if (status != PJ_SUCCESS) {
_debug ("Failed to check_incoming_sdp in call_on_state_changed");
_warn ("UserAgent: Failed to check_incoming_sdp in call_on_state_changed");
return;
}
}
@ -3434,12 +3475,12 @@ mod_on_rx_request (pjsip_rx_data *rdata)
// No need to go any further on incoming ACK
if (rdata->msg_info.msg->line.req.method.id == PJSIP_ACK_METHOD) {
_debug("UserAgent: received an ACK");
_info("UserAgent: received an ACK");
return true;
}
// Handle the incoming call invite in this function
_debug("UserAgent: Receiving REQUEST using transport: %s %s (refcnt=%d)",
_info("UserAgent: Receiving REQUEST using transport: %s %s (refcnt=%d)",
rdata->tp_info.transport->obj_name,
rdata->tp_info.transport->info,
(int)pj_atomic_get(rdata->tp_info.transport->ref_cnt));
@ -3470,7 +3511,7 @@ mod_on_rx_request (pjsip_rx_data *rdata)
/* If we can't find any voIP link to handle the incoming call */
if (!link) {
_warn("ERROR: cannot retrieve the voiplink from the account ID...");
_warn("UserAgent: Error: cannot retrieve the voiplink from the account ID...");
pj_strdup2 (_pool, &reason, "ERROR: cannot retrieve the voip link from account");
pjsip_endpt_respond_stateless (_endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR,
&reason, NULL, NULL);
@ -3582,7 +3623,7 @@ mod_on_rx_request (pjsip_rx_data *rdata)
/************************************************************************************************/
_debug ("UserAgent: Create a new call");
_info ("UserAgent: Create a new call");
// Generate a new call ID for the incoming call!
id = Manager::instance().getNewCallID();
@ -3639,7 +3680,7 @@ mod_on_rx_request (pjsip_rx_data *rdata)
// Notify UI there is an incoming call
_debug ("Add call to account link");
_debug ("UserAgent: Add call to account link");
if (Manager::instance().incomingCall (call, account_id)) {
// Add this call to the callAccountMap in ManagerImpl
@ -3672,7 +3713,8 @@ mod_on_rx_request (pjsip_rx_data *rdata)
if (status!=PJ_SUCCESS) {
delete call; call = NULL;
pj_strdup2 (_pool, &reason, "fail in receiving local offer");
_warn("UserAgent: fail in receiving initial offer");
pj_strdup2 (_pool, &reason, "fail in receiving initial offer");
pjsip_endpt_respond_stateless (_endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR,
&reason, NULL, NULL);
return false;
@ -3683,6 +3725,7 @@ mod_on_rx_request (pjsip_rx_data *rdata)
status = pjsip_dlg_create_uas (pjsip_ua_instance(), rdata, NULL, &dialog);
if (status != PJ_SUCCESS) {
delete call; call = NULL;
_warn("UserAgent: Error: Failed to create uas dialog");
pj_strdup2 (_pool, &reason, "fail to create uas dialog");
pjsip_endpt_respond_stateless (_endpt, rdata, PJSIP_SC_INTERNAL_SERVER_ERROR,
&reason, NULL, NULL);

View File

@ -178,13 +178,23 @@ class SIPVoIPLink : public VoIPLink
bool refuse (const CallID& id);
/**
* Send DTMF
* Send DTMF refering to account configuration
* @param id The call identifier
* @param code The char code
* @return bool True on success
*/
bool carryingDTMFdigits(const CallID& id, char code);
/**
* Send Dtmf using SIP INFO message
*/
bool dtmfSipInfo(SIPCall *call, char code);
/**
* Send Dtmf over RTP
*/
bool dtmfOverRtp(SIPCall* call, char code);
/**
* Terminate every call not hangup | brutal | Protected by mutex
*/

186
sippxml/accountcalluac.xml Normal file
View File

@ -0,0 +1,186 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<!-- 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 2 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., -->
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
<scenario name="accountcall_client">
<send retrans="500">
<![CDATA[
REGISTER sip:[remote_ip] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
Max-Forward: 70
From: <sip:27182@[remote_ip]:[remote_port]>;tag=[call_number]
To: <sip:27182@[remote_ip]:[remote_port]>
Call-ID: REG///[call_id]
CSeq: 1 REGISTER
Contact: <sip:27182@[remote_ip]:[remote_port]>
Content-Length: 0
Expires: 300
]]>
</send>
<recv response="401" auth="true">
</recv>
<send retrans="500">
<![CDATA[
REGISTER sip:[remote_ip] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
Max-Forwards: 70
From: <sip:27182@[remote_ip]:[remote_port]>;tag=[call_number]
To: <sip:27182@[remote_ip]:[remote_port]>
Call-ID: REG///[call_id]
CSeq: 2 REGISTER
Contact: <sip:27182@[remote_ip]:[remote_port]>
Content-Length: 0
Expires: 300
[authentication username=27182 password=1234]
]]>
</send>
<recv response="200">
</recv>
<pause milliseconds="200"/>
<send retrans="500">
<![CDATA[
INVITE sip:2000@[remote_ip] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
From: <sip:27182@[remote_ip]:[remote_port]>;tag=[call_number]
To: <sip:2000@[remote_ip]:[remote_port]>
Call-ID: [call_id]
CSeq: 3 INVITE
Contact: sip:27182@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Functional Test
Content-Type: application/sdp
Content-Length: [len]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv response="401" auth="true">
</recv>
<pause milliseconds="200"/>
<send>
<![CDATA[
ACK sip:27182@[remote_ip] SIP/2.0
Max-Forwards: 70
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: <sip:27182@[remote_ip]:[remote_port]>;tag=[call_number]
To: <sip:2000@[remote_ip]:[remote_port]>
Call-ID: [call_id]
CSeq: 4 ACK
Subject: Functional Test
Content-Length: 0
]]>
</send>
<send retrans="500">
<![CDATA[
INVITE sip:2000@[remote_ip] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
From: <sip:27182@:[remote_ip]:[remote_port]>;tag=[call_number]
To: <sip:2000@[remote_ip]:[remote_port]>
Call-ID: [call_id]
CSeq: 5 INVITE
Contact: sip:27182@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Functional Test
Content-Type: application/sdp
Content-Length: [len]
[authentication username=27182 password=1234]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv response="100">
</recv>
<recv response="180">
</recv>
<recv response="200">
</recv>
<send>
<![CDATA[
ACK sip:2000@192.168.50.79 SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: <sip:27182@[local_ip]:[local_port]>;tag=[call_number]
To: <sip:2000@192.168.50.79:[remote_port]>
Call-ID: [call_id]
CSeq: 5 ACK
Contact: sip:27182@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Functional Test
Content-Length: 0
]]>
</send>
<send retrans="500">
<![CDATA[
BYE sip:2000@192.168.50.79 SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: <sip:27182@[local_ip]:[local_port]>;tag=[call_number]
To: <sip:2000@192.168.50.79:[remote_port]>
Call-ID: [call_id]
CSeq: 6 BYE
Contact: sip:27182@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Functional Test
Content-Length: 0
]]>
</send>
<pause milliseconds="1000"/>
</scenario>

159
sippxml/accountcalluas.xml Normal file
View File

@ -0,0 +1,159 @@
<?xml version="1.0" encoding="ISO-8859-1" ?>
<!DOCTYPE scenario SYSTEM "sipp.dtd">
<!-- 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 2 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., -->
<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
<scenario name="branch_server">
<recv request="REGISTER">
</recv>
<send>
<![CDATA[
SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
Expires: 300
]]>
</send>
<!-- Set variable 3 if the ua is of the form ua2... -->
<recv request="INVITE" crlf="true">
<action>
<ereg regexp="ua2"
search_in="hdr"
header="From: "
assign_to="3"/>
</action>
</recv>
<!-- send 180 then trying if variable 3 is set -->
<send next="1" test="3">
<![CDATA[
SIP/2.0 180 Ringing
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<!-- if not, send a 403 error then skip to wait for a BYE -->
<send next="2">
<![CDATA[
SIP/2.0 403 Error
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<label id="1"/>
<send>
<![CDATA[
SIP/2.0 100 Trying
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<send retrans="500">
<![CDATA[
SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Type: application/sdp
Content-Length: 136
v=0
o=user1 53655765 2353687637 IN IP4 127.0.0.1
s=-
t=0 0
c=IN IP4 [media_ip]
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv request="ACK"
optional="true"
rtd="true"
crlf="true">
</recv>
<label id="2"/>
<recv request="BYE">
</recv>
<send>
<![CDATA[
SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<!-- Keep the call open for a while in case the 200 is lost to be -->
<!-- able to retransmit it if we receive the BYE again. -->
<pause milliseconds="4000"/>
<!-- Definition of the response time repartition table (unit is ms) -->
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<!-- Definition of the call length repartition table (unit is ms) -->
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>

85
sippxml/ip2ipcalluac.xml Normal file
View File

@ -0,0 +1,85 @@
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="Basic Sipstone UAC">
<send retrans="500">
<![CDATA[
INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
To: sut <sip:[service]@[remote_ip]:[remote_port]>
Call-ID: [call_id]
CSeq: 1 INVITE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Type: application/sdp
Content-Length: [len]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv response="100"
optional="true">
</recv>
<recv response="180" optional="true">
</recv>
<recv response="200" rtd="true">
</recv>
<send>
<![CDATA[
ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
Call-ID: [call_id]
CSeq: 1 ACK
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Length: 0
]]>
</send>
<pause/>
<send retrans="500">
<![CDATA[
BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
Call-ID: [call_id]
CSeq: 2 BYE
Contact: sip:sipp@[local_ip]:[local_port]
Max-Forwards: 70
Subject: Performance Test
Content-Length: 0
]]>
</send>
<recv response="200" crlf="true">
</recv>
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>

80
sippxml/ip2ipcalluas.xml Normal file
View File

@ -0,0 +1,80 @@
<?xml version="1.0" encoding="ISO-8859-1" ?> <!DOCTYPE scenario SYSTEM "sipp.dtd">
<scenario name="Basic UAS responder">
<recv request="INVITE" crlf="true">
</recv>
<send>
<![CDATA[
SIP/2.0 180 Ringing
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<send retrans="500">
<![CDATA[
SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:];tag=[call_number]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Type: application/sdp
Content-Length: [len]
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
m=audio [media_port] RTP/AVP 0
a=rtpmap:0 PCMU/8000
]]>
</send>
<recv request="ACK"
optional="true"
rtd="true"
crlf="true">
</recv>
<recv request="BYE">
</recv>
<send>
<![CDATA[
SIP/2.0 200 OK
[last_Via:]
[last_From:]
[last_To:]
[last_Call-ID:]
[last_CSeq:]
Contact: <sip:[local_ip]:[local_port];transport=[transport]>
Content-Length: 0
]]>
</send>
<pause milliseconds="4000"/>
<ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/>
<CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/>
</scenario>

460
sippxml/sippusage.txt Normal file
View File

@ -0,0 +1,460 @@
Usage:
sipp remote_host[:remote_port] [options]
Available options:
-v : Display version and copyright information.
-aa : Enable automatic 200 OK answer for INFO, UPDATE and
NOTIFY messages.
-auth_uri : Force the value of the URI for authentication.
By default, the URI is composed of
remote_ip:remote_port.
-base_cseq : Start value of [cseq] for each call.
-bg : Launch SIPp in background mode.
-bind_local : Bind socket to local IP address, i.e. the local IP
address is used as the source IP address. If SIPp runs
in server mode it will only listen on the local IP
address instead of all IP addresses.
-buff_size : Set the send and receive buffer size.
-calldebug_file : Set the name of the call debug file.
-calldebug_overwrite: Overwrite the call debug file (default true).
-cid_str : Call ID string (default %u-%p@%s). %u=call_number,
%s=ip_address, %p=process_number, %%=% (in any order).
-ci : Set the local control IP address
-cp : Set the local control port number. Default is 8888.
-d : Controls the length of calls. More precisely, this
controls the duration of 'pause' instructions in the
scenario, if they do not have a 'milliseconds' section.
Default value is 0 and default unit is milliseconds.
-deadcall_wait : How long the Call-ID and final status of calls should be
kept to improve message and error logs (default unit is
ms).
-default_behaviors: Set the default behaviors that SIPp will use. Possbile
values are:
- all Use all default behaviors
- none Use no default behaviors
- bye Send byes for aborted calls
- abortunexp Abort calls on unexpected messages
- pingreply Reply to ping requests
If a behavior is prefaced with a -, then it is turned
off. Example: all,-bye
-error_file : Set the name of the error log file.
-error_overwrite : Overwrite the error log file (default true).
-f : Set the statistics report frequency on screen. Default is
1 and default unit is seconds.
-fd : Set the statistics dump log report frequency. Default is
60 and default unit is seconds.
-i : Set the local IP address for 'Contact:','Via:', and
'From:' headers. Default is primary host IP address.
-inf : Inject values from an external CSV file during calls into
the scenarios.
First line of this file say whether the data is to be
read in sequence (SEQUENTIAL), random (RANDOM), or user
(USER) order.
Each line corresponds to one call and has one or more
';' delimited data fields. Those fields can be referred
as [field0], [field1], ... in the xml scenario file.
Several CSV files can be used simultaneously (syntax:
-inf f1.csv -inf f2.csv ...)
-infindex : file field
Create an index of file using field. For example -inf
users.csv -infindex users.csv 0 creates an index on the
first key.
-ip_field : Set which field from the injection file contains the IP
address from which the client will send its messages.
If this option is omitted and the '-t ui' option is
present, then field 0 is assumed.
Use this option together with '-t ui'
-l : Set the maximum number of simultaneous calls. Once this
limit is reached, traffic is decreased until the number
of open calls goes down. Default:
(3 * call_duration (s) * rate).
-log_file : Set the name of the log actions log file.
-log_overwrite : Overwrite the log actions log file (default true).
-lost : Set the number of packets to lose by default (scenario
specifications override this value).
-rtcheck : Select the retransmisison detection method: full
(default) or loose.
-m : Stop the test and exit when 'calls' calls are processed
-mi : Set the local media IP address (default: local primary
host IP address)
-master : 3pcc extended mode: indicates the master number
-max_recv_loops : Set the maximum number of messages received read per
cycle. Increase this value for high traffic level. The
default value is 1000.
-max_sched_loops : Set the maximum number of calsl run per event loop.
Increase this value for high traffic level. The default
value is 1000.
-max_reconnect : Set the the maximum number of reconnection.
-max_retrans : Maximum number of UDP retransmissions before call ends on
timeout. Default is 5 for INVITE transactions and 7 for
others.
-max_invite_retrans: Maximum number of UDP retransmissions for invite
transactions before call ends on timeout.
-max_non_invite_retrans: Maximum number of UDP retransmissions for non-invite
transactions before call ends on timeout.
-max_log_size : What is the limit for error and message log file sizes.
-max_socket : Set the max number of sockets to open simultaneously.
This option is significant if you use one socket per
call. Once this limit is reached, traffic is distributed
over the sockets already opened. Default value is 50000
-mb : Set the RTP echo buffer size (default: 2048).
-message_file : Set the name of the message log file.
-message_overwrite: Overwrite the message log file (default true).
-mp : Set the local RTP echo port number. Default is 6000.
-nd : No Default. Disable all default behavior of SIPp which
are the following:
- On UDP retransmission timeout, abort the call by
sending a BYE or a CANCEL
- On receive timeout with no ontimeout attribute, abort
the call by sending a BYE or a CANCEL
- On unexpected BYE send a 200 OK and close the call
- On unexpected CANCEL send a 200 OK and close the call
- On unexpected PING send a 200 OK and continue the call
- On any other unexpected message, abort the call by
sending a BYE or a CANCEL
-nr : Disable retransmission in UDP mode.
-nostdin : Disable stdin.
-p : Set the local port number. Default is a random free port
chosen by the system.
-pause_msg_ign : Ignore the messages received during a pause defined in
the scenario
-periodic_rtd : Reset response time partition counters each logging
interval.
-plugin : Load a plugin.
-r : Set the call rate (in calls per seconds). This value can
bechanged during test by pressing '+','_','*' or '/'.
Default is 10.
pressing '+' key to increase call rate by 1 *
rate_scale,
pressing '-' key to decrease call rate by 1 *
rate_scale,
pressing '*' key to increase call rate by 10 *
rate_scale,
pressing '/' key to decrease call rate by 10 *
rate_scale.
If the -rp option is used, the call rate is calculated
with the period in ms given by the user.
-rp : Specify the rate period for the call rate. Default is 1
second and default unit is milliseconds. This allows
you to have n calls every m milliseconds (by using -r n
-rp m).
Example: -r 7 -rp 2000 ==> 7 calls every 2 seconds.
-r 10 -rp 5s => 10 calls every 5 seconds.
-rate_scale : Control the units for the '+', '-', '*', and '/' keys.
-rate_increase : Specify the rate increase every -fd units (default is
seconds). This allows you to increase the load for each
independent logging period.
Example: -rate_increase 10 -fd 10s
==> increase calls by 10 every 10 seconds.
-rate_max : If -rate_increase is set, then quit after the rate
reaches this value.
Example: -rate_increase 10 -rate_max 100
==> increase calls by 10 until 100 cps is hit.
-no_rate_quit : If -rate_increase is set, do not quit after the rate
reaches -rate_max.
-recv_timeout : Global receive timeout. Default unit is milliseconds. If
the expected message is not received, the call times out
and is aborted.
-send_timeout : Global send timeout. Default unit is milliseconds. If a
message is not sent (due to congestion), the call times
out and is aborted.
-sleep : How long to sleep for at startup. Default unit is
seconds.
-reconnect_close : Should calls be closed on reconnect?
-reconnect_sleep : How long (in milliseconds) to sleep between the close and
reconnect?
-ringbuffer_files: How many error/message files should be kept after
rotation?
-ringbuffer_size : How large should error/message files be before they get
rotated?
-rsa : Set the remote sending address to host:port for sending
the messages.
-rtp_echo : Enable RTP echo. RTP/UDP packets received on port defined
by -mp are echoed to their sender.
RTP/UDP packets coming on this port + 2 are also echoed
to their sender (used for sound and video echo).
-rtt_freq : freq is mandatory. Dump response times every freq calls
in the log file defined by -trace_rtt. Default value is
200.
-s : Set the username part of the resquest URI. Default is
'service'.
-sd : Dumps a default scenario (embeded in the sipp executable)
-sf : Loads an alternate xml scenario file. To learn more
about XML scenario syntax, use the -sd option to dump
embedded scenarios. They contain all the necessary help.
-shortmessage_file: Set the name of the short message log file.
-shortmessage_overwrite: Overwrite the short message log file (default true).
-oocsf : Load out-of-call scenario.
-oocsn : Load out-of-call scenario.
-skip_rlimit : Do not perform rlimit tuning of file descriptor limits.
Default: false.
-slave : 3pcc extended mode: indicates the slave number
-slave_cfg : 3pcc extended mode: indicates the file where the master
and slave addresses are stored
-sn : Use a default scenario (embedded in the sipp executable).
If this option is omitted, the Standard SipStone UAC
scenario is loaded.
Available values in this version:
- 'uac' : Standard SipStone UAC (default).
- 'uas' : Simple UAS responder.
- 'regexp' : Standard SipStone UAC - with regexp and
variables.
- 'branchc' : Branching and conditional branching in
scenarios - client.
- 'branchs' : Branching and conditional branching in
scenarios - server.
Default 3pcc scenarios (see -3pcc option):
- '3pcc-C-A' : Controller A side (must be started after
all other 3pcc scenarios)
- '3pcc-C-B' : Controller B side.
- '3pcc-A' : A side.
- '3pcc-B' : B side.
-stat_delimiter : Set the delimiter for the statistics file
-stf : Set the file name to use to dump statistics
-t : Set the transport mode:
- u1: UDP with one socket (default),
- un: UDP with one socket per call,
- ui: UDP with one socket per IP address The IP
addresses must be defined in the injection file.
- t1: TCP with one socket,
- tn: TCP with one socket per call,
- l1: TLS with one socket,
- ln: TLS with one socket per call,
- c1: u1 + compression (only if compression plugin
loaded),
- cn: un + compression (only if compression plugin
loaded). This plugin is not provided with sipp.
-timeout : Global timeout. Default unit is seconds. If this option
is set, SIPp quits after nb units (-timeout 20s quits
after 20 seconds).
-timeout_error : SIPp fails if the global timeout is reached is set
(-timeout option required).
-timer_resol : Set the timer resolution. Default unit is milliseconds.
This option has an impact on timers precision.Small
values allow more precise scheduling but impacts CPU
usage.If the compression is on, the value is set to
50ms. The default value is 10ms.
-sendbuffer_warn : Produce warnings instead of errors on SendBuffer
failures.
-trace_msg : Displays sent and received SIP messages in <scenario file
name>_<pid>_messages.log
-trace_shortmsg : Displays sent and received SIP messages as CSV in
<scenario file name>_<pid>_shortmessages.log
-trace_screen : Dump statistic screens in the
<scenario_name>_<pid>_ s.log file when quitting
SIPp. Useful to get a final status report in background
mode (-bg option).
-trace_err : Trace all unexpected messages in <scenario file
name>_<pid>_errors.log.
-trace_calldebug : Dumps debugging information about aborted calls to
<scenario_name>_<pid>_calldebug.log file.
-trace_stat : Dumps all statistics in <scenario_name>_<pid>.csv file.
Use the '-h stat' option for a detailed description of
the statistics file content.
-trace_counts : Dumps individual message counts in a CSV file.
-trace_rtt : Allow tracing of all response times in <scenario file
name>_<pid>_rtt.csv.
-trace_logs : Allow tracing of <log> actions in <scenario file
name>_<pid>_logs.log.
-users : Instead of starting calls at a fixed rate, begin 'users'
calls at startup, and keep the number of calls constant.
-watchdog_interval: Set gap between watchdog timer firings. Default is 400.
-watchdog_reset : If the watchdog timer has not fired in more than this
time period, then reset the max triggers counters.
Default is 10 minutes.
-watchdog_minor_threshold: If it has been longer than this period between watchdog
executions count a minor trip. Default is 500.
-watchdog_major_threshold: If it has been longer than this period between watchdog
executions count a major trip. Default is 3000.
-watchdog_major_maxtriggers: How many times the major watchdog timer can be tripped
before the test is terminated. Default is 10.
-watchdog_minor_maxtriggers: How many times the minor watchdog timer can be tripped
before the test is terminated. Default is 120.
-ap : Set the password for authentication challenges. Default
is 'password
-tls_cert : Set the name for TLS Certificate file. Default is
'cacert.pem
-tls_key : Set the name for TLS Private Key file. Default is
'cakey.pem'
-tls_crl : Set the name for Certificate Revocation List file. If not
specified, X509 CRL is not activated.
-3pcc : Launch the tool in 3pcc mode ("Third Party call
control"). The passed ip address is depending on the
3PCC role.
- When the first twin command is 'sendCmd' then this is
the address of the remote twin socket. SIPp will try to
connect to this address:port to send the twin command
(This instance must be started after all other 3PCC
scenarii).
Example: 3PCC-C-A scenario.
- When the first twin command is 'recvCmd' then this is
the address of the local twin socket. SIPp will open
this address:port to listen for twin command.
Example: 3PCC-C-B scenario.
-tdmmap : Generate and handle a table of TDM circuits.
A circuit must be available for the call to be placed.
Format: -tdmmap {0-3}{99}{5-8}{1-31}
-key : keyword value
Set the generic parameter named "keyword" to "value".
-set : variable value
Set the global variable parameter named "variable" to
"value".
-dynamicStart : variable value
Set the start offset of dynamic_id varaiable
-dynamicMax : variable value
Set the maximum of dynamic_id variable
-dynamicStep : variable value
Set the increment of dynamic_id variable
Signal handling:
SIPp can be controlled using posix signals. The following signals
are handled:
USR1: Similar to press 'q' keyboard key. It triggers a soft exit
of SIPp. No more new calls are placed and all ongoing calls
are finished before SIPp exits.
Example: kill -SIGUSR1 732
USR2: Triggers a dump of all statistics screens in
<scenario_name>_<pid>_screens.log file. Especially useful
in background mode to know what the current status is.
Example: kill -SIGUSR2 732
Exit code:
Upon exit (on fatal error or when the number of asked calls (-m
option) is reached, sipp exits with one of the following exit
code:
0: All calls were successful
1: At least one call failed
97: exit on internal command. Calls may have been processed
99: Normal exit without calls processed
-1: Fatal error
Example:
Run sipp with embedded server (uas) scenario:
./sipp -sn uas
On the same host, run sipp with embedded client (uac) scenario
./sipp -sn uac 127.0.0.1

57
sippxml/testsuiteuac.sh Normal file
View File

@ -0,0 +1,57 @@
#!/bin/bash
# sleep 5;
SERVERPORT=5062
function test_ip2ipcall {
# start sipp server to receive calls from sflphone
sipp -sf ip2ipcalluas.xml -p ${SERVERPORT} &
# start sflphoned
/usr/lib/sflphone/sflphoned&
# wait some time to make sure sflphoned is started
sleep 2;
# run python client and script to make calls
python ../tools/pysflphone/pysflphone_testdbus.py
# kill every one
killall sipp
killall sflphoned
}
function test_accountcall {
# start sflphoned
# /usr/lib/sflphone/sflphoned&
# wait some time to make sure sflphoned is started
#sleep 2;
# python ../tools/pysflphone/pysflphone_testdbus.py &
#sleep 2;
# start sipp client and send calls
sipp -sf accountcalluac.xml 192.168.50.79 -i 192.168.50.182 -p ${SERVERPORT} -l 1
# kill every one
killall sipp
killall sflphoned
}
# function called if CTRL-C detected
bashtrap()
{
killall sipp
killall sflphoned
}
# Here Start the Test suite
# test_ip2ipcall
test_accountcall

View File

@ -1,11 +1,17 @@
#!/usr/bin/env python
import time
import sys
import getopt
from threading import Event
from sflphonectrlsimple import SflPhoneCtrlSimple
class SflPhoneTests(SflPhoneCtrlSimple):
def test_get_allaccounts_methods(self):
for account in self.getAllAccounts():
@ -23,7 +29,7 @@ class SflPhoneTests(SflPhoneCtrlSimple):
def test_make_iptoip_call(self):
"""Make a call to a server (sipp) on port 5062"""
i = 0
while(i < 50):
while(i < 10):
callid = self.Call("sip:test@127.0.0.1:5062")
time.sleep(0.4)
@ -52,7 +58,7 @@ class SflPhoneTests(SflPhoneCtrlSimple):
def test_create_account(self):
"""Create a new sip fake account and remove it"""
"""Create a new sip account"""
CONFIG_ACCOUNT_TYPE = "Account.type"
CONFIG_ACCOUNT_ALIAS = "Account.alias"
@ -60,24 +66,45 @@ class SflPhoneTests(SflPhoneCtrlSimple):
USERNAME = "username"
PASSWORD = "password"
accDetails = {CONFIG_ACCOUNT_TYPE:"SIP", CONFIG_ACCOUNT_ALIAS:"myNewAccount",
HOSTNAME:"192.168.50.3", USERNAME:"431",
PASSWORD:"alexandre"}
accDetails = {CONFIG_ACCOUNT_TYPE:"SIP", CONFIG_ACCOUNT_ALIAS:"testsuiteaccount",
HOSTNAME:"192.168.50.79", USERNAME:"31416",
PASSWORD:"1234"}
accountID = self.addAccount(accDetails)
print "New Account ID " + accountID
time.sleep(3)
return accountID
def test_remove_account(self, accountID):
"""Remove test account"""
self.removeAccount(accountID)
print "Account with ID " + accountID + " removed"
# Open sflphone and connect to sflphoned through dbus
sflphone = SflPhoneTests()
sflphone.test_get_allaccounts_methods()
sflphone.start()
sflphone.test_make_iptoip_call()
# Test 1: Makke approximately one IP2IP call per second
# to a sipp uas on local addrress
#sflphone.test_make_iptoip_call()
sflphone.test_make_account_call()
sflphone.test_create_account()
# Test 2: - Create an account on Asterisk
# - Wait for incoming calls
# - Once a call is received, answer
# - The call should then be hung up by caller
# accountID = sflphone.test_create_account()
# sflphone.test_make_account_call()
# time.sleep(0.3)
# sflphone.test_remove_account(accountID)

View File

@ -32,6 +32,7 @@ import time
import hashlib
from threading import Thread
from threading import Event
from Errors import *
@ -42,21 +43,23 @@ except ImportError, e:
raise SflPhoneError("No python-dbus module found")
class SflPhoneCtrlSimple(object):
class SflPhoneCtrlSimple(Thread):
"""Simple class for controlling SflPhoned through DBUS"""
# list of active calls (known by the client)
activeCalls = {}
def __init__(self, name=sys.argv[0]):
Thread.__init__(self)
# current active account
self.account = None
# client name
self.name = name
# client registered to sflphoned ?
self.registered = False
self.register()
self.event = Event()
self.currentCallId = ""
def __del__(self):
@ -139,6 +142,9 @@ class SflPhoneCtrlSimple(object):
def onIncomingCall(self, account, callid, to):
print "Incoming call: " + account + ", " + callid + ", " + to
self.activeCalls[callid] = {'Account': account, 'To': to, 'State': '' }
self.currentCallId = callid
self.event.set()
Answer(callid)
# On call state changed event, set the values for new calls,
# or delete the call from the list of active calls
@ -559,3 +565,13 @@ class SflPhoneCtrlSimple(object):
m.update(str(t) + str(r))
callid = m.hexdigest()
return callid
def run(self):
while(True):
print "Waiting Event"
self.event.wait()
sflphone.Accept(sflphone.currentCallId)
self.event.clear()
print "Call Accepted"