From 01048011551578b65162d8c649ab996057f77b31 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Tue, 2 Mar 2010 17:14:28 -0500 Subject: [PATCH 1/7] [#2926] Cleanup --- sflphone-common/src/sip/sdp.cpp | 6 +++--- sflphone-common/src/sip/sipvoiplink.cpp | 24 +++++++++++++----------- 2 files changed, 16 insertions(+), 14 deletions(-) diff --git a/sflphone-common/src/sip/sdp.cpp b/sflphone-common/src/sip/sdp.cpp index 886dc1430..b46d35bb4 100644 --- a/sflphone-common/src/sip/sdp.cpp +++ b/sflphone-common/src/sip/sdp.cpp @@ -240,17 +240,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; } diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index 5c5bed594..c4fb1fb8e 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -1497,20 +1497,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)"); } } @@ -3076,7 +3076,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 +3434,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 +3470,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 +3582,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 +3639,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 +3672,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 +3684,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); From d6928d411f12f7b1f76ac30e33c72ded73329a64 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Tue, 2 Mar 2010 17:52:04 -0500 Subject: [PATCH 2/7] [#2926] Cleanup --- sflphone-common/src/sip/sdp.cpp | 20 +++++++++----------- sflphone-common/src/sip/sipvoiplink.cpp | 11 ++++++----- 2 files changed, 15 insertions(+), 16 deletions(-) diff --git a/sflphone-common/src/sip/sdp.cpp b/sflphone-common/src/sip/sdp.cpp index b46d35bb4..4d6505740 100644 --- a/sflphone-common/src/sip/sdp.cpp +++ b/sflphone-common/src/sip/sdp.cpp @@ -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); @@ -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& crypto) { diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index c4fb1fb8e..fdbbd7f59 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -738,7 +738,7 @@ SIPVoIPLink::newOutgoingCall (const CallID& id, const std::string& toUrl) account = dynamic_cast (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 ()); From 9d97dd073e71163764b683e604e59007daa02cae Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Thu, 4 Mar 2010 13:25:09 -0500 Subject: [PATCH 3/7] [#2977] Dtmf over RTP implemented Missing user configuration in GUI --- .../src/audio/audiortp/AudioRtpFactory.cpp | 16 +++ .../src/audio/audiortp/AudioRtpFactory.h | 94 ++++++------ .../src/audio/audiortp/AudioRtpSession.h | 124 ++++++++++++++-- .../src/audio/audiortp/AudioSrtpSession.cpp | 6 - sflphone-common/src/managerimpl.cpp | 18 +-- sflphone-common/src/sip/sipaccount.cpp | 3 +- sflphone-common/src/sip/sipaccount.h | 36 +++-- sflphone-common/src/sip/sipvoiplink.cpp | 135 +++++++++++------- sflphone-common/src/sip/sipvoiplink.h | 12 +- 9 files changed, 300 insertions(+), 144 deletions(-) diff --git a/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp b/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp index 646aa89b9..cb3480979 100644 --- a/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp +++ b/sflphone-common/src/audio/audiortp/AudioRtpFactory.cpp @@ -229,6 +229,22 @@ void AudioRtpFactory::setRemoteCryptoInfo(sfl::SdesNegotiator& nego) } } +void AudioRtpFactory::sendDtmfDigit(int digit) { + switch(_rtpSessionType) { + + case Sdes: + static_cast (_rtpSession)->putDtmfEvent(digit); + break; + + case Symmetric: + static_cast (_rtpSession)->putDtmfEvent(digit); + break; + + case Zrtp: + static_cast (_rtpSession)->putDtmfEvent(digit); + break; + } +} } diff --git a/sflphone-common/src/audio/audiortp/AudioRtpFactory.h b/sflphone-common/src/audio/audiortp/AudioRtpFactory.h index 0076c968c..a1c93d2cd 100644 --- a/sflphone-common/src/audio/audiortp/AudioRtpFactory.h +++ b/sflphone-common/src/audio/audiortp/AudioRtpFactory.h @@ -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__ diff --git a/sflphone-common/src/audio/audiortp/AudioRtpSession.h b/sflphone-common/src/audio/audiortp/AudioRtpSession.h index b6d490844..cb0578bea 100644 --- a/sflphone-common/src/audio/audiortp/AudioRtpSession.h +++ b/sflphone-common/src/audio/audiortp/AudioRtpSession.h @@ -25,6 +25,7 @@ #include #include +#include #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 EventQueue; + template 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::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(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 + void AudioRtpSession::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 + void AudioRtpSession::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(this)->setPayloadFormat (ost::DynamicPayloadFormat ( (ost::PayloadType) 101, 8000)); + + // Set marker in case this is a new Event + if(dtmf->newevent) + static_cast(this)->setMark (true); + + static_cast(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(this)->setMark (false); + } + + // get back the payload to audio + static_cast(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 int AudioRtpSession::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 @@ -580,7 +672,12 @@ namespace sfl { // Send session sessionWaiting = static_cast(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()); diff --git a/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp b/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp index 26b429039..0595cf436 100644 --- a/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp +++ b/sflphone-common/src/audio/audiortp/AudioSrtpSession.cpp @@ -33,12 +33,6 @@ #include #include -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 { diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index f4e3f899e..bf60e374f 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -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; } diff --git a/sflphone-common/src/sip/sipaccount.cpp b/sflphone-common/src/sip/sipaccount.cpp index 4541d675c..9d91ffaf6 100644 --- a/sflphone-common/src/sip/sipaccount.cpp +++ b/sflphone-common/src/sip/sipaccount.cpp @@ -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 ("") { diff --git a/sflphone-common/src/sip/sipaccount.h b/sflphone-common/src/sip/sipaccount.h index dd9782f2d..c6cdb021a 100644 --- a/sflphone-common/src/sip/sipaccount.h +++ b/sflphone-common/src/sip/sipaccount.h @@ -31,6 +31,8 @@ #include "pjsip/sip_transport_tls.h" #include "pjsip/sip_types.h" +enum DtmfType { OVERRTP, SIPINFO}; + class SIPVoIPLink; /** @@ -95,7 +97,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 +299,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 +359,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 +397,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; diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index fdbbd7f59..b22e053ac 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -1235,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(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) { @@ -2783,6 +2819,7 @@ void SIPVoIPLink::shutdownSipTransport(const AccountID& accountID) } + bool SIPVoIPLink::loadSIPLocalIP (std::string *addr) { diff --git a/sflphone-common/src/sip/sipvoiplink.h b/sflphone-common/src/sip/sipvoiplink.h index 67108a7b9..445a28b6f 100644 --- a/sflphone-common/src/sip/sipvoiplink.h +++ b/sflphone-common/src/sip/sipvoiplink.h @@ -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 */ From 315cbc2debfe9ab82fd29d0b508b0c48c2327373 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Thu, 4 Mar 2010 15:59:47 -0500 Subject: [PATCH 4/7] [#2977] Added DTMF type configuration on a per account basis in GUI --- .../src/config/accountconfigdialog.c | 75 +++++++++++++++++++ sflphone-client-gnome/src/config/audioconf.c | 3 +- sflphone-client-gnome/src/sflphone_const.h | 5 ++ sflphone-common/src/account.h | 2 + sflphone-common/src/managerimpl.cpp | 8 ++ sflphone-common/src/sip/sipaccount.cpp | 5 ++ sflphone-common/src/sip/sipaccount.h | 3 + 7 files changed, 100 insertions(+), 1 deletion(-) diff --git a/sflphone-client-gnome/src/config/accountconfigdialog.c b/sflphone-client-gnome/src/config/accountconfigdialog.c index 4f7e34ee3..63f9d9d14 100644 --- a/sflphone-client-gnome/src/config/accountconfigdialog.c +++ b/sflphone-client-gnome/src/config/accountconfigdialog.c @@ -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) { diff --git a/sflphone-client-gnome/src/config/audioconf.c b/sflphone-client-gnome/src/config/audioconf.c index ce269415c..322801a90 100644 --- a/sflphone-client-gnome/src/config/audioconf.c +++ b/sflphone-client-gnome/src/config/audioconf.c @@ -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; } +*/ diff --git a/sflphone-client-gnome/src/sflphone_const.h b/sflphone-client-gnome/src/sflphone_const.h index 7153a5f54..919bf1d30 100644 --- a/sflphone-client-gnome/src/sflphone_const.h +++ b/sflphone-client-gnome/src/sflphone_const.h @@ -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 diff --git a/sflphone-common/src/account.h b/sflphone-common/src/account.h index 998330d0c..3272010a2 100644 --- a/sflphone-common/src/account.h +++ b/sflphone-common/src/account.h @@ -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: diff --git a/sflphone-common/src/managerimpl.cpp b/sflphone-common/src/managerimpl.cpp index bf60e374f..2e0934d17 100644 --- a/sflphone-common/src/managerimpl.cpp +++ b/sflphone-common/src/managerimpl.cpp @@ -3277,6 +3277,8 @@ std::map ManagerImpl::getAccountDetails ( accountID, STUN_ENABLE))); a.insert(std::pair(STUN_SERVER, getConfigString( accountID, STUN_SERVER))); + a.insert(std::pair(ACCOUNT_DTMF_TYPE, getConfigString( + accountID, ACCOUNT_DTMF_TYPE))); RegistrationState state; std::string registrationStateCode; @@ -3561,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; @@ -3620,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; } @@ -3749,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) diff --git a/sflphone-common/src/sip/sipaccount.cpp b/sflphone-common/src/sip/sipaccount.cpp index 9d91ffaf6..e50ac1905 100644 --- a/sflphone-common/src/sip/sipaccount.cpp +++ b/sflphone-common/src/sip/sipaccount.cpp @@ -363,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); diff --git a/sflphone-common/src/sip/sipaccount.h b/sflphone-common/src/sip/sipaccount.h index c6cdb021a..57fd602c6 100644 --- a/sflphone-common/src/sip/sipaccount.h +++ b/sflphone-common/src/sip/sipaccount.h @@ -33,6 +33,9 @@ enum DtmfType { OVERRTP, SIPINFO}; +#define OVERRTPSTR "overrtp" +#define SIPINFOSTR "sipinfo" + class SIPVoIPLink; /** From 3a0339072f7578aef417683a9df00a40d7109d63 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Thu, 4 Mar 2010 17:41:57 -0500 Subject: [PATCH 5/7] [#2536] Very basic functional test script Start sipp server on 5062 Start sflphoned on 5060 Use pysfphone client to make 10 calls --- sippxml/simpleuac.xml | 85 +++++ sippxml/simpleuas.xml | 80 +++++ sippxml/sippusage.txt | 460 ++++++++++++++++++++++++ sippxml/testsuiteuac.sh | 27 ++ tools/pysflphone/pysflphone_testdbus.py | 12 +- 5 files changed, 660 insertions(+), 4 deletions(-) create mode 100644 sippxml/simpleuac.xml create mode 100644 sippxml/simpleuas.xml create mode 100644 sippxml/sippusage.txt create mode 100644 sippxml/testsuiteuac.sh diff --git a/sippxml/simpleuac.xml b/sippxml/simpleuac.xml new file mode 100644 index 000000000..902385639 --- /dev/null +++ b/sippxml/simpleuac.xml @@ -0,0 +1,85 @@ + + + + + + + ;tag=[call_number] + To: sut + 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 + + ]]> + + + + + + + + + + + + + ;tag=[call_number] + To: sut [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 + + ]]> + + + + + + ;tag=[call_number] + To: sut [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 + + ]]> + + + + + + + + + + diff --git a/sippxml/simpleuas.xml b/sippxml/simpleuas.xml new file mode 100644 index 000000000..b7ef0303b --- /dev/null +++ b/sippxml/simpleuas.xml @@ -0,0 +1,80 @@ + + + + + + + + + + + + Content-Length: 0 + + ]]> + + + + + 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 + + ]]> + + + + + + + + + + + Content-Length: 0 + + ]]> + + + + + + + + + + diff --git a/sippxml/sippusage.txt b/sippxml/sippusage.txt new file mode 100644 index 000000000..5c1925285 --- /dev/null +++ b/sippxml/sippusage.txt @@ -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 __messages.log + + -trace_shortmsg : Displays sent and received SIP messages as CSV in + __shortmessages.log + + -trace_screen : Dump statistic screens in the + __ 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 __errors.log. + + -trace_calldebug : Dumps debugging information about aborted calls to + __calldebug.log file. + + -trace_stat : Dumps all statistics in _.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 __rtt.csv. + + -trace_logs : Allow tracing of actions in __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 + __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 diff --git a/sippxml/testsuiteuac.sh b/sippxml/testsuiteuac.sh new file mode 100644 index 000000000..9188b130c --- /dev/null +++ b/sippxml/testsuiteuac.sh @@ -0,0 +1,27 @@ +#!/bin/bash +# sleep 5; + +SERVERPORT=5062 + +#start sipp server to receive calls from sflphone +sipp -sf simpleuas.xml -p ${SERVERPORT} & + +#start sflphoned +/usr/lib/sflphone/sflphoned& + +#wait some time to make sure sflphone is started +sleep 2; + +#run python client and associated script +python ../tools/pysflphone/pysflphone_testdbus.py + +#kill every one +killall sipp +killall sflphoned + +# function called if CTRL-C detected +bashtrap() +{ + killall sipp + killall sflphoned +} \ No newline at end of file diff --git a/tools/pysflphone/pysflphone_testdbus.py b/tools/pysflphone/pysflphone_testdbus.py index 7ff1383f8..bf2598881 100644 --- a/tools/pysflphone/pysflphone_testdbus.py +++ b/tools/pysflphone/pysflphone_testdbus.py @@ -1,5 +1,8 @@ #!/usr/bin/env python import time +import sys + +import getopt from sflphonectrlsimple import SflPhoneCtrlSimple @@ -23,7 +26,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) @@ -72,12 +75,13 @@ class SflPhoneTests(SflPhoneCtrlSimple): self.removeAccount(accountID) print "Account with ID " + accountID + " removed" + sflphone = SflPhoneTests() -sflphone.test_get_allaccounts_methods() +# sflphone.test_get_allaccounts_methods() sflphone.test_make_iptoip_call() -sflphone.test_make_account_call() +# sflphone.test_make_account_call() -sflphone.test_create_account() +# sflphone.test_create_account() From d0fe2fe3531c7c59bf06658b1ae125fa40269e18 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Fri, 5 Mar 2010 13:05:00 -0500 Subject: [PATCH 6/7] [#2536] Add sipp account registration xml scripts and register account --- sflphone-common/src/sip/sipvoiplink.cpp | 5 +- sippxml/accountcalluac.xml | 161 ++++++++++++++++++++ sippxml/accountcalluas.xml | 159 +++++++++++++++++++ sippxml/{simpleuac.xml => ip2ipcalluac.xml} | 0 sippxml/{simpleuas.xml => ip2ipcalluas.xml} | 0 sippxml/testsuiteuac.sh | 38 +++-- tools/pysflphone/pysflphone_testdbus.py | 28 ++-- 7 files changed, 369 insertions(+), 22 deletions(-) create mode 100644 sippxml/accountcalluac.xml create mode 100644 sippxml/accountcalluas.xml rename sippxml/{simpleuac.xml => ip2ipcalluac.xml} (100%) rename sippxml/{simpleuas.xml => ip2ipcalluas.xml} (100%) diff --git a/sflphone-common/src/sip/sipvoiplink.cpp b/sflphone-common/src/sip/sipvoiplink.cpp index b22e053ac..a7058bbb7 100644 --- a/sflphone-common/src/sip/sipvoiplink.cpp +++ b/sflphone-common/src/sip/sipvoiplink.cpp @@ -2404,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)); diff --git a/sippxml/accountcalluac.xml b/sippxml/accountcalluac.xml new file mode 100644 index 000000000..2d43c0384 --- /dev/null +++ b/sippxml/accountcalluac.xml @@ -0,0 +1,161 @@ + + + + + + + + + + + + + + + + + + + + + + + ;tag=[call_number] + To: + Call-ID: [call_id] + CSeq: 1 REGISTER + Contact: + Content-Length: 0 + Expires: 300 + + ]]> + + + + + + + ;tag=[call_number] + To: + Call-ID: [call_id] + CSeq: 1 REGISTER + Contact: + Content-Length: 0 + Expires: 300 + [authentication username=27182 password=1234] + + ]]> + + + + + + + + ;tag=[call_number] + To: + Call-ID: [call_id] + CSeq: 1 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 + + ]]> + + + + + + + + + + + + + + + + + + + + + + ;tag=[call_number] + To: + Call-ID: [call_id] + CSeq: 1 ACK + Contact: sip:27182@[local_ip]:[local_port] + Max-Forwards: 70 + Subject: Functional Test + Content-Length: 0 + + ]]> + + + + + diff --git a/sippxml/accountcalluas.xml b/sippxml/accountcalluas.xml new file mode 100644 index 000000000..82158ef0a --- /dev/null +++ b/sippxml/accountcalluas.xml @@ -0,0 +1,159 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + Content-Length: 0 + Expires: 300 + + ]]> + + + + + + + + + + + + + Content-Length: 0 + + ]]> + + + + + + Content-Length: 0 + + ]]> + + + diff --git a/sippxml/simpleuac.xml b/sippxml/ip2ipcalluac.xml similarity index 100% rename from sippxml/simpleuac.xml rename to sippxml/ip2ipcalluac.xml diff --git a/sippxml/simpleuas.xml b/sippxml/ip2ipcalluas.xml similarity index 100% rename from sippxml/simpleuas.xml rename to sippxml/ip2ipcalluas.xml diff --git a/sippxml/testsuiteuac.sh b/sippxml/testsuiteuac.sh index 9188b130c..9864f1303 100644 --- a/sippxml/testsuiteuac.sh +++ b/sippxml/testsuiteuac.sh @@ -3,25 +3,39 @@ SERVERPORT=5062 -#start sipp server to receive calls from sflphone -sipp -sf simpleuas.xml -p ${SERVERPORT} & +function test_ip2ipcall { -#start sflphoned -/usr/lib/sflphone/sflphoned& + #start sipp server to receive calls from sflphone + sipp -sf ip2ipcalluas.xml -p ${SERVERPORT} & -#wait some time to make sure sflphone is started -sleep 2; + #start sflphoned + /usr/lib/sflphone/sflphoned& -#run python client and associated script -python ../tools/pysflphone/pysflphone_testdbus.py + #wait some time to make sure sflphone is started + sleep 2; -#kill every one -killall sipp -killall sflphoned + #run python client and associated script + python ../tools/pysflphone/pysflphone_testdbus.py + + #kill every one + killall sipp + killall sflphoned +} + +function test_accountcall { + + sipp -sf accountcalluac.xml 192.168.50.79 -i 192.168.50.182 -p ${SERVERPORT} + +} # function called if CTRL-C detected bashtrap() { killall sipp killall sflphoned -} \ No newline at end of file +} + + +# Here Start the Test suite + +test_ip2ipcall \ No newline at end of file diff --git a/tools/pysflphone/pysflphone_testdbus.py b/tools/pysflphone/pysflphone_testdbus.py index bf2598881..47183d645 100644 --- a/tools/pysflphone/pysflphone_testdbus.py +++ b/tools/pysflphone/pysflphone_testdbus.py @@ -9,6 +9,7 @@ from sflphonectrlsimple import SflPhoneCtrlSimple class SflPhoneTests(SflPhoneCtrlSimple): + def test_get_allaccounts_methods(self): for account in self.getAllAccounts(): @@ -55,7 +56,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" @@ -63,25 +64,34 @@ 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() +# Test 1: Makke approximately one IP2IP call per second +# to a sipp uas on local addrress +#sflphone.test_make_iptoip_call() -sflphone.test_make_iptoip_call() +# Test 2: +accountID = sflphone.test_create_account() # sflphone.test_make_account_call() - -# sflphone.test_create_account() +time.sleep(0.3) +# sflphone.test_remove_account(accountID) From 64a8b9508f723bfb7abcd46f99cbb089a7536631 Mon Sep 17 00:00:00 2001 From: Alexandre Savard Date: Fri, 5 Mar 2010 17:43:45 -0500 Subject: [PATCH 7/7] [#2536] Added an event loop in sflphone python client --- sippxml/accountcalluac.xml | 139 ++++++++++++++---------- sippxml/testsuiteuac.sh | 30 +++-- tools/pysflphone/pysflphone_testdbus.py | 19 +++- tools/pysflphone/sflphonectrlsimple.py | 20 +++- 4 files changed, 139 insertions(+), 69 deletions(-) diff --git a/sippxml/accountcalluac.xml b/sippxml/accountcalluac.xml index 2d43c0384..a5ba5ac28 100644 --- a/sippxml/accountcalluac.xml +++ b/sippxml/accountcalluac.xml @@ -22,14 +22,14 @@ ;tag=[call_number] - To: - Call-ID: [call_id] + From: ;tag=[call_number] + To: + Call-ID: REG///[call_id] CSeq: 1 REGISTER - Contact: + Contact: Content-Length: 0 Expires: 300 @@ -42,14 +42,14 @@ ;tag=[call_number] - To: - Call-ID: [call_id] - CSeq: 1 REGISTER - Contact: + From: ;tag=[call_number] + To: + Call-ID: REG///[call_id] + CSeq: 2 REGISTER + Contact: Content-Length: 0 Expires: 300 [authentication username=27182 password=1234] @@ -60,16 +60,17 @@ + ;tag=[call_number] - To: + INVITE sip:2000@[remote_ip] SIP/2.0 + Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch] + From: ;tag=[call_number] + To: Call-ID: [call_id] - CSeq: 1 INVITE + CSeq: 3 INVITE Contact: sip:27182@[local_ip]:[local_port] Max-Forwards: 70 Subject: Functional Test @@ -87,57 +88,73 @@ ]]> - + - - + - - - - - - - - - - - - - + ;tag=[call_number] - To: - Call-ID: [call_id] - CSeq: 1 ACK - Contact: sip:27182@[local_ip]:[local_port] + ACK sip:27182@[remote_ip] SIP/2.0 Max-Forwards: 70 + Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch] + From: ;tag=[call_number] + To: + Call-ID: [call_id] + CSeq: 4 ACK Subject: Functional Test Content-Length: 0 ]]> - - - diff --git a/sippxml/testsuiteuac.sh b/sippxml/testsuiteuac.sh index 9864f1303..88e58de30 100644 --- a/sippxml/testsuiteuac.sh +++ b/sippxml/testsuiteuac.sh @@ -5,27 +5,41 @@ SERVERPORT=5062 function test_ip2ipcall { - #start sipp server to receive calls from sflphone + # start sipp server to receive calls from sflphone sipp -sf ip2ipcalluas.xml -p ${SERVERPORT} & - #start sflphoned + # start sflphoned /usr/lib/sflphone/sflphoned& - #wait some time to make sure sflphone is started + # wait some time to make sure sflphoned is started sleep 2; - #run python client and associated script + # run python client and script to make calls python ../tools/pysflphone/pysflphone_testdbus.py - #kill every one + # kill every one killall sipp killall sflphoned } function test_accountcall { - sipp -sf accountcalluac.xml 192.168.50.79 -i 192.168.50.182 -p ${SERVERPORT} + # 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 @@ -38,4 +52,6 @@ bashtrap() # Here Start the Test suite -test_ip2ipcall \ No newline at end of file +# test_ip2ipcall + +test_accountcall \ No newline at end of file diff --git a/tools/pysflphone/pysflphone_testdbus.py b/tools/pysflphone/pysflphone_testdbus.py index 47183d645..f46a23292 100644 --- a/tools/pysflphone/pysflphone_testdbus.py +++ b/tools/pysflphone/pysflphone_testdbus.py @@ -4,6 +4,8 @@ import sys import getopt +from threading import Event + from sflphonectrlsimple import SflPhoneCtrlSimple @@ -82,16 +84,27 @@ class SflPhoneTests(SflPhoneCtrlSimple): print "Account with ID " + accountID + " removed" + # Open sflphone and connect to sflphoned through dbus sflphone = SflPhoneTests() +sflphone.start() + # Test 1: Makke approximately one IP2IP call per second # to a sipp uas on local addrress #sflphone.test_make_iptoip_call() -# Test 2: -accountID = 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) +# time.sleep(0.3) + + + # sflphone.test_remove_account(accountID) diff --git a/tools/pysflphone/sflphonectrlsimple.py b/tools/pysflphone/sflphonectrlsimple.py index 6ed51344a..d73b0ef4e 100755 --- a/tools/pysflphone/sflphonectrlsimple.py +++ b/tools/pysflphone/sflphonectrlsimple.py @@ -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"