mirror of
https://git.jami.net/savoirfairelinux/jami-daemon.git
synced 2025-08-12 22:09:25 +08:00
Merge branch 'master' of git+ssh://repos-sflphone-git@git.sflphone.org/var/repos/sflphone/git/sflphone
This commit is contained in:
@ -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) {
|
||||
|
@ -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;
|
||||
|
||||
}
|
||||
*/
|
||||
|
@ -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
|
||||
|
@ -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:
|
||||
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -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__
|
||||
|
@ -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());
|
||||
|
@ -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
|
||||
{
|
||||
|
@ -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)
|
||||
|
@ -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)
|
||||
{
|
||||
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
@ -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
186
sippxml/accountcalluac.xml
Normal 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
159
sippxml/accountcalluas.xml
Normal 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
85
sippxml/ip2ipcalluac.xml
Normal 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
80
sippxml/ip2ipcalluas.xml
Normal 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
460
sippxml/sippusage.txt
Normal 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
57
sippxml/testsuiteuac.sh
Normal 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
|
@ -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)
|
||||
|
@ -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"
|
||||
|
Reference in New Issue
Block a user