diff options
6 files changed, 889 insertions, 0 deletions
diff --git a/pjsip/include/pjsua-lib/pjsua_internal.h b/pjsip/include/pjsua-lib/pjsua_internal.h index 877e6b8e..f20b73de 100644 --- a/pjsip/include/pjsua-lib/pjsua_internal.h +++ b/pjsip/include/pjsua-lib/pjsua_internal.h @@ -90,6 +90,12 @@ typedef struct pjsua_call char last_text_buf_[128]; /**< Buffer for last_text. */ + struct { + pj_timer_entry reinv_timer;/**< Reinvite retry timer. */ + pjmedia_sdp_session *new_sdp;/**< The new SDP offer. */ + } lock_codec; /**< Data for codec locking when answer + contains multiple codecs. */ + } pjsua_call; diff --git a/pjsip/src/pjsua-lib/pjsua_call.c b/pjsip/src/pjsua-lib/pjsua_call.c index 85db6d5f..f3ca5cba 100644 --- a/pjsip/src/pjsua-lib/pjsua_call.c +++ b/pjsip/src/pjsua-lib/pjsua_call.c @@ -24,6 +24,12 @@ #define THIS_FILE "pjsua_call.c" +/* Retry interval of sending re-INVITE for locking a codec when remote + * SDP answer contains multiple codec, in milliseconds. + */ +#define LOCK_CODEC_RETRY_INTERVAL 200 + + /* This callback receives notification from invite session when the * session state has changed. */ @@ -1513,6 +1519,13 @@ PJ_DEF(pj_status_t) pjsua_call_hangup(pjsua_call_id call_id, return status; } + /* Stop lock codec timer, if it is active */ + if (call->lock_codec.reinv_timer.id) { + pjsip_endpt_cancel_timer(pjsua_var.endpt, + &call->lock_codec.reinv_timer); + call->lock_codec.reinv_timer.id = PJ_FALSE; + } + pjsip_dlg_dec_lock(dlg); return PJ_SUCCESS; @@ -2913,6 +2926,226 @@ PJ_DEF(pj_status_t) pjsua_call_dump( pjsua_call_id call_id, } +/* Timer callback to close sound device */ +static void reinv_timer_cb(pj_timer_heap_t *th, + pj_timer_entry *entry) +{ + pjsua_call_id call_id = (pjsua_call_id)(pj_size_t)entry->user_data; + pjsip_dialog *dlg; + pjsua_call *call; + pjsip_tx_data *tdata; + pj_status_t status; + + PJ_UNUSED_ARG(th); + + pjsua_var.calls[call_id].lock_codec.reinv_timer.id = PJ_FALSE; + + status = acquire_call("reinv_timer_cb()", call_id, &call, &dlg); + if (status != PJ_SUCCESS) + return; + + /* Verify if another SDP negotiation is in progress, e.g: session timer + * or another re-INVITE. + */ + if (call->inv==NULL || call->inv->neg==NULL || + pjmedia_sdp_neg_get_state(call->inv->neg)!=PJMEDIA_SDP_NEG_STATE_DONE) + { + goto on_return; + } + + /* Verify if another SDP negotiation has been completed by comparing + * the SDP version. + */ + { + const pjmedia_sdp_session *sdp; + + status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &sdp); + if (status == PJ_SUCCESS && + sdp->origin.version > call->lock_codec.new_sdp->origin.version) + { + goto on_return; + } + } + + /* Create re-INVITE with the new offer */ + status = pjsip_inv_reinvite(call->inv, NULL, call->lock_codec.new_sdp, + &tdata); + if (status == PJ_EINVALIDOP) { + /* Ups, let's reschedule again */ + pj_time_val delay = {0, LOCK_CODEC_RETRY_INTERVAL}; + call->lock_codec.reinv_timer.id = PJ_TRUE; + pjsip_endpt_schedule_timer(pjsua_var.endpt, + &call->lock_codec.reinv_timer, &delay); + } else if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed creating re-INVITE in lock codec", + status); + } + + /* Send the UPDATE/re-INVITE request */ + status = pjsip_inv_send_msg(call->inv, tdata); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Failed sending re-INVITE in lock codec", + status); + } + +on_return: + pjsip_dlg_dec_lock(dlg); +} + + +/* Check if the specified format can be skipped in counting codecs */ +static pj_bool_t is_non_av_fmt(const pjmedia_sdp_media *m, + const pj_str_t *fmt) +{ + unsigned pt; + + pt = pj_strtoul(fmt); + + /* Check for comfort noise */ + if (pt == PJMEDIA_RTP_PT_CN) + return PJ_TRUE; + + /* Dynamic PT, check the format name */ + if (pt >= 96) { + pjmedia_sdp_attr *a; + pjmedia_sdp_rtpmap rtpmap; + + /* Get the format name */ + a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt); + if (a && pjmedia_sdp_attr_get_rtpmap(a, &rtpmap)==PJ_SUCCESS) { + /* Check for telephone-event */ + if (pj_stricmp2(&rtpmap.enc_name, "telephone-event")==0) + return PJ_TRUE; + } else { + /* Invalid SDP, should not reach here */ + pj_assert(!"SDP should have been validated!"); + return PJ_TRUE; + } + } + + return PJ_FALSE; +} + + +/* Check if remote answerer has given us more than one codecs. If so, + * create another offer with one codec only to lock down the codec. + */ +static pj_status_t lock_codec(pjsua_call *call) +{ + const pj_str_t st_update = {"UPDATE", 6}; + pjsip_inv_session *inv = call->inv; + const pjmedia_sdp_session *local_sdp; + const pjmedia_sdp_session *remote_sdp; + const pjmedia_sdp_media *rem_m; + pjmedia_sdp_session *new_sdp; + pjmedia_sdp_media *m; + pjsip_tx_data *tdata; + unsigned i, codec_cnt = 0; + pj_status_t status; + + if (!pjmedia_sdp_neg_was_answer_remote(inv->neg)) + return PJ_SUCCESS; + + status = pjmedia_sdp_neg_get_active_local(call->inv->neg, &local_sdp); + if (status != PJ_SUCCESS) + return status; + status = pjmedia_sdp_neg_get_active_remote(call->inv->neg, &remote_sdp); + if (status != PJ_SUCCESS) + return status; + + PJ_ASSERT_RETURN(call->audio_idx>=0 && + call->audio_idx < (int)remote_sdp->media_count, + PJ_EINVALIDOP); + + rem_m = remote_sdp->media[call->audio_idx]; + + /* Check if media is disabled or only one format in the answer. */ + if (rem_m->desc.port==0 || rem_m->desc.fmt_count==1) + return PJ_SUCCESS; + + /* Count the formats in the answer. */ + for (i=0; i<rem_m->desc.fmt_count && codec_cnt <= 1; ++i) { + if (!is_non_av_fmt(rem_m, &rem_m->desc.fmt[i])) + ++codec_cnt; + } + + if (codec_cnt <= 1) { + /* Answer contains single codec. */ + return PJ_SUCCESS; + } + + PJ_LOG(3, (THIS_FILE, "Got answer with multiple codecs, start " + "updating media session to use only one codec..")); + + /* Clone the offer */ + new_sdp = pjmedia_sdp_session_clone(inv->pool_prov, local_sdp); + /* Note that the usage of pool_prov above is risky when locking codec + * delays the re-INVITE (using timer) and there are two SDP negotiations + * done before the re-INVITE. + */ + + /* Update the new offer so it contains only a codec. Note that formats + * order in the offer should have been matched to the answer, so we can + * just directly update the offer without looking-up the answer. + */ + m = new_sdp->media[call->audio_idx]; + codec_cnt = 0; + i = 0; + while (i < m->desc.fmt_count) { + pjmedia_sdp_attr *a; + pj_str_t *fmt = &m->desc.fmt[i]; + + if (is_non_av_fmt(m, fmt) || (++codec_cnt == 1)) { + ++i; + continue; + } + + /* Remove format */ + a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "rtpmap", fmt); + if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); + a = pjmedia_sdp_attr_find2(m->attr_count, m->attr, "fmtp", fmt); + if (a) pjmedia_sdp_attr_remove(&m->attr_count, m->attr, a); + pj_array_erase(m->desc.fmt, sizeof(m->desc.fmt[0]), + m->desc.fmt_count, i); + --m->desc.fmt_count; + } + + /* Send new SDP offer via UPDATE or re-INVITE */ + if (pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)== + PJSIP_DIALOG_CAP_SUPPORTED) + { + /* Create UPDATE with the new offer */ + status = pjsip_inv_update(inv, NULL, new_sdp, &tdata); + if (status != PJ_SUCCESS) + return status; + + } else { + /* Create re-INVITE with the new offer */ + status = pjsip_inv_reinvite(inv, NULL, new_sdp, &tdata); + if (status == PJ_EINVALIDOP) { + /* Current INVITE transaction is pending, reschedule re-INVITE. */ + pj_time_val delay = {0, LOCK_CODEC_RETRY_INTERVAL}; + + call->lock_codec.new_sdp = new_sdp; + pj_timer_entry_init(&call->lock_codec.reinv_timer, PJ_TRUE, + (void*)(pj_size_t)call->index, + &reinv_timer_cb); + pjsip_endpt_schedule_timer(pjsua_var.endpt, + &call->lock_codec.reinv_timer, &delay); + return PJ_SUCCESS; + + } else if (status != PJ_SUCCESS) + return status; + } + + /* Send the UPDATE/re-INVITE request */ + status = pjsip_inv_send_msg(inv, tdata); + if (status != PJ_SUCCESS) + return status; + + return PJ_SUCCESS; +} + /* * This callback receives notification from invite session when the * session state has changed. @@ -2946,6 +3179,16 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv, break; case PJSIP_INV_STATE_CONFIRMED: pj_gettimeofday(&call->conn_time); + + /* Ticket #476, locking a codec in the media session. */ + { + pj_status_t status; + status = lock_codec(call); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Unable to lock codec", status); + } + } + break; case PJSIP_INV_STATE_DISCONNECTED: pj_gettimeofday(&call->dis_time); @@ -2965,6 +3208,13 @@ static void pjsua_call_on_state_changed(pjsip_inv_session *inv, pjsip_get_status_text(call->last_code), sizeof(call->last_text_buf_)); } + + /* Stop lock codec timer, if it is active */ + if (call->lock_codec.reinv_timer.id) { + pjsip_endpt_cancel_timer(pjsua_var.endpt, + &call->lock_codec.reinv_timer); + call->lock_codec.reinv_timer.id = PJ_FALSE; + } break; default: call->last_code = (pjsip_status_code) @@ -3169,6 +3419,7 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv, pjsua_call *call; const pjmedia_sdp_session *local_sdp; const pjmedia_sdp_session *remote_sdp; + const pj_str_t st_update = {"UPDATE", 6}; PJSUA_LOCK(); @@ -3240,6 +3491,17 @@ static void pjsua_call_on_media_update(pjsip_inv_session *inv, return; } + /* Ticket #476, handle the case of early media and remote support UPDATE */ + if (inv->state == PJSIP_INV_STATE_EARLY && + pjmedia_sdp_neg_was_answer_remote(inv->neg) && + pjsip_dlg_remote_has_cap(inv->dlg, PJSIP_H_ALLOW, NULL, &st_update)== + PJSIP_DIALOG_CAP_SUPPORTED) + { + status = lock_codec(call); + if (status != PJ_SUCCESS) { + pjsua_perror(THIS_FILE, "Unable to lock codec", status); + } + } /* Call application callback, if any */ if (pjsua_var.ua_cfg.cb.on_call_media_state) diff --git a/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml new file mode 100644 index 00000000..e75e7c76 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml @@ -0,0 +1,170 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE scenario SYSTEM "sipp.dtd"> + +<!-- This program is free software; you can redistribute it and/or --> +<!-- modify it under the terms of the GNU General Public License as --> +<!-- published by the Free Software Foundation; either version 2 of the --> +<!-- License, or (at your option) any later version. --> +<!-- --> +<!-- This program is distributed in the hope that it will be useful, --> +<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of --> +<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> +<!-- GNU General Public License for more details. --> +<!-- --> +<!-- You should have received a copy of the GNU General Public License --> +<!-- along with this program; if not, write to the --> +<!-- Free Software Foundation, Inc., --> +<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> +<!-- --> +<!-- Sipp default 'uas' scenario. --> +<!-- --> + +<scenario name="UAS answer multiple formats in early media, UAS supports UPDATE method"> + <!-- By adding rrs="true" (Record Route Sets), the route sets --> + <!-- are saved and used for following messages sent. Useful to test --> + <!-- against stateful SIP proxies/B2BUAs. --> + <recv request="INVITE" crlf="true"> + <action> + <ereg regexp=".*" search_in="hdr" header="From" assign_to="3"/> + <ereg regexp="sip:(.*)>" search_in="hdr" header="Contact" assign_to="4,5"/> + <assign assign_to="4" variable="5" /> + <ereg regexp=".*" search_in="hdr" header="Via" assign_to="6"/> + <ereg regexp=".*" search_in="hdr" header="CSeq" assign_to="7"/> + </action> + </recv> + + <!-- The '[last_*]' keyword is replaced automatically by the --> + <!-- specified header if it was present in the last message received --> + <!-- (except if it was a retransmission). If the header was not --> + <!-- present or if no message has been received, the '[last_*]' --> + <!-- keyword is discarded, and all bytes until the end of the line --> + <!-- are also discarded. --> + <!-- --> + <!-- If the specified header was present several times in the --> + <!-- message, all occurences are concatenated (CRLF seperated) --> + <!-- to be used in place of the '[last_*]' keyword. --> + + <send> + <![CDATA[ + + SIP/2.0 180 Ringing + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + Allow: INVITE, UPDATE, ACK, BYE + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 8 3 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:8 PCMA/8000 + a=rtpmap:3 GSM/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + + + <recv request="UPDATE" crlf="true"> + </recv> + + <send> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + Allow: INVITE, UPDATE, ACK, BYE + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <pause milliseconds="2000"/> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + Via[$6] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + CSeq[$7] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + Allow: INVITE, UPDATE, ACK, BYE + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + <pause milliseconds="2000"/> + + <send retrans="500"> + <![CDATA[ + + BYE sip:[$5] SIP/2.0 + Via: SIP/2.0/[transport] [local_ip]:[local_port] + From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number] + To[$3] + Call-ID: [call_id] + Cseq: 1 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + </send> + + <!-- Keep the call open for a while in case the 200 is lost to be --> + <!-- able to retransmit it if we receive the BYE again. --> + <pause milliseconds="4000"/> + + + <!-- definition of the response time repartition table (unit is ms) --> + <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/> + + <!-- definition of the call length repartition table (unit is ms) --> + <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/> + +</scenario> + diff --git a/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml new file mode 100644 index 00000000..bc27c9df --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml @@ -0,0 +1,172 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE scenario SYSTEM "sipp.dtd"> + +<!-- This program is free software; you can redistribute it and/or --> +<!-- modify it under the terms of the GNU General Public License as --> +<!-- published by the Free Software Foundation; either version 2 of the --> +<!-- License, or (at your option) any later version. --> +<!-- --> +<!-- This program is distributed in the hope that it will be useful, --> +<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of --> +<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> +<!-- GNU General Public License for more details. --> +<!-- --> +<!-- You should have received a copy of the GNU General Public License --> +<!-- along with this program; if not, write to the --> +<!-- Free Software Foundation, Inc., --> +<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> +<!-- --> +<!-- Sipp default 'uas' scenario. --> +<!-- --> + +<scenario name="UAS answer with multiple formats in early media"> + <!-- By adding rrs="true" (Record Route Sets), the route sets --> + <!-- are saved and used for following messages sent. Useful to test --> + <!-- against stateful SIP proxies/B2BUAs. --> + <recv request="INVITE" crlf="true"> + </recv> + + <!-- The '[last_*]' keyword is replaced automatically by the --> + <!-- specified header if it was present in the last message received --> + <!-- (except if it was a retransmission). If the header was not --> + <!-- present or if no message has been received, the '[last_*]' --> + <!-- keyword is discarded, and all bytes until the end of the line --> + <!-- are also discarded. --> + <!-- --> + <!-- If the specified header was present several times in the --> + <!-- message, all occurences are concatenated (CRLF seperated) --> + <!-- to be used in place of the '[last_*]' keyword. --> + + <send> + <![CDATA[ + + SIP/2.0 180 Ringing + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 8 3 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:8 PCMA/8000 + a=rtpmap:3 GSM/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <pause milliseconds="2000"/> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 8 3 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:8 PCMA/8000 + a=rtpmap:3 GSM/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + + + <recv request="INVITE" crlf="true"> + <action> + <ereg regexp=".*" search_in="hdr" header="From" assign_to="3"/> + <ereg regexp="sip:(.*)>" search_in="hdr" header="Contact" assign_to="4,5"/> + <assign assign_to="4" variable="5" /> + </action> + </recv> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + + <pause milliseconds="2000"/> + + + <send retrans="500"> + <![CDATA[ + + BYE sip:[$5] SIP/2.0 + Via: SIP/2.0/[transport] [local_ip]:[local_port] + From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number] + To[$3] + Call-ID: [call_id] + Cseq: 1 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + </send> + + <!-- Keep the call open for a while in case the 200 is lost to be --> + <!-- able to retransmit it if we receive the BYE again. --> + <pause milliseconds="4000"/> + + + <!-- definition of the response time repartition table (unit is ms) --> + <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/> + + <!-- definition of the call length repartition table (unit is ms) --> + <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/> + +</scenario> + diff --git a/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml new file mode 100644 index 00000000..5d576003 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml @@ -0,0 +1,139 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE scenario SYSTEM "sipp.dtd"> + +<!-- This program is free software; you can redistribute it and/or --> +<!-- modify it under the terms of the GNU General Public License as --> +<!-- published by the Free Software Foundation; either version 2 of the --> +<!-- License, or (at your option) any later version. --> +<!-- --> +<!-- This program is distributed in the hope that it will be useful, --> +<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of --> +<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> +<!-- GNU General Public License for more details. --> +<!-- --> +<!-- You should have received a copy of the GNU General Public License --> +<!-- along with this program; if not, write to the --> +<!-- Free Software Foundation, Inc., --> +<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> +<!-- --> +<!-- Sipp default 'uas' scenario. --> +<!-- --> + +<scenario name="UAS answer multiple formats, UAS supports UPDATE method"> + <!-- By adding rrs="true" (Record Route Sets), the route sets --> + <!-- are saved and used for following messages sent. Useful to test --> + <!-- against stateful SIP proxies/B2BUAs. --> + <recv request="INVITE" crlf="true"> + <action> + <ereg regexp=".*" search_in="hdr" header="From" assign_to="3"/> + <ereg regexp="sip:(.*)>" search_in="hdr" header="Contact" assign_to="4,5"/> + <assign assign_to="4" variable="5" /> + </action> + </recv> + + <!-- The '[last_*]' keyword is replaced automatically by the --> + <!-- specified header if it was present in the last message received --> + <!-- (except if it was a retransmission). If the header was not --> + <!-- present or if no message has been received, the '[last_*]' --> + <!-- keyword is discarded, and all bytes until the end of the line --> + <!-- are also discarded. --> + <!-- --> + <!-- If the specified header was present several times in the --> + <!-- message, all occurences are concatenated (CRLF seperated) --> + <!-- to be used in place of the '[last_*]' keyword. --> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + Allow: INVITE, UPDATE, ACK, BYE + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 8 3 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:8 PCMA/8000 + a=rtpmap:3 GSM/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + + + <recv request="UPDATE" crlf="true"> + </recv> + + <send> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + Allow: INVITE, UPDATE, ACK, BYE + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <pause milliseconds="2000"/> + + <send retrans="500"> + <![CDATA[ + + BYE sip:[$5] SIP/2.0 + Via: SIP/2.0/[transport] [local_ip]:[local_port] + From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number] + To[$3] + Call-ID: [call_id] + Cseq: 1 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + </send> + + <!-- Keep the call open for a while in case the 200 is lost to be --> + <!-- able to retransmit it if we receive the BYE again. --> + <pause milliseconds="4000"/> + + + <!-- definition of the response time repartition table (unit is ms) --> + <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/> + + <!-- definition of the call length repartition table (unit is ms) --> + <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/> + +</scenario> + diff --git a/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml new file mode 100644 index 00000000..4e4170d2 --- /dev/null +++ b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml @@ -0,0 +1,140 @@ +<?xml version="1.0" encoding="ISO-8859-1" ?> +<!DOCTYPE scenario SYSTEM "sipp.dtd"> + +<!-- This program is free software; you can redistribute it and/or --> +<!-- modify it under the terms of the GNU General Public License as --> +<!-- published by the Free Software Foundation; either version 2 of the --> +<!-- License, or (at your option) any later version. --> +<!-- --> +<!-- This program is distributed in the hope that it will be useful, --> +<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of --> +<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the --> +<!-- GNU General Public License for more details. --> +<!-- --> +<!-- You should have received a copy of the GNU General Public License --> +<!-- along with this program; if not, write to the --> +<!-- Free Software Foundation, Inc., --> +<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA --> +<!-- --> +<!-- Sipp default 'uas' scenario. --> +<!-- --> + +<scenario name="UAS answer multiple formats"> + <!-- By adding rrs="true" (Record Route Sets), the route sets --> + <!-- are saved and used for following messages sent. Useful to test --> + <!-- against stateful SIP proxies/B2BUAs. --> + <recv request="INVITE" crlf="true"> + </recv> + + <!-- The '[last_*]' keyword is replaced automatically by the --> + <!-- specified header if it was present in the last message received --> + <!-- (except if it was a retransmission). If the header was not --> + <!-- present or if no message has been received, the '[last_*]' --> + <!-- keyword is discarded, and all bytes until the end of the line --> + <!-- are also discarded. --> + <!-- --> + <!-- If the specified header was present several times in the --> + <!-- message, all occurences are concatenated (CRLF seperated) --> + <!-- to be used in place of the '[last_*]' keyword. --> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 8 3 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:8 PCMA/8000 + a=rtpmap:3 GSM/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + + + <recv request="INVITE" crlf="true"> + <action> + <ereg regexp=".*" search_in="hdr" header="From" assign_to="3"/> + <ereg regexp="sip:(.*)>" search_in="hdr" header="Contact" assign_to="4,5"/> + <assign assign_to="4" variable="5" /> + </action> + </recv> + + <send retrans="500"> + <![CDATA[ + + SIP/2.0 200 OK + [last_Via:] + [last_From:] + [last_To:];tag=[call_number] + [last_Call-ID:] + [last_CSeq:] + Contact: sip:sipp@[local_ip]:[local_port] + Content-Type: application/sdp + Content-Length: [len] + + v=0 + o=- 3441953879 3441953879 IN IP4 192.168.0.15 + s=pjmedia + c=IN IP4 192.168.0.15 + t=0 0 + m=audio 4004 RTP/AVP 0 111 + a=rtpmap:0 PCMU/8000 + a=rtpmap:111 telephone-event/8000 + a=fmtp:111 0-15 + + ]]> + </send> + + <recv request="ACK" crlf="true"> + </recv> + + <pause milliseconds="2000"/> + + <send retrans="500"> + <![CDATA[ + + BYE sip:[$5] SIP/2.0 + Via: SIP/2.0/[transport] [local_ip]:[local_port] + From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number] + To[$3] + Call-ID: [call_id] + Cseq: 1 BYE + Contact: sip:sipp@[local_ip]:[local_port] + Max-Forwards: 70 + Content-Length: 0 + + ]]> + </send> + + <!-- Keep the call open for a while in case the 200 is lost to be --> + <!-- able to retransmit it if we receive the BYE again. --> + <pause milliseconds="4000"/> + + + <!-- definition of the response time repartition table (unit is ms) --> + <ResponseTimeRepartition value="10, 20, 30, 40, 50, 100, 150, 200"/> + + <!-- definition of the call length repartition table (unit is ms) --> + <CallLengthRepartition value="10, 50, 100, 500, 1000, 5000, 10000"/> + +</scenario> + |