diff --git a/ChangeLog b/ChangeLog index 6a49b5bae99a4a4c8f9ceb4de6e9c8d8e7aee99f..49d5fd6420f8fa64e22d34ff0ebcb6e687da0247 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,7 @@ +Laurielle LEA (27 July 2005) version 0.4 +- Migrate from libeXoSIP 0.9.0 to libeXosip2-1.9.1-pre15 +(http://www.antisip.com/download/) + Laurielle LEA (21 July 2005) version 0.4 - Change README. diff --git a/DEPS b/DEPS index d1f4c99b5cf5983d5c1f8044e2f1893dd034cab7..e924e675273db15a1e6a888060a69e2d03f010b6 100644 --- a/DEPS +++ b/DEPS @@ -1,5 +1,5 @@ PortAudio: http://portaudio.com/archives/pa_snapshot_v19.tar.gz Common C++ 2 1.3.6: http://sourceforge.net/projects/cplusplus/ ccRTP 1.3.0: http://sourceforge.net/projects/cplusplus/ -libosip 2.2.0: http://savannah.gnu.org/projects/osip/ -libeXoSIP 0.9.0: http://savannah.nongnu.org/projects/exosip/ +libosip 2.2.1: http://savannah.gnu.org/projects/osip/ +libeXosip2-1.9.1-pre14: http://www.antisip.com/download/ diff --git a/config.h.in b/config.h.in index 35f2516284c6792300322b539bec03d3de744ae5..af06bd0e0a6d50960f55781f1e29427775e75048 100644 --- a/config.h.in +++ b/config.h.in @@ -15,8 +15,8 @@ /* Define to 1 if you have the <dlfcn.h> header file. */ #undef HAVE_DLFCN_H -/* Define to 1 if you have the <eXosip/eXosip.h> header file. */ -#undef HAVE_EXOSIP_EXOSIP_H +/* Define to 1 if you have the <eXosip2/eXosip.h> header file. */ +#undef HAVE_EXOSIP2_EXOSIP_H /* Define to 1 if you have the <inttypes.h> header file. */ #undef HAVE_INTTYPES_H diff --git a/configure.ac b/configure.ac index 741fd3d5da43cb114984e12eec201dc80ee0022a..a2556030f891c215e1bbd7d08fc648205323f4c8 100644 --- a/configure.ac +++ b/configure.ac @@ -54,7 +54,7 @@ dnl Checks for header files. AC_HEADER_STDC AC_CHECK_HEADERS( \ ostream \ -eXosip/eXosip.h \ +eXosip2/eXosip.h \ portaudio.h \ ) @@ -78,11 +78,11 @@ PKG_CHECK_MODULES(libosip2, libosip2 >= ${LIBOSIP2_MIN_VERSION}) SFLPHONE_CXXFLAGS="$SFLPHONE_CXXFLAGS $libosip2_CFLAGS" SFLPHONE_LIBS="$SFLPHONE_LIBS $libosip2_LIBS" -if test $ac_cv_header_eXosip_eXosip_h = no; then - AC_MSG_ERROR([*** missing eXipsip/eXosip.h. You need a working eXosip installation. See http://savannah.nongnu.org/projects/exosip/]) +if test $ac_cv_header_eXosip2_eXosip_h = no; then + AC_MSG_ERROR([*** missing eXosip2/eXosip.h. You need a working eXosip2 installation. See http://www.antisip.com/download/]) fi -libexosip_LIBS="-leXosip " -SFLPHONE_LIBS="$SFLPHONE_LIBS $libexosip_LIBS" +libexosip2_LIBS="-leXosip2 " +SFLPHONE_LIBS="$SFLPHONE_LIBS $libexosip2_LIBS" AC_SUBST(LIBQT) diff --git a/src/audio/audiortp.cpp b/src/audio/audiortp.cpp index b593b9bf13bd009a6656d9ea32920a156bb34425..5c43810e56db0742905eedb6926df8289f893fa9 100644 --- a/src/audio/audiortp.cpp +++ b/src/audio/audiortp.cpp @@ -189,6 +189,7 @@ AudioRtpRTX::initAudioRtpSession (void) setCancel(cancelImmediate); } } + _debug("-----------------------\n"); } void diff --git a/src/gui/qt/qtGUImainwindow.cpp b/src/gui/qt/qtGUImainwindow.cpp index 1b380ef9f764b7f40958d02770a902317c2ac705..8eb23f2ae41ca0a67ef34fd24ba448bc224a33b5 100644 --- a/src/gui/qt/qtGUImainwindow.cpp +++ b/src/gui/qt/qtGUImainwindow.cpp @@ -707,6 +707,7 @@ QtGUIMainWindow::callIsOnHold(int id, int line, int busyLine) int QtGUIMainWindow::callIsIncoming (int id, int line, int busyLine) { + _TabIncomingCalls[line] = -1; changeLineStatePixmap(line, BUSY); putOnHoldBusyLine(busyLine); if (qt_answerCall(id) != 1) { @@ -1218,6 +1219,7 @@ QtGUIMainWindow::hangupLine (void) Manager::instance().displayErrorText("Hangup call failed !\n"); } } else if ((i = isThereIncomingCall()) > 0){ + _debug("&&&&&&&&&& i = %d\n", i); // To refuse new incoming call _debug("Refuse call %d\n", id); if (qt_refuseCall(i)) { diff --git a/src/gui/qt/qtGUImainwindow.h b/src/gui/qt/qtGUImainwindow.h index a47f746526600417919f632d7527a34661fb1190..e9e58964e65c63bfb01eef2e71289c40615b2bfa 100644 --- a/src/gui/qt/qtGUImainwindow.h +++ b/src/gui/qt/qtGUImainwindow.h @@ -286,7 +286,7 @@ private: inline void setPrevLine(int line) { _prevLine = line; } inline int getPrevLine(void) { return _prevLine; } - // Array of incoming calls + // Array of incoming calls, contains call-id int _TabIncomingCalls[NUMBER_OF_LINES]; // The current phoneline diff --git a/src/sipcall.cpp b/src/sipcall.cpp index 334c86b8b94d050daf765ceed0cace610727566a..90eb0b6b0765aeef8e1f4990c582301052a23d07 100644 --- a/src/sipcall.cpp +++ b/src/sipcall.cpp @@ -24,6 +24,12 @@ #include <iostream> +// For AF_INET +#include <sys/socket.h> +#include <sys/types.h> +#include <netinet/in.h> +// + #include "global.h" #include "audio/audiocodec.h" #include "audio/codecDescriptor.h" @@ -95,6 +101,18 @@ SipCall::getCid (void) return _cid; } +void +SipCall::setTid (int tid) +{ + _tid = tid; +} + +int +SipCall::getTid (void) +{ + return _tid; +} + int SipCall::getRemoteSdpAudioPort (void) { @@ -124,187 +142,634 @@ int SipCall::newIncomingCall (eXosip_event_t *event) { SipCall *ca = this; + sdp_message_t *remote_sdp = NULL; + _cid = event->cid; _did = event->did; + _tid = event->tid; if (_did < 1 && _cid < 1) { + exit(0); return -1; /* not enough information for this event?? */ } osip_strncpy (_textinfo, event->textinfo, 255); - osip_strncpy (_req_uri, event->req_uri, 255); - osip_strncpy (_local_uri, event->local_uri, 255); - osip_strncpy (_local_uri, event->remote_uri, 255); - osip_strncpy (_subject, event->subject, 255); - - osip_strncpy (ca->_remote_sdp_audio_ip, event->remote_sdp_audio_ip, 49); - ca->_remote_sdp_audio_port = event->remote_sdp_audio_port; - - ca->payload = event->payload; - _debug("For incoming ca->_payload = %d\n", ca->payload); - osip_strncpy (ca->_payload_name, event->payload_name, 49); - setAudioCodec(_cdv->at(0)->alloc(ca->payload, ca->_payload_name)); - - osip_strncpy (ca->_sdp_body, event->sdp_body, 1000); - osip_strncpy (ca->_sdp_body, event->sdp_body, 1000); - _debug("\n%s\n", ca->_sdp_body); - - if (event->reason_phrase[0] != '\0') { - osip_strncpy(this->_reason_phrase, event->reason_phrase, 49); - this->_status_code = event->status_code; + + if (event->response != NULL) { + _status_code = event->response->status_code; + snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); } - + + if (event->request != NULL) { + char *tmp = NULL; + + osip_from_to_str (event->request->from, &tmp); + if (tmp != NULL) { + snprintf (_remote_uri, 255, "%s", tmp); + osip_free (tmp); + } + } + + /* negotiate payloads */ + if (event->request != NULL) { + remote_sdp = eXosip_get_sdp_info (event->request); + } + + if (remote_sdp == NULL) { + _debug("missing SDP in INVITE request\n"); + } + + if (remote_sdp != NULL) { /* TODO: else build an offer */ + sdp_connection_t *conn; + sdp_media_t *remote_med; + char *tmp = NULL; + + if (remote_sdp == NULL) { + _debug("No remote SDP body found for call\n"); + // Send 400 BAD REQUEST + eXosip_call_send_answer (_tid, 400, NULL); + sdp_message_free (remote_sdp); + return 0; + } + + conn = eXosip_get_audio_connection (remote_sdp); + if (conn != NULL && conn->c_addr != NULL) { + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + } + remote_med = eXosip_get_audio_media (remote_sdp); + + if (remote_med == NULL || remote_med->m_port == NULL) { + /* no audio media proposed */ + // Send 415 Unsupported media type + eXosip_call_send_answer (_tid, 415, NULL); + sdp_message_free (remote_sdp); + return 0; + } + + _remote_sdp_audio_port = atoi (remote_med->m_port); + + if (_remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0') { + int pos; + pos = 0; + while (!osip_list_eol (remote_med->m_payloads, pos)) { + tmp = (char *) osip_list_get (remote_med->m_payloads, pos); + if (tmp != NULL && + (0 == osip_strcasecmp (tmp, "0") + || 0 == osip_strcasecmp (tmp, "8"))) { + break; + } + tmp = NULL; + pos++; + } + } + if (tmp != NULL) { + ca->payload = atoi (tmp); + } else { + // Send 415 Unsupported media type + eXosip_call_send_answer (_tid, 415, NULL); + sdp_message_free (remote_sdp); + return 0; + } + + if (tmp != NULL && (ca->payload == 0 || ca->payload == 8) + && _remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0') { + } + } + + if (remote_sdp != NULL) { /* TODO: else build an offer */ + osip_message_t *answer; + int i; + + eXosip_lock (); + i = eXosip_call_build_answer (_tid, 183, &answer); + if (i == 0) { + i = sdp_complete_message (remote_sdp, answer); + if (i != 0) { + osip_message_free (answer); + // Send 415 Unsupported media type + eXosip_call_send_answer (_tid, 415, NULL); + } else { + /* start sending audio */ + if (ca->enable_audio > 0) { + ca->enable_audio = -1; + } + if (ca->enable_audio != 1) /* audio is started */ { + sdp_message_t *local_sdp; + local_sdp = eXosip_get_sdp_info (answer); + if (remote_sdp != NULL && local_sdp != NULL) { + sdp_connection_t *conn; + sdp_media_t *local_med; + sdp_media_t *remote_med; + char *tmp = NULL; + int audio_port = 0; + + conn = eXosip_get_audio_connection (remote_sdp); + if (conn != NULL && conn->c_addr != NULL) { + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + } + remote_med = eXosip_get_audio_media (remote_sdp); + if (remote_med != NULL && remote_med->m_port != NULL) { + _remote_sdp_audio_port = atoi (remote_med->m_port); + } + local_med = eXosip_get_audio_media (local_sdp); + if (local_med != NULL && local_med->m_port != NULL) { + audio_port = atoi (local_med->m_port); + } + + if (_remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0' + && local_med != NULL) { + tmp = (char *) osip_list_get (local_med->m_payloads, 0); + } + if (tmp != NULL) { + ca->payload = atoi (tmp); + _debug("For incoming _payload = %d\n", ca->payload); + setAudioCodec(_cdv->at(0)->alloc(ca->payload, "")); + } + if (tmp != NULL + && audio_port > 0 + && _remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0') { + + /* search if stream is sendonly or recvonly */ + _remote_sendrecv = + sdp_analyse_attribute (remote_sdp, remote_med); + _local_sendrecv = + sdp_analyse_attribute (local_sdp, local_med); + if (_local_sendrecv == _SENDRECV) { + if (_remote_sendrecv == _SENDONLY) + _local_sendrecv = _RECVONLY; + else if (_remote_sendrecv == _RECVONLY) + _local_sendrecv = _SENDONLY; + } + } + } + sdp_message_free (local_sdp); + } + + i = eXosip_call_send_answer (_tid, 183, answer); + } + + if (i != 0) { + _debug("cannot send 183 progress?\n"); + } + } + eXosip_unlock (); + } + this->_state = event->type; + sdp_message_free (remote_sdp); return 0; } int SipCall::ringingCall (eXosip_event_t *event) { - SipCall *ca = this; + SipCall* ca = this; this->_cid = event->cid; this->_did = event->did; + this->_tid = event->tid; if (this->_did < 1 && this->_cid < 1) { return -1; } - osip_strncpy(this->_textinfo, event->textinfo, 255); - osip_strncpy(this->_req_uri, event->req_uri, 255); - osip_strncpy(this->_local_uri, event->local_uri, 255); - osip_strncpy(this->_remote_uri, event->remote_uri, 255); - osip_strncpy(this->_subject, event->subject, 255); + osip_strncpy (_textinfo, event->textinfo, 255); - osip_strncpy(ca->_remote_sdp_audio_ip, event->remote_sdp_audio_ip, 49); - ca->_remote_sdp_audio_port = event->remote_sdp_audio_port; - ca->payload = event->payload; - osip_strncpy(ca->_payload_name, event->payload_name, 49); - - if (event->reason_phrase[0]!='\0') { - osip_strncpy(this->_reason_phrase, event->reason_phrase, 49); - this->_status_code = event->status_code; + if (event->response != NULL) { + _status_code = event->response->status_code; + snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); + } + + if (event->request != NULL) { + char *tmp = NULL; + + osip_from_to_str (event->request->from, &tmp); + if (tmp != NULL) { + snprintf (_remote_uri, 255, "%s", tmp); + osip_free (tmp); + } + } + + sdp_message_t *remote_sdp; + sdp_message_t *local_sdp; + + local_sdp = eXosip_get_sdp_info (event->request); + remote_sdp = eXosip_get_sdp_info (event->response); + if (remote_sdp == NULL) { + _debug("No remote SDP body found for call\n"); + /* TODO: remote_sdp = retreive from ack above */ + } + if (local_sdp == NULL) { + _debug("SDP body was probably in the ACK (TODO)\n"); } + if (remote_sdp != NULL && local_sdp != NULL) { + sdp_connection_t *conn; + sdp_media_t *local_med; + sdp_media_t *remote_med; + char *tmp = NULL; + int audio_port = 0; + + conn = eXosip_get_audio_connection (remote_sdp); + if (conn != NULL && conn->c_addr != NULL) { + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + } + remote_med = eXosip_get_audio_media (remote_sdp); + if (remote_med != NULL && remote_med->m_port != NULL) { + _remote_sdp_audio_port = atoi (remote_med->m_port); + } + local_med = eXosip_get_audio_media (local_sdp); + if (local_med != NULL && local_med->m_port != NULL) { + audio_port = atoi (local_med->m_port); + } + if (_remote_sdp_audio_port > 0 && _remote_sdp_audio_ip[0] != '\0' + && remote_med != NULL) { + tmp = (char *) osip_list_get (remote_med->m_payloads, 0); + } + if (tmp != NULL) { + ca->payload = atoi (tmp); + } + if (tmp != NULL + && audio_port > 0 + && _remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0') { + /* search if stream is sendonly or recvonly */ + _remote_sendrecv = + sdp_analyse_attribute (remote_sdp, remote_med); + _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + if (_local_sendrecv == _SENDRECV) { + if (_remote_sendrecv == _SENDONLY) + _local_sendrecv = _RECVONLY; + else if (_remote_sendrecv == _RECVONLY) + _local_sendrecv = _SENDONLY; + } + } + } + sdp_message_free (local_sdp); + sdp_message_free (remote_sdp); + this->_state = event->type;; return 0; } +int +SipCall::receivedAck (eXosip_event_t *event) +{ + SipCall *ca = this; + + _cid = event->cid; + _did = event->did; + + + if (event->ack != NULL) { + sdp_message_t *remote_sdp; + remote_sdp = eXosip_get_sdp_info (event->ack); + if (remote_sdp != NULL) { + _debug("SDP detected in ACK!\n"); + } else { + _debug("no SDP detected in ACK!\n"); + } + } + + if (ca->enable_audio != 1) { /* audio is started */ + sdp_message_t *remote_sdp; + sdp_message_t *local_sdp; + + remote_sdp = eXosip_get_remote_sdp (_did); + local_sdp = eXosip_get_local_sdp (_did); + if (remote_sdp == NULL) { + _debug("No remote SDP body found for call\n"); + } + if (remote_sdp != NULL && local_sdp != NULL) { + sdp_connection_t *conn; + sdp_media_t *local_med; + sdp_media_t *remote_med; + char *tmp = NULL; + int audio_port = 0; + + conn = eXosip_get_audio_connection (remote_sdp); + if (conn != NULL && conn->c_addr != NULL) { + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + } + remote_med = eXosip_get_audio_media (remote_sdp); + if (remote_med != NULL && remote_med->m_port != NULL) { + _remote_sdp_audio_port = atoi (remote_med->m_port); + } + local_med = eXosip_get_audio_media (local_sdp); + if (local_med != NULL && local_med->m_port != NULL) { + audio_port = atoi (local_med->m_port); + } + + if (_remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0' && local_med != NULL) { + tmp = (char *) osip_list_get (local_med->m_payloads, 0); + } + if (tmp != NULL) { + ca->payload = atoi (tmp); + } + if (tmp != NULL + && audio_port > 0 + && _remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0') { + + /* search if stream is sendonly or recvonly */ + _remote_sendrecv = + sdp_analyse_attribute (remote_sdp, remote_med); + _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + if (_local_sendrecv == _SENDRECV) { + if (_remote_sendrecv == _SENDONLY) + _local_sendrecv = _RECVONLY; + else if (_remote_sendrecv == _RECVONLY) + _local_sendrecv = _SENDONLY; + } + } + } + sdp_message_free (local_sdp); + sdp_message_free (remote_sdp); + } + + _state = event->type; + return 0; +} int SipCall::answeredCall(eXosip_event_t *event) { - SipCall *ca = this; - _cid = event->cid; _did = event->did; if (_did < 1 && _cid < 1) { - return -1; /* not enough information for this event?? */ + exit(0); + return -1; /* not enough information for this event?? */ } - osip_strncpy(this->_textinfo, event->textinfo, 255); - osip_strncpy(this->_req_uri, event->req_uri, 255); - osip_strncpy(this->_local_uri, event->local_uri, 255); - osip_strncpy(this->_remote_uri, event->remote_uri, 255); - osip_strncpy(this->_subject, event->subject, 255); - - osip_strncpy(ca->_remote_sdp_audio_ip, event->remote_sdp_audio_ip, 49); - ca->_remote_sdp_audio_port = event->remote_sdp_audio_port; - osip_strncpy(ca->_payload_name, event->payload_name, 49); - osip_strncpy (ca->_sdp_body, event->sdp_body, 1000); - _debug("\n%s\n", ca->_sdp_body); - - // For outgoing calls, find the first payload of the remote user - int i, size; - char temp[64]; - bzero(temp, 64); - size = _cdv->size(); - // Codec array in common with the 2 parts - int m_audio[size]; - for (int a = 0; a < size; a++) - m_audio[a] = -1; - - sdp_message_t *sdp; - i = sdp_message_init(&sdp); - if (i != 0) _debug("Cannot allocate a SDP packet\n"); - i = sdp_message_parse(sdp, ca->_sdp_body); - if (i != 0) _debug("Cannot parse the SDP body\n"); - int pos = 0; - if (sdp == NULL) _debug("SDP = NULL\n"); -/*********/ - while (!sdp_message_endof_media (sdp, pos)) { - int k = 0; - char *tmp = sdp_message_m_media_get (sdp, pos); - - if (0 == osip_strncasecmp (tmp, "audio", 5)) { - char *payload = NULL; - int c = 0; - do { - payload = sdp_message_m_payload_get (sdp, pos, k); - for (int j = 0; j < size; j++) { - snprintf(temp, 63, "%d", _cdv->at(j)->getPayload()); - if (payload != NULL and strcmp(temp, payload) == 0) { - m_audio[c] = _cdv->at(j)->getPayload(); - c++; - break; - } - } - k++; - } while (payload != NULL); - } - pos++; - } -/***********/ - if (m_audio[0] == -1) { - noSupportedCodec(); - } else { - ca->payload = m_audio[0]; - setAudioCodec(_cdv->at(0)->alloc(ca->payload, "")); - } - _debug("For outgoing call: ca->_payload = %d\n", ca->payload); - - sdp_message_free(sdp); + if (event->response != NULL) { + _status_code = event->response->status_code; + snprintf (_reason_phrase, 49, "%s", event->response->reason_phrase); + } + + if (event->request != NULL) { + char *tmp = NULL; - if (event->reason_phrase[0]!='\0') { - osip_strncpy(this->_reason_phrase, event->reason_phrase, 49); - this->_status_code = event->status_code; + osip_from_to_str (event->request->from, &tmp); + if (tmp != NULL) { + snprintf (_remote_uri, 255, "%s", tmp); + osip_free (tmp); + } } + + eXosip_lock (); + { + osip_message_t *ack = NULL; + int i; + + i = eXosip_call_build_ack (_did, &ack); + if (i != 0) { + _debug("Cannot build ACK for call!\n"); + } else { + sdp_message_t *local_sdp = NULL; + sdp_message_t *remote_sdp = NULL; + + if (event->request != NULL && event->response != NULL) { + local_sdp = eXosip_get_sdp_info (event->request); + remote_sdp = eXosip_get_sdp_info (event->response); + } + if (local_sdp == NULL && remote_sdp != NULL) { + /* sdp in ACK */ + i = sdp_complete_message (remote_sdp, ack); + if (i != 0) { + _debug("Cannot complete ACK with sdp body?!\n"); + } + } + sdp_message_free (local_sdp); + sdp_message_free (remote_sdp); + + eXosip_call_send_ack (_did, ack); + } + } + eXosip_unlock (); + this->_state = event->type; return 0; } -int -SipCall::onholdCall (eXosip_event_t *event) { +void +SipCall::answeredCall_without_hold (eXosip_event_t *event) +{ SipCall *ca = this; - osip_strncpy(ca->_textinfo, event->textinfo, 255); - - osip_strncpy(ca->_remote_sdp_audio_ip, event->remote_sdp_audio_ip, 49); - ca->_remote_sdp_audio_port = event->remote_sdp_audio_port; + if (ca->enable_audio == 1 && event->response != NULL) { + sdp_message_t *sdp = eXosip_get_sdp_info (event->response); + if (sdp != NULL) { + /* audio is started and session has just been modified */ + ca->enable_audio = -1; + sdp_message_free (sdp); + } + } - osip_strncpy(ca->_reason_phrase, event->reason_phrase, 49); - ca->_status_code = event->status_code; - - ca->_state = event->type; - return 0; + if (ca->enable_audio != 1) { /* audio is started */ + sdp_message_t *remote_sdp; + sdp_message_t *local_sdp; + + local_sdp = eXosip_get_sdp_info (event->request); + remote_sdp = eXosip_get_sdp_info (event->response); + if (remote_sdp == NULL) { + _debug("No remote SDP body found for call\n"); + /* TODO: remote_sdp = retreive from ack above */ + } + if (local_sdp == NULL) { + _debug("SDP body was probably in the ACK (TODO)\n"); + } + + if (remote_sdp != NULL && local_sdp != NULL) { + sdp_connection_t *conn; + sdp_media_t *local_med; + sdp_media_t *remote_med; + char *tmp = NULL; + int audio_port = 0; + + conn = eXosip_get_audio_connection (remote_sdp); + if (conn != NULL && conn->c_addr != NULL) { + snprintf (_remote_sdp_audio_ip, 49, "%s", conn->c_addr); + } + remote_med = eXosip_get_audio_media (remote_sdp); + if (remote_med != NULL && remote_med->m_port != NULL) { + _remote_sdp_audio_port = atoi (remote_med->m_port); + } + local_med = eXosip_get_audio_media (local_sdp); + if (local_med != NULL && local_med->m_port != NULL) { + audio_port = atoi (local_med->m_port); + } + + if (_remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0' && remote_med != NULL) { + tmp = (char *) osip_list_get (remote_med->m_payloads, 0); + } + if (tmp != NULL) { + ca->payload = atoi (tmp); + _debug("For outgoing call: ca->_payload = %d\n", ca->payload); + setAudioCodec(_cdv->at(0)->alloc(ca->payload, "")); + } + if (tmp != NULL + && audio_port > 0 + && _remote_sdp_audio_port > 0 + && _remote_sdp_audio_ip[0] != '\0') { + + /* search if stream is sendonly or recvonly */ + _remote_sendrecv = + sdp_analyse_attribute (remote_sdp, remote_med); + _local_sendrecv = sdp_analyse_attribute (local_sdp, local_med); + if (_local_sendrecv == _SENDRECV) { + if (_remote_sendrecv == _SENDONLY) + _local_sendrecv = _RECVONLY; + else if (_remote_sendrecv == _RECVONLY) + _local_sendrecv = _SENDONLY; + } + } + } + sdp_message_free (local_sdp); + sdp_message_free (remote_sdp); + } } int -SipCall::offholdCall (eXosip_event_t *event) { - SipCall *ca = this; +SipCall::sdp_complete_message(sdp_message_t * remote_sdp, + osip_message_t * msg) +{ + sdp_media_t *remote_med; + char *tmp = NULL; + char buf[4096]; + int pos; - osip_strncpy(ca->_textinfo, event->textinfo, 255); + char localip[128]; - osip_strncpy(ca->_remote_sdp_audio_ip, event->remote_sdp_audio_ip, 49); - ca->_remote_sdp_audio_port = event->remote_sdp_audio_port; + // Format port to a char* + char port_tmp[64]; + bzero(port_tmp, 64); + snprintf(port_tmp, 63, "%d", _local_audio_port); + + if (remote_sdp == NULL) { + _debug("No remote SDP body found for call\n"); + return -1; + } + if (msg == NULL) { + _debug("No message to complete\n"); + return -1; + } + + eXosip_guess_localip (AF_INET, localip, 128); + snprintf (buf, 4096, + "v=0\r\n" + "o=user 0 0 IN IP4 %s\r\n" + "s=session\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n", localip, localip); + + pos = 0; + while (!osip_list_eol (remote_sdp->m_medias, pos)) { + char payloads[128]; + int pos2; + + memset (payloads, '\0', sizeof (payloads)); + remote_med = (sdp_media_t *) osip_list_get (remote_sdp->m_medias, pos); + + if (0 == osip_strcasecmp (remote_med->m_media, "audio")) { + pos2 = 0; + while (!osip_list_eol (remote_med->m_payloads, pos2)) { + tmp = (char *) osip_list_get (remote_med->m_payloads, pos2); + if (tmp != NULL && + (0 == osip_strcasecmp (tmp, "0") + || 0 == osip_strcasecmp (tmp, "8") + || 0 == osip_strcasecmp (tmp, "3"))) { + strcat (payloads, tmp); + strcat (payloads, " "); + } + pos2++; + } + strcat (buf, "m="); + strcat (buf, remote_med->m_media); + if (pos2 == 0 || payloads[0] == '\0') { + strcat (buf, " 0 RTP/AVP \r\n"); + return -1; /* refuse anyway */ + } else { + strcat (buf, " "); + strcat (buf, port_tmp); + strcat (buf, " RTP/AVP "); + strcat (buf, payloads); + strcat (buf, "\r\n"); + + if (NULL != strstr (payloads, " 0 ") + || (payloads[0] == '0' && payloads[1] == ' ')) + strcat (buf, "a=rtpmap:0 PCMU/8000\r\n"); + if (NULL != strstr (payloads, " 8 ") + || (payloads[0] == '8' && payloads[1] == ' ')) + strcat (buf, "a=rtpmap:8 PCMA/8000\r\n"); + if (NULL != strstr (payloads, " 3 ") + || (payloads[0] == '8' && payloads[1] == ' ')) + strcat (buf, "a=rtpmap:8 GSM/8000\r\n"); + } + } else { + strcat (buf, "m="); + strcat (buf, remote_med->m_media); + strcat (buf, " 0 "); + strcat (buf, remote_med->m_proto); + strcat (buf, " \r\n"); + } + pos++; + } - osip_strncpy(ca->_reason_phrase, event->reason_phrase, 49); - ca->_status_code = event->status_code; - - ca->_state = event->type; + osip_message_set_body (msg, buf, strlen (buf)); + osip_message_set_content_type (msg, "application/sdp"); return 0; } +int +SipCall::sdp_analyse_attribute (sdp_message_t * sdp, sdp_media_t * med) +{ + int pos; + int pos_media; + + /* test media attributes */ + pos = 0; + while (!osip_list_eol (med->a_attributes, pos)) { + sdp_attribute_t *at; + + at = (sdp_attribute_t *) osip_list_get (med->a_attributes, pos); + if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendonly")) { + return _SENDONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "recvonly")) { + return _RECVONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendrecv")) { + return _SENDRECV; + } + pos++; + } + + /* test global attributes */ + pos_media = -1; + pos = 0; + while (!osip_list_eol (sdp->a_attributes, pos)) { + sdp_attribute_t *at; + + at = (sdp_attribute_t *) osip_list_get (sdp->a_attributes, pos); + if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendonly")) { + return _SENDONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "recvonly")) { + return _RECVONLY; + } else if (at->a_att_field != NULL && + 0 == strcmp (at->a_att_field, "sendrecv")) { + return _SENDRECV; + } + pos++; + } + + return _SENDRECV; +} + void SipCall::alloc(void) { this->_reason_phrase = new char[50]; diff --git a/src/sipcall.h b/src/sipcall.h index 2b37a5d77b895ca5ad59d43b0c4663b16a15b1e6..6a8a38ba077b11747e1741440ff43154b6b9eb19 100644 --- a/src/sipcall.h +++ b/src/sipcall.h @@ -22,13 +22,16 @@ #ifndef __SIP_CALL_H__ #define __SIP_CALL_H__ -#include <eXosip/eXosip.h> +#include <eXosip2/eXosip.h> #include <vector> class CodecDescriptor; class AudioCodec; #define NOT_USED 0 +#define _SENDRECV 0 +#define _SENDONLY 1 +#define _RECVONLY 2 using namespace std; typedef vector<CodecDescriptor*, allocator<CodecDescriptor*> > CodecDescriptorVector; @@ -43,9 +46,9 @@ public: int newIncomingCall (eXosip_event_t *); int answeredCall (eXosip_event_t *); + void answeredCall_without_hold (eXosip_event_t *); int ringingCall (eXosip_event_t *); - int onholdCall (eXosip_event_t *); - int offholdCall (eXosip_event_t *); + int receivedAck (eXosip_event_t *); void setLocalAudioPort (int); int getLocalAudioPort (void); @@ -55,11 +58,15 @@ public: int getDid (void); void setCid (int cid); int getCid (void); + void setTid (int tid); + int getTid (void); int getRemoteSdpAudioPort (void); char* getRemoteSdpAudioIp (void); AudioCodec* getAudioCodec (void); void setAudioCodec (AudioCodec* ac); + inline char* getRemoteUri (void) { return _remote_uri; } + inline void setStandBy (bool standby) { _standby = standby; } inline bool getStandBy (void) { return _standby; } @@ -67,6 +74,9 @@ private: void alloc (void); void dealloc (void); void noSupportedCodec(void); + + int sdp_complete_message(sdp_message_t * remote_sdp, osip_message_t * msg); + int sdp_analyse_attribute (sdp_message_t * sdp, sdp_media_t * med); CodecDescriptorVector* _cdv; AudioCodec* _audiocodec; @@ -74,6 +84,7 @@ private: short _id; int _cid; // call id int _did; // dialog id + int _tid; // transaction id bool _standby; // wait for a cid and did when outgoing call is made int _status_code; @@ -88,9 +99,12 @@ private: char* _remote_sdp_audio_ip; char* _payload_name; char* _sdp_body; + int _payload; int _state; int _local_audio_port; int _remote_sdp_audio_port; + int _local_sendrecv; /* _SENDRECV, _SENDONLY, _RECVONLY */ + int _remote_sendrecv; /* _SENDRECV, _SENDONLY, _RECVONLY */ }; #endif // __SIP_CALL_H__ diff --git a/src/sipvoiplink.cpp b/src/sipvoiplink.cpp index 300affeae41570f29b52e41a471fab828f1283ff..1594eaf1617a0ab7dcf25ef85b4236c7aa2d84dc 100644 --- a/src/sipvoiplink.cpp +++ b/src/sipvoiplink.cpp @@ -18,7 +18,7 @@ */ #include <sys/time.h> -#include <eXosip/eXosip.h> +#include <eXosip2/eXosip.h> #include <osip2/osip.h> #include <osipparser2/osip_const.h> #include <osipparser2/osip_headers.h> @@ -87,16 +87,26 @@ int SipVoIPLink::init (void) { string tmp; + int i; tmp = string(PROGNAME) + "/" + string(VERSION); + i = eXosip_init (); + if (i != 0) { + _debug("Could not initialize eXosip\n"); + exit (0); + } + srand (time(NULL)); - if (eXosip_init (NULL, NULL, DEFAULT_SIP_PORT) != 0) { - if (eXosip_init (NULL, NULL, RANDOM_SIP_PORT) != 0) { - _debug("Cannot init eXosip\n"); + i = eXosip_listen_addr(IPPROTO_UDP, NULL, DEFAULT_SIP_PORT, AF_INET, 0); + if (i != 0) { + i = eXosip_listen_addr(IPPROTO_UDP, NULL, RANDOM_SIP_PORT, AF_INET, 0); + if (i != 0) { + _debug("Could not initialize transport layer\n"); return -1; } } + // If use STUN server, firewall address setup if (Manager::instance().useStun()) { eXosip_set_user_agent(tmp.data()); @@ -104,11 +114,13 @@ SipVoIPLink::init (void) return 0; } - eXosip_set_firewallip((Manager::instance().getFirewallAddress()).data()); + eXosip_masquerade_contact((Manager::instance().getFirewallAddress()).data(), + Manager::instance().getFirewallPort()); + } eXosip_set_user_agent(tmp.data()); - initRtpmapCodec(); +// initRtpmapCodec(); _evThread->start(); return 1; } @@ -126,33 +138,7 @@ SipVoIPLink::isInRtpmap (int index, int payload, CodecDescriptorVector* cdv) { void SipVoIPLink::initRtpmapCodec (void) { - int payload; - unsigned int nb; - char rtpmap[128]; - char tmp[64]; - bzero(rtpmap, 128); - bzero(tmp, 64); - - /* reset all payload to fit application capabilities */ - eXosip_sdp_negotiation_remove_audio_payloads(); - - // Set rtpmap according to the supported codec order - nb = Manager::instance().getNumberOfCodecs(); - for (unsigned int i = 0; i < nb; i++) { - payload = Manager::instance().getCodecDescVector()->at(i)->getPayload(); - - // Add payload to rtpmap if it is not already added - if (!isInRtpmap(i, payload, Manager::instance().getCodecDescVector())) { - snprintf(rtpmap, 127, "%d %s/%d", payload, - Manager::instance().getCodecDescVector()->at(i)->rtpmapPayload(payload).data(), SAMPLING_RATE); - snprintf(tmp, 63, "%d", payload); - - eXosip_sdp_negotiation_add_codec( osip_strdup(tmp), NULL, - osip_strdup("RTP/AVP"), NULL, NULL, NULL, NULL,NULL, - osip_strdup(rtpmap)); - } - } } void @@ -164,7 +150,9 @@ SipVoIPLink::quit(void) int SipVoIPLink::setRegister (void) { + int i; int reg_id = -1; + osip_message_t *reg = NULL; string proxy = "sip:" + get_config_fields_str(SIGNALISATION, PROXY); @@ -189,21 +177,20 @@ SipVoIPLink::setRegister (void) return -1; } - _debug("register From: %s\n", from.data()); + _debug("REGISTER From: %s\n", from.data()); if (!get_config_fields_str(SIGNALISATION, PROXY).empty()) { - reg_id = eXosip_register_init((char*)from.data(), - (char*)proxy.data(),NULL); + reg_id = eXosip_register_build_initial_register ((char*)from.data(), + (char*)proxy.data(), NULL, EXPIRES_VALUE, ®); } else { - reg_id = eXosip_register_init((char*)from.data(), - (char*)hostname.data(), NULL); + reg_id = eXosip_register_build_initial_register ((char*)from.data(), + (char*)hostname.data(), NULL, EXPIRES_VALUE, ®); } if (reg_id < 0) { eXosip_unlock(); return -1; } - - int i = eXosip_register(reg_id, EXPIRES_VALUE); - + + i = eXosip_register_send_register (reg_id, reg); if (i == -2) { _debug("cannot build registration, check the setup\n"); eXosip_unlock(); @@ -216,7 +203,7 @@ SipVoIPLink::setRegister (void) } eXosip_unlock(); - return 0; + return i; } int SipVoIPLink::outgoingInvite (short id, const string& to_url) @@ -271,6 +258,7 @@ int SipVoIPLink::answer (short id) { int i; + int port; char tmpbuf[64]; bzero (tmpbuf, 64); // Get port @@ -278,10 +266,34 @@ SipVoIPLink::answer (short id) _debug("Answer call [id = %d, cid = %d, did = %d]\n", id, getSipCall(id)->getCid(), getSipCall(id)->getDid()); - _debug("Local audio port: %d\n", getSipCall(id)->getLocalAudioPort()); + port = getSipCall(id)->getLocalAudioPort(); + _debug("Local audio port: %d\n", port); + + osip_message_t *answer = NULL; + SipCall* ca = getSipCall(id); + + // Send 180 RINGING + eXosip_lock (); + eXosip_call_send_answer (ca->getTid(), RINGING, NULL); + eXosip_unlock (); + + // Send 200 OK eXosip_lock(); - i = eXosip_answer_call(getSipCall(id)->getDid(), 200, tmpbuf); + i = eXosip_call_build_answer (ca->getTid(), OK, &answer); + if (i != 0) { + // Send 400 BAD_REQUEST + eXosip_call_send_answer (ca->getTid(), BAD_REQ, NULL); + } else { + i = sdp_complete_200ok (ca->getDid(), answer, port); + if (i != 0) { + osip_message_free (answer); + // Send 415 UNSUPPORTED_MEDIA_TYPE + eXosip_call_send_answer (ca->getTid(), UNSUP_MEDIA_TYPE, NULL); + } else { + eXosip_call_send_answer (ca->getTid(), OK, answer); + } + } eXosip_unlock(); // Incoming call is answered, start the sound channel. @@ -301,7 +313,7 @@ SipVoIPLink::hangup (short id) id, getSipCall(id)->getCid(), getSipCall(id)->getDid()); // Release SIP stack. eXosip_lock(); - i = eXosip_terminate_call (getSipCall(id)->getCid(), + i = eXosip_call_terminate (getSipCall(id)->getCid(), getSipCall(id)->getDid()); eXosip_unlock(); @@ -321,7 +333,7 @@ SipVoIPLink::cancel (short id) _debug("Cancel call [id = %d, cid = %d]\n", id, getCid()); // Release SIP stack. eXosip_lock(); - i = eXosip_terminate_call (getCid(), -1); + i = eXosip_call_terminate (getCid(), -1); eXosip_unlock(); } deleteSipCall(id); @@ -331,12 +343,64 @@ SipVoIPLink::cancel (short id) int SipVoIPLink::onhold (short id) { - int i; + osip_message_t *invite; + int i; + int did; + + sdp_message_t *local_sdp = NULL; + + did = getSipCall(id)->getDid(); - eXosip_lock(); - i = eXosip_on_hold_call(getSipCall(id)->getDid()); - eXosip_unlock(); + eXosip_lock (); + local_sdp = eXosip_get_local_sdp (did); + eXosip_unlock (); + + if (local_sdp == NULL) { + return -1; + } + +/* + char port[10]; + snprintf (port, 10, "%d", getSipCall(id)->getLocalAudioPort()); + */ + eXosip_lock (); + // Build INVITE_METHOD for put call on-hold + i = eXosip_call_build_request (did, INVITE_METHOD, &invite); + eXosip_unlock (); + + if (i != 0) { + sdp_message_free(local_sdp); + return -1; + } + + /* add sdp body */ + { + char *tmp = NULL; + + i = sdp_hold_call (local_sdp); + if (i != 0) { + sdp_message_free (local_sdp); + osip_message_free (invite); + return -1; + } + + i = sdp_message_to_str (local_sdp, &tmp); + sdp_message_free (local_sdp); + if (i != 0) { + osip_message_free (invite); + return -1; + } + osip_message_set_body (invite, tmp, strlen (tmp)); + osip_free (tmp); + osip_message_set_content_type (invite, "application/sdp"); + } + + eXosip_lock (); + // Send request + i = eXosip_call_send_request (did, invite); + eXosip_unlock (); + // Disable audio _audiortp->closeRtpSession(getSipCall(id)); return i; @@ -345,12 +409,62 @@ SipVoIPLink::onhold (short id) int SipVoIPLink::offhold (short id) { - int i; - - eXosip_lock(); - i = eXosip_off_hold_call(getSipCall(id)->getDid(), NULL, 0); - eXosip_unlock(); + osip_message_t *invite; + int i; + int did; + + sdp_message_t *local_sdp = NULL; + + did = getSipCall(id)->getDid(); + eXosip_lock (); + local_sdp = eXosip_get_local_sdp (did); + eXosip_unlock (); + if (local_sdp == NULL) { + return -1; + } + + /* + char port[10]; + snprintf (port, 10, "%d", getSipCall(id)->getLocalAudioPort()); + */ + eXosip_lock (); + // Build INVITE_METHOD for put call off-hold + i = eXosip_call_build_request (did, INVITE_METHOD, &invite); + eXosip_unlock (); + + if (i != 0) { + sdp_message_free(local_sdp); + return -1; + } + + /* add sdp body */ + { + char *tmp = NULL; + + i = sdp_off_hold_call (local_sdp); + if (i != 0) { + sdp_message_free (local_sdp); + osip_message_free (invite); + return -1; + } + + i = sdp_message_to_str (local_sdp, &tmp); + sdp_message_free (local_sdp); + if (i != 0) { + osip_message_free (invite); + return -1; + } + osip_message_set_body (invite, tmp, strlen (tmp)); + osip_free (tmp); + osip_message_set_content_type (invite, "application/sdp"); + } + + eXosip_lock (); + // Send request + i = eXosip_call_send_request (did, invite); + eXosip_unlock (); + // Enable audio if (_audiortp->createNewSession (getSipCall(id)) < 0) { _debug("FATAL: Unable to start sound (%s:%d)\n", __FILE__, __LINE__); @@ -362,6 +476,7 @@ SipVoIPLink::offhold (short id) int SipVoIPLink::transfer (short id, const string& to) { + osip_message_t *refer; int i; string tmp_to; tmp_to = toHeader(to); @@ -370,7 +485,13 @@ SipVoIPLink::transfer (short id, const string& to) } eXosip_lock(); - i = eXosip_transfer_call(getSipCall(id)->getDid(), (char*)tmp_to.data()); + // Build transfer request + i = eXosip_call_build_refer (getSipCall(id)->getDid(), (char*)tmp_to.data(), + &refer); + if (i == 0) { + // Send transfer request + i = eXosip_call_send_request (getSipCall(id)->getDid(), refer); + } eXosip_unlock(); return i; } @@ -384,8 +505,12 @@ SipVoIPLink::refuse (short id) // Get local port snprintf (tmpbuf, 63, "%d", getSipCall(id)->getLocalAudioPort()); + osip_message_t *answer = NULL; eXosip_lock(); - i = eXosip_answer_call(getSipCall(id)->getDid(), BUSY_HERE, tmpbuf); + i = eXosip_call_build_answer (getSipCall(id)->getTid(), BUSY_HERE, &answer); + if (i == 0) { + i = eXosip_call_send_answer (getSipCall(id)->getTid(), BUSY_HERE, answer); + } eXosip_unlock(); return i; } @@ -396,16 +521,18 @@ SipVoIPLink::getEvent (void) eXosip_event_t *event; short id; char *name; - static int countReg = 0; - eXosip_automatic_refresh(); event = eXosip_event_wait (0, 50); + eXosip_lock(); + eXosip_automatic_action(); + eXosip_unlock(); + if (event == NULL) { return -1; } switch (event->type) { // IP-Phone user receives a new call - case EXOSIP_CALL_NEW: // + case EXOSIP_CALL_INVITE: // // Set local random port for incoming call if (!Manager::instance().useStun()) { setLocalPort(RANDOM_LOCAL_PORT); @@ -418,6 +545,7 @@ SipVoIPLink::getEvent (void) } } + // Generate id id = Manager::instance().generateNewCallId(); Manager::instance().pushBackNewCall(id, Incoming); _debug("Incoming Call with identifiant %d [cid = %d, did = %d]\n", @@ -427,7 +555,17 @@ SipVoIPLink::getEvent (void) // Display the callerId-name osip_from_t *from; osip_from_init(&from); - osip_from_parse(from, event->remote_uri); + + if (event->request != NULL) { + char *tmp = NULL; + + osip_from_to_str (event->request->from, &tmp); + if (tmp != NULL) { + snprintf (getSipCall(id)->getRemoteUri(), 256, "%s", tmp); + osip_free (tmp); + } + } + osip_from_parse(from, getSipCall(id)->getRemoteUri()); name = osip_from_get_displayname(from); Manager::instance().displayTextMessage(id, name); if (Manager::instance().getCall(id) != NULL) { @@ -438,15 +576,16 @@ SipVoIPLink::getEvent (void) _debug("From: %s\n", name); osip_from_free(from); + // Associate an audio port with a call + getSipCall(id)->setLocalAudioPort(_localPort); + + getSipCall(id)->newIncomingCall(event); if (Manager::instance().incomingCall(id) < 0) { Manager::instance().displayErrorText("Incoming call failed"); return -1; } - // Associate an audio port with a call - getSipCall(id)->setLocalAudioPort(_localPort); - break; // The peer-user answers @@ -463,6 +602,7 @@ SipVoIPLink::getEvent (void) and !Manager::instance().getCall(id)->isOffHold()) { getSipCall(id)->setStandBy(false); if (getSipCall(id)->answeredCall(event) != -1) { + getSipCall(id)->answeredCall_without_hold(event); Manager::instance().peerAnsweredCall(id); // Outgoing call is answered, start the sound channel. @@ -472,9 +612,15 @@ SipVoIPLink::getEvent (void) exit(1); } } + } else { + // Answer to on/off hold to send ACK + if (id > 0) { + getSipCall(id)->answeredCall(event); + _debug("-----------------------\n"); + } } break; - + case EXOSIP_CALL_RINGING: //peer call is ringing id = findCallIdWhenRinging(); @@ -492,6 +638,17 @@ SipVoIPLink::getEvent (void) case EXOSIP_CALL_REDIRECTED: break; + case EXOSIP_CALL_ACK: + id = findCallId(event); + _debug("ACK received [id = %d, cid = %d, did = %d]\n", + id, event->cid, event->did); + if (id > 0) { + getSipCall(id)->receivedAck(event); + } else { + return -1; + } + break; + // The peer-user closed the phone call(we received BYE). case EXOSIP_CALL_CLOSED: id = findCallId(event); @@ -509,35 +666,14 @@ SipVoIPLink::getEvent (void) } break; - case EXOSIP_CALL_HOLD: - id = findCallId(event); - if (id > 0) { - getSipCall(id)->onholdCall(event); - } else { - return -1; - } - break; - - case EXOSIP_CALL_OFFHOLD: - id = findCallId(event); - if (id > 0) { - getSipCall(id)->offholdCall(event); - } else { - return -1; - } - break; - case EXOSIP_CALL_REQUESTFAILURE: id = findCallId(event); // Handle 4XX errors - switch (event->status_code) { + switch (event->response->status_code) { case AUTH_REQUIRED: - if (setAuthentication() == -1) { - break; - } eXosip_lock(); - eXosip_retry_call (event->cid); + eXosip_automatic_action(); eXosip_unlock(); break; case BAD_REQ: @@ -551,7 +687,7 @@ SipVoIPLink::getEvent (void) case ADDR_INCOMPLETE: case BUSY_HERE: // Display error on the screen phone - Manager::instance().displayError(event->reason_phrase); + Manager::instance().displayError(event->response->reason_phrase); Manager::instance().congestion(true); break; case REQ_TERMINATED: @@ -563,7 +699,7 @@ SipVoIPLink::getEvent (void) case EXOSIP_CALL_SERVERFAILURE: // Handle 5XX errors - switch (event->status_code) { + switch (event->response->status_code) { case SERVICE_UNAVAILABLE: Manager::instance().ringback(false); Manager::instance().congestion(true); @@ -575,7 +711,7 @@ SipVoIPLink::getEvent (void) case EXOSIP_CALL_GLOBALFAILURE: // Handle 6XX errors - switch (event->status_code) { + switch (event->response->status_code) { case BUSY_EVERYWHERE: case DECLINE: Manager::instance().ringback(false); @@ -587,64 +723,36 @@ SipVoIPLink::getEvent (void) break; case EXOSIP_REGISTRATION_SUCCESS: - _debug("-- Registration succeeded --\n"); Manager::instance().displayStatus(LOGGED_IN_STATUS); break; case EXOSIP_REGISTRATION_FAILURE: - _debug("-- Registration failed --\n"); - if (countReg <= 3) { - setRegister(); - countReg++; - } - break; - case EXOSIP_OPTIONS_NEW: - /* answer the OPTIONS method */ - /* 1: search for an existing call */ + case EXOSIP_MESSAGE_NEW: unsigned int k; - for (k = 0; k < _sipcallVector->size(); k++) { - if (_sipcallVector->at(k)->getCid() == event->cid) { - break; + if (event->request != NULL && MSG_IS_OPTIONS(event->request)) { + for (k = 0; k < _sipcallVector->size(); k++) { + if (_sipcallVector->at(k)->getCid() == event->cid) { + break; + } } + + // TODO: Que faire si rien trouve?? + eXosip_lock(); + if (_sipcallVector->at(k)->getCid() == event->cid) { + /* already answered! */ + } + else if (k == _sipcallVector->size()) { + /* answer 200 ok */ + eXosip_options_send_answer (event->tid, OK, NULL); + } else { + /* answer 486 ok */ + eXosip_options_send_answer (event->tid, BUSY_HERE, NULL); + } + eXosip_unlock(); } - - // TODO: Que faire si rien trouve?? - eXosip_lock(); - if (_sipcallVector->at(k)->getCid() == event->cid) { - /* already answered! */ - } - else if (k == _sipcallVector->size()) { - /* answer 200 ok */ - eXosip_answer_options (event->cid, event->did, 200); - } else { - /* answer 486 ok */ - eXosip_answer_options (event->cid, event->did, 486); - } - eXosip_unlock(); - break; - - case EXOSIP_OPTIONS_ANSWERED: - break; - - case EXOSIP_OPTIONS_PROCEEDING: - break; - - case EXOSIP_OPTIONS_REDIRECTED: - break; - - case EXOSIP_OPTIONS_REQUESTFAILURE: - break; - - case EXOSIP_OPTIONS_SERVERFAILURE: - break; - - case EXOSIP_OPTIONS_GLOBALFAILURE: - break; - - case EXOSIP_SUBSCRIPTION_NOTIFY: break; default: @@ -671,17 +779,23 @@ SipVoIPLink::setLocalPort (int port) void SipVoIPLink::carryingDTMFdigits (short id, char code) { int duration = get_config_fields_int(SIGNALISATION, PULSE_LENGTH); - - static const int body_len = 128; + osip_message_t *info; + const int body_len = 1000; + int i; char *dtmf_body = new char[body_len]; - snprintf(dtmf_body, body_len - 1, - "Signal=%c\r\nDuration=%d\r\n", - code, duration); eXosip_lock(); - eXosip_info_call(getSipCall(id)->getDid(), "application/dtmf-relay", - dtmf_body); + // Build info request + i = eXosip_call_build_info (getSipCall(id)->getDid(), &info); + if (i == 0) { + snprintf(dtmf_body, body_len - 1, "Signal=%c\r\nDuration=%d\r\n", + code, duration); + osip_message_set_content_type (info, "application/dtmf-relay"); + osip_message_set_body (info, dtmf_body, strlen (dtmf_body)); + // Send info request + i = eXosip_call_send_request (getSipCall(id)->getDid(), info); + } eXosip_unlock(); delete[] dtmf_body; @@ -741,6 +855,178 @@ SipVoIPLink::getAudioCodec (short callid) /////////////////////////////////////////////////////////////////////////////// // Private functions /////////////////////////////////////////////////////////////////////////////// +int +SipVoIPLink::sdp_hold_call (sdp_message_t * sdp) +{ + int pos; + int pos_media = -1; + char *rcvsnd; + int recv_send = -1; + + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { + recv_send = 0; + } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") + || 0 == strcmp (rcvsnd, "sendrecv"))) { + recv_send = 0; + sprintf (rcvsnd, "sendonly"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } + + pos_media = 0; + while (!sdp_message_endof_media (sdp, pos_media)) { + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && 0 == strcmp (rcvsnd, "sendonly")) { + recv_send = 0; + } else if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "recvonly") + || 0 == strcmp (rcvsnd, "sendrecv"))) { + recv_send = 0; + sprintf (rcvsnd, "sendonly"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } + pos_media++; + } + + if (recv_send == -1) { + /* we need to add a global attribute with a field set to "sendonly" */ + sdp_message_a_attribute_add (sdp, -1, osip_strdup ("sendonly"), NULL); + } + return 0; +} + +int +SipVoIPLink::sdp_off_hold_call (sdp_message_t * sdp) +{ + int pos; + int pos_media = -1; + char *rcvsnd; + + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") + || 0 == strcmp (rcvsnd, "recvonly"))) { + sprintf (rcvsnd, "sendrecv"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } + + pos_media = 0; + while (!sdp_message_endof_media (sdp, pos_media)) { + pos = 0; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + while (rcvsnd != NULL) { + if (rcvsnd != NULL && (0 == strcmp (rcvsnd, "sendonly") + || 0 == strcmp (rcvsnd, "recvonly"))) { + sprintf (rcvsnd, "sendrecv"); + } + pos++; + rcvsnd = sdp_message_a_att_field_get (sdp, pos_media, pos); + } + pos_media++; + } + + return 0; +} + +int +SipVoIPLink::sdp_complete_200ok (int did, osip_message_t * answer, int port) +{ + sdp_message_t *remote_sdp; + sdp_media_t *remote_med; + char *tmp = NULL; + char buf[4096]; + char port_tmp[64]; + int pos; + + char localip[128]; + + // Format port to a char* + bzero(port_tmp, 64); + snprintf(port_tmp, 63, "%d", port); + + remote_sdp = eXosip_get_remote_sdp (did); + if (remote_sdp == NULL) { + return -1; /* no existing body? */ + } + + eXosip_guess_localip (AF_INET, localip, 128); + snprintf (buf, 4096, + "v=0\r\n" + "o=user 0 0 IN IP4 %s\r\n" + "s=session\r\n" "c=IN IP4 %s\r\n" "t=0 0\r\n", localip,localip); + + pos = 0; + while (!osip_list_eol (remote_sdp->m_medias, pos)) { + char payloads[128]; + int pos2; + + memset (payloads, '\0', sizeof (payloads)); + remote_med = (sdp_media_t *) osip_list_get (remote_sdp->m_medias, pos); + + if (0 == osip_strcasecmp (remote_med->m_media, "audio")) { + pos2 = 0; + while (!osip_list_eol (remote_med->m_payloads, pos2)) { + tmp = (char *) osip_list_get (remote_med->m_payloads, pos2); + if (tmp != NULL && (0 == osip_strcasecmp (tmp, "0") + || 0 == osip_strcasecmp (tmp, "8") + || 0 == osip_strcasecmp (tmp, "3"))) { + strcat (payloads, tmp); + strcat (payloads, " "); + } + pos2++; + } + strcat (buf, "m="); + strcat (buf, remote_med->m_media); + if (pos2 == 0 || payloads[0] == '\0') { + strcat (buf, " 0 RTP/AVP \r\n"); + sdp_message_free (remote_sdp); + return -1; /* refuse anyway */ + } else { + strcat (buf, " "); + strcat (buf, port_tmp); + strcat (buf, " RTP/AVP "); + strcat (buf, payloads); + strcat (buf, "\r\n"); + + if (NULL != strstr (payloads, " 0 ") + || (payloads[0] == '0' && payloads[1] == ' ')) { + strcat (buf, "a=rtpmap:0 PCMU/8000\r\n"); + } + if (NULL != strstr (payloads, " 8 ") + || (payloads[0] == '8' && payloads[1] == ' ')) { + strcat (buf, "a=rtpmap:8 PCMA/8000\r\n"); + } + if (NULL != strstr (payloads, " 3") + || (payloads[0] == '3' && payloads[1] == ' ')) { + strcat (buf, "a=rtpmap:3 GSM/8000\r\n"); + } + } + } else { + strcat (buf, "m="); + strcat (buf, remote_med->m_media); + strcat (buf, " 0 "); + strcat (buf, remote_med->m_proto); + strcat (buf, " \r\n"); + } + pos++; + } + + osip_message_set_body (answer, buf, strlen (buf)); + osip_message_set_content_type (answer, "application/sdp"); + sdp_message_free (remote_sdp); + return 0; +} + int SipVoIPLink::behindNat (void) @@ -852,18 +1138,10 @@ SipVoIPLink::startCall (short id, const string& from, const string& to, Manager::instance().error()->errorName(TO_ERROR); return -1; } - - i = eXosip_build_initial_invite(&invite,(char*)to.data(),(char*)from.data(), - (char*)route.data(), (char*)subject.data()); - if (i != 0) { - return -1; - } - - eXosip_lock(); char port[64]; if (!Manager::instance().useStun()) { - // Set random port for outgoing call + // Set random port for outgoing call if no firewall setLocalPort(RANDOM_LOCAL_PORT); _debug("Local audio port: %d\n",_localPort); } else { @@ -876,6 +1154,7 @@ SipVoIPLink::startCall (short id, const string& from, const string& to, } } + // Set local audio port for sipcall(id) if (getSipCall(id) != NULL) { getSipCall(id)->setLocalAudioPort(_localPort); } else { @@ -884,12 +1163,73 @@ SipVoIPLink::startCall (short id, const string& from, const string& to, bzero (port, 64); snprintf (port, 63, "%d", getLocalPort()); - - i = eXosip_initiate_call(invite, NULL, NULL, port); + + i = eXosip_call_build_initial_invite (&invite, (char*)to.data(), + (char*)from.data(), + (char*)route.data(), + (char*)subject.data()); + if (i != 0) { + return -1; + } + + + int payload; + unsigned int nb; + char rtpmap[128]; + char rtpmap_attr[2048]; + char media[64]; + char media_audio[64]; + + bzero(rtpmap, 128); + bzero(rtpmap_attr, 2048); + bzero(media, 64); + bzero(media_audio, 64); + + // Set rtpmap according to the supported codec order + nb = Manager::instance().getNumberOfCodecs(); + for (unsigned int i = 0; i < nb; i++) { + payload = Manager::instance().getCodecDescVector()->at(i)->getPayload(); + + // Add payload to rtpmap if it is not already added + if (!isInRtpmap(i, payload, Manager::instance().getCodecDescVector())) { + snprintf(media, 63, "%d ", payload); + strcat (media_audio, media); + + snprintf(rtpmap, 127, "a=rtpmap: %d %s/%d\r\n", payload, + Manager::instance().getCodecDescVector()->at(i)->rtpmapPayload(payload).data(), SAMPLING_RATE); + strcat(rtpmap_attr, rtpmap); + } + } + + /* add sdp body */ + { + char tmp[4096]; + char localip[128]; + + eXosip_guess_localip (AF_INET, localip, 128); + snprintf (tmp, 4096, + "v=0\r\n" + "o=SFLphone 0 0 IN IP4 %s\r\n" + "s=call\r\n" + "c=IN IP4 %s\r\n" + "t=0 0\r\n" + "m=audio %s RTP/AVP %s\r\n" + "%s", + localip, localip, port, media_audio, rtpmap_attr); + + osip_message_set_body (invite, tmp, strlen (tmp)); + osip_message_set_content_type (invite, "application/sdp"); + } + + eXosip_lock(); + + i = eXosip_call_send_initial_invite (invite); if (i <= 0) { eXosip_unlock(); return -1; + } else { + eXosip_call_set_reference (i, NULL); } eXosip_unlock(); diff --git a/src/sipvoiplink.h b/src/sipvoiplink.h index ae34952765d451170a34e07bf43b51e8f2637c04..fbcbf7d9c3f3469e67918f9ecf37323fcfdf97c4 100644 --- a/src/sipvoiplink.h +++ b/src/sipvoiplink.h @@ -20,7 +20,8 @@ #ifndef __SIP_VOIP_LINK_H__ #define __SIP_VOIP_LINK_H__ -#include <eXosip/eXosip.h> +#include <eXosip2/eXosip.h> +#include <osipparser2/sdp_message.h> #include <string> #include <vector> @@ -30,8 +31,12 @@ using namespace std; #define EXPIRES_VALUE 180 +#define INVITE_METHOD "INVITE" // 1XX responses #define DIALOG_ESTABLISHED 101 +#define RINGING 180 +// 2XX +#define OK 200 // 4XX Errors #define BAD_REQ 400 #define UNAUTHORIZED 401 @@ -41,6 +46,7 @@ using namespace std; #define NOT_ACCEPTABLE 406 #define AUTH_REQUIRED 407 #define REQ_TIMEOUT 408 +#define UNSUP_MEDIA_TYPE 415 #define TEMP_UNAVAILABLE 480 #define ADDR_INCOMPLETE 484 #define BUSY_HERE 486 @@ -122,6 +128,21 @@ private: short findCallId (eXosip_event_t *e); short findCallIdWhenRinging (void); bool isInRtpmap (int index, int payload, CodecDescriptorVector* cdv); + + /* + * To build sdp with 200 OK when answered call + */ + int sdp_complete_200ok(int did, osip_message_t * answer, int port); + + /* + * To build sdp when call is on-hold + */ + int sdp_hold_call (sdp_message_t * sdp); + + /* + * To build sdp when call is off-hold + */ + int sdp_off_hold_call (sdp_message_t * sdp); EventThread* _evThread; SipCallVector* _sipcallVector;