summaryrefslogtreecommitdiff
path: root/tests
diff options
context:
space:
mode:
authorDavid M. Lee <dlee@digium.com>2013-01-07 14:24:28 -0600
committerDavid M. Lee <dlee@digium.com>2013-01-07 14:24:28 -0600
commitf3ab456a17af1c89a6e3be4d20c5944853df1cb0 (patch)
treed00e1a332cd038a6d906a1ea0ac91e1a4458e617 /tests
Import pjproject-2.0.1
Diffstat (limited to 'tests')
-rw-r--r--tests/automated/README.txt4
-rwxr-xr-xtests/automated/configure.py354
-rw-r--r--tests/automated/gnu-ipp.xml.template28
-rw-r--r--tests/automated/gnu.xml.template29
-rw-r--r--tests/automated/iphone.xml.template23
-rw-r--r--tests/automated/msvc.xml.template24
-rw-r--r--tests/automated/prepare.xml.template46
-rwxr-xr-xtests/automated/run_continuous.py140
-rw-r--r--tests/automated/run_scenario.py11
-rw-r--r--tests/automated/symbian-aps.xml.template78
-rw-r--r--tests/automated/symbian-vas.xml.template79
-rw-r--r--tests/automated/symbian.xml.template20
-rw-r--r--tests/automated/testvars.template33
-rw-r--r--tests/cdash/README.TXT59
-rw-r--r--tests/cdash/builder.py501
-rw-r--r--tests/cdash/cfg_gnu.py73
-rw-r--r--tests/cdash/cfg_msvc.py82
-rw-r--r--tests/cdash/cfg_site_sample.py50
-rw-r--r--tests/cdash/cfg_symbian.py86
-rw-r--r--tests/cdash/inc_test.py1
-rw-r--r--tests/cdash/main.py42
-rw-r--r--tests/cdash/starttest_sample.bat44
-rw-r--r--tests/pjsua/README.TXT65
-rw-r--r--tests/pjsua/config_site.py4
-rw-r--r--tests/pjsua/inc_cfg.py107
-rw-r--r--tests/pjsua/inc_const.py64
-rw-r--r--tests/pjsua/inc_sdp.py38
-rw-r--r--tests/pjsua/inc_sip.py343
-rw-r--r--tests/pjsua/mod_call.py226
-rw-r--r--tests/pjsua/mod_media_playrec.py108
-rw-r--r--tests/pjsua/mod_pesq.py167
-rw-r--r--tests/pjsua/mod_pres.py125
-rw-r--r--tests/pjsua/mod_recvfrom.py97
-rw-r--r--tests/pjsua/mod_run.py11
-rw-r--r--tests/pjsua/mod_sendto.py53
-rw-r--r--tests/pjsua/mod_sipp.py275
-rw-r--r--tests/pjsua/run.py289
-rw-r--r--tests/pjsua/runall.py187
-rw-r--r--tests/pjsua/scripts-call/100_simplecall.py12
-rw-r--r--tests/pjsua/scripts-call/150_srtp_0_1.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_0_3.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_1_0.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_1_1.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_1_2.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_1_3.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_2_1.py12
-rw-r--r--tests/pjsua/scripts-call/150_srtp_2_2.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_2_3.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_3_0.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_3_1.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_3_2.py11
-rw-r--r--tests/pjsua/scripts-call/150_srtp_3_3.py11
-rw-r--r--tests/pjsua/scripts-call/200_tcp.py12
-rw-r--r--tests/pjsua/scripts-call/300_ice_0_1.py12
-rw-r--r--tests/pjsua/scripts-call/300_ice_1_0.py12
-rw-r--r--tests/pjsua/scripts-call/300_ice_1_1.py12
-rw-r--r--tests/pjsua/scripts-call/301_ice_public_a.py22
-rw-r--r--tests/pjsua/scripts-call/301_ice_public_b.py25
-rw-r--r--tests/pjsua/scripts-call/305_ice_comp_1_2.py12
-rw-r--r--tests/pjsua/scripts-call/305_ice_comp_2_1.py12
-rw-r--r--tests/pjsua/scripts-call/350_prack_a.py12
-rw-r--r--tests/pjsua/scripts-call/350_prack_b.py12
-rw-r--r--tests/pjsua/scripts-call/400_tel_uri.py12
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_16.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_22.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_32.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_44.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_48.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_11_8.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_11.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_16.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_22.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_32.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_44.py11
-rw-r--r--tests/pjsua/scripts-media-playrec/100_resample_lf_8_48.py11
-rw-r--r--tests/pjsua/scripts-pesq/100_defaults.py19
-rw-r--r--tests/pjsua/scripts-pesq/101_defaults.py18
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_g711a.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_g711u.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_g722.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_gsm.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_ilbc.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_l16_16000.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_l16_16000_stereo.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_l16_8000.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_l16_8000_stereo.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_speex_16000.py19
-rw-r--r--tests/pjsua/scripts-pesq/200_codec_speex_8000.py19
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_g711a.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_g711u.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_g722.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_gsm.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_ilbc.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_l16_16000.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_l16_16000_stereo.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_l16_8000.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_l16_8000_stereo.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_speex_16000.py17
-rw-r--r--tests/pjsua/scripts-pesq/201_codec_speex_8000.py17
-rw-r--r--tests/pjsua/scripts-pres/100_peertopeer.py12
-rw-r--r--tests/pjsua/scripts-pres/200_publish.py35
-rw-r--r--tests/pjsua/scripts-recvfrom/100_simple.py16
-rw-r--r--tests/pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py15
-rw-r--r--tests/pjsua/scripts-recvfrom/201_reg_good_ok.py23
-rw-r--r--tests/pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py23
-rw-r--r--tests/pjsua/scripts-recvfrom/203_reg_good_empty_realm.py31
-rw-r--r--tests/pjsua/scripts-recvfrom/205_reg_good_no_realm.py16
-rw-r--r--tests/pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py26
-rw-r--r--tests/pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py29
-rw-r--r--tests/pjsua/scripts-recvfrom/209a_reg_handle_423_ok.py31
-rw-r--r--tests/pjsua/scripts-recvfrom/209b_reg_handle_423_bad_min_expires1.py20
-rw-r--r--tests/pjsua/scripts-recvfrom/209c_reg_handle_423_bad_min_expires2.py25
-rw-r--r--tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py28
-rw-r--r--tests/pjsua/scripts-recvfrom/220_reg_good_ims_ok.py26
-rw-r--r--tests/pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py41
-rw-r--r--tests/pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py41
-rw-r--r--tests/pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py41
-rw-r--r--tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py15
-rw-r--r--tests/pjsua/scripts-recvfrom/240_publish_scenarios.py51
-rw-r--r--tests/pjsua/scripts-recvfrom/300_timer_good.py17
-rw-r--r--tests/pjsua/scripts-recvfrom/301_timer_good_retry_after_422.py30
-rw-r--r--tests/pjsua/scripts-recvfrom/400_inv_answered_with_less_media.py32
-rw-r--r--tests/pjsua/scripts-run/100_simple.py13
-rw-r--r--tests/pjsua/scripts-run/200_register.py20
-rw-r--r--tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py52
-rw-r--r--tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py25
-rw-r--r--tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py35
-rw-r--r--tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py25
-rw-r--r--tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py25
-rw-r--r--tests/pjsua/scripts-sendto/100_simplecall.py20
-rw-r--r--tests/pjsua/scripts-sendto/110_tel_uri.py46
-rw-r--r--tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_1.py28
-rw-r--r--tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_2.py28
-rw-r--r--tests/pjsua/scripts-sendto/121_sdp_with_video_static_1.py28
-rw-r--r--tests/pjsua/scripts-sendto/121_sdp_with_video_static_2.py28
-rw-r--r--tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_1.py27
-rw-r--r--tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_2.py27
-rw-r--r--tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_1.py27
-rw-r--r--tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_2.py27
-rw-r--r--tests/pjsua/scripts-sendto/124_sdp_with_unknown_static_unknown_transport.py27
-rw-r--r--tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_0.py29
-rw-r--r--tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_1.py27
-rw-r--r--tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_2.py27
-rw-r--r--tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_3.py28
-rw-r--r--tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_4.py27
-rw-r--r--tests/pjsua/scripts-sendto/126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py26
-rw-r--r--tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_1.py28
-rw-r--r--tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_2.py30
-rw-r--r--tests/pjsua/scripts-sendto/150_err_extension.py27
-rw-r--r--tests/pjsua/scripts-sendto/151_err_sdp_video.py23
-rw-r--r--tests/pjsua/scripts-sendto/152_err_sdp_no_media.py22
-rw-r--r--tests/pjsua/scripts-sendto/153_err_sdp_unsupported_codec.py24
-rw-r--r--tests/pjsua/scripts-sendto/155_err_sdp_bad_syntax.py23
-rw-r--r--tests/pjsua/scripts-sendto/156_err_sdp_bad_net_type.py27
-rw-r--r--tests/pjsua/scripts-sendto/157_err_sdp_bad_addr_type.py27
-rw-r--r--tests/pjsua/scripts-sendto/158_err_sdp_bad_transport_type.py27
-rw-r--r--tests/pjsua/scripts-sendto/159_no_rport.py38
-rw-r--r--tests/pjsua/scripts-sendto/159_no_rport_nit.py25
-rw-r--r--tests/pjsua/scripts-sendto/160_err_duplicate_replaces.py23
-rw-r--r--tests/pjsua/scripts-sendto/161_err_replaces_dlg_not_found.py23
-rw-r--r--tests/pjsua/scripts-sendto/170_timer_required.py27
-rw-r--r--tests/pjsua/scripts-sendto/171_timer_initiated_by_uas.py36
-rw-r--r--tests/pjsua/scripts-sendto/172_timer_supported_but_not_used.py26
-rw-r--r--tests/pjsua/scripts-sendto/173_timer_offer_no_refresher.py26
-rw-r--r--tests/pjsua/scripts-sendto/173_timer_offer_refresher_uac.py26
-rw-r--r--tests/pjsua/scripts-sendto/173_timer_offer_refresher_uas.py26
-rw-r--r--tests/pjsua/scripts-sendto/174_timer_se_too_small.py26
-rw-r--r--tests/pjsua/scripts-sendto/200_ice_no_ice.py26
-rw-r--r--tests/pjsua/scripts-sendto/200_ice_success_1.py31
-rw-r--r--tests/pjsua/scripts-sendto/200_ice_success_2.py36
-rw-r--r--tests/pjsua/scripts-sendto/200_ice_success_3.py35
-rw-r--r--tests/pjsua/scripts-sendto/200_ice_success_4.py35
-rw-r--r--tests/pjsua/scripts-sendto/201_ice_mismatch_1.py29
-rw-r--r--tests/pjsua/scripts-sendto/201_ice_mismatch_2.py31
-rw-r--r--tests/pjsua/scripts-sendto/201_ice_mismatch_3.py30
-rw-r--r--tests/pjsua/scripts-sendto/251_multipart_ok_simple.py38
-rw-r--r--tests/pjsua/scripts-sendto/252_multipart_ok_clutter.py47
-rw-r--r--tests/pjsua/scripts-sendto/260_multipart_err_no_sdp.py38
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_crypto_case_insensitive.py27
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_duplicated_crypto_tag.py27
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_invalid_crypto_tag_non_numeric.py27
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_receive_crypto_tag_zero.py26
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_receive_no_key_1.py26
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_receive_no_key_2.py26
-rw-r--r--tests/pjsua/scripts-sendto/300_srtp_receive_no_key_3.py26
-rw-r--r--tests/pjsua/scripts-sendto/301_srtp0_recv_avp.py28
-rw-r--r--tests/pjsua/scripts-sendto/301_srtp0_recv_savp.py28
-rw-r--r--tests/pjsua/scripts-sendto/310_srtp1_no_crypto.py26
-rw-r--r--tests/pjsua/scripts-sendto/311_srtp1_recv_avp.py28
-rw-r--r--tests/pjsua/scripts-sendto/312_srtp1_recv_savp.py28
-rw-r--r--tests/pjsua/scripts-sendto/313_srtp1_unsupported_crypto.py26
-rw-r--r--tests/pjsua/scripts-sendto/320_srtp2_no_crypto.py26
-rw-r--r--tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_1.py28
-rw-r--r--tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_2.py28
-rw-r--r--tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_1.py27
-rw-r--r--tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_2.py27
-rw-r--r--tests/pjsua/scripts-sendto/321_srtp2_recv_avp.py28
-rw-r--r--tests/pjsua/scripts-sendto/322_srtp2_recv_savp.py28
-rw-r--r--tests/pjsua/scripts-sendto/323_srtp2_receive_too_long_key.py25
-rw-r--r--tests/pjsua/scripts-sendto/323_srtp2_unsupported_crypto.py26
-rw-r--r--tests/pjsua/scripts-sendto/330_srtp_prefer_rtp_savp.py30
-rw-r--r--tests/pjsua/scripts-sendto/331_srtp_prefer_rtp_avp.py29
-rw-r--r--tests/pjsua/scripts-sendto/360_non_sip_uri.py27
-rw-r--r--tests/pjsua/scripts-sendto/361_non_sip_uri.py26
-rw-r--r--tests/pjsua/scripts-sendto/362_non_sip_uri.py27
-rw-r--r--tests/pjsua/scripts-sendto/363_non_sip_uri_subscribe.py31
-rw-r--r--tests/pjsua/scripts-sendto/364_non_sip_uri_subscribe.py30
-rw-r--r--tests/pjsua/scripts-sendto/400_fmtp_g7221_with_bitrate.py34
-rw-r--r--tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_24000.py35
-rw-r--r--tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_32000.py35
-rw-r--r--tests/pjsua/scripts-sendto/410_fmtp_amrnb_offer_octet_align.py32
-rw-r--r--tests/pjsua/scripts-sendto/411_fmtp_amrnb_offer_band_eff.py31
-rw-r--r--tests/pjsua/scripts-sendto/412_fmtp_amrnb_offer_band_eff2.py32
-rw-r--r--tests/pjsua/scripts-sendto/500_pres_subscribe_with_bad_event.py28
-rw-r--r--tests/pjsua/scripts-sendto/999_asterisk_err.py45
-rw-r--r--tests/pjsua/scripts-sendto/999_message_no_body.py24
-rw-r--r--tests/pjsua/scripts-sipp/strict-route.py9
-rw-r--r--tests/pjsua/scripts-sipp/strict-route.xml161
-rw-r--r--tests/pjsua/scripts-sipp/transfer-attended.py52
-rw-r--r--tests/pjsua/scripts-sipp/transfer-attended.xml26
-rw-r--r--tests/pjsua/scripts-sipp/transfer-unattended.py30
-rw-r--r--tests/pjsua/scripts-sipp/transfer-unattended.xml26
-rw-r--r--tests/pjsua/scripts-sipp/uac-bad-ack.xml132
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-and-ack-without-sdp.xml91
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml67
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.py7
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.xml97
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-without-sdp.py11
-rw-r--r--tests/pjsua/scripts-sipp/uac-inv-without-sdp.xml110
-rw-r--r--tests/pjsua/scripts-sipp/uac-message-no-body.xml32
-rw-r--r--tests/pjsua/scripts-sipp/uac-options.xml54
-rw-r--r--tests/pjsua/scripts-sipp/uac-reinvite-bad-via-branch.xml173
-rw-r--r--tests/pjsua/scripts-sipp/uac-reinvite-port-0-bad-sdp.xml207
-rw-r--r--tests/pjsua/scripts-sipp/uac-subscribe.xml113
-rw-r--r--tests/pjsua/scripts-sipp/uac-ticket-1148.py7
-rw-r--r--tests/pjsua/scripts-sipp/uac-ticket-1148.xml98
-rw-r--r--tests/pjsua/scripts-sipp/uas-422-then-200-bad-se.xml118
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml168
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml171
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-inv-without-sdp.xml80
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml138
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml138
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.xml86
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.xml83
-rw-r--r--tests/pjsua/scripts-sipp/uas-auth.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-auth.xml64
-rw-r--r--tests/pjsua/scripts-sipp/uas-cancel-no-final.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-cancel-no-final.xml62
-rw-r--r--tests/pjsua/scripts-sipp/uas-early-bye.xml68
-rw-r--r--tests/pjsua/scripts-sipp/uas-forked-100rel.xml225
-rw-r--r--tests/pjsua/scripts-sipp/uas-forked-200.xml128
-rw-r--r--tests/pjsua/scripts-sipp/uas-inv-answered-with-srtp.xml77
-rw-r--r--tests/pjsua/scripts-sipp/uas-inv_401_retry_after_100.xml106
-rw-r--r--tests/pjsua/scripts-sipp/uas-mwi-0.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-mwi-0.xml79
-rw-r--r--tests/pjsua/scripts-sipp/uas-mwi.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-mwi.xml105
-rw-r--r--tests/pjsua/scripts-sipp/uas-prack_fork.xml130
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-and-ack-same-branch-without-sdp.xml118
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-and-ack-without-sdp.xml118
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-glare.py7
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-glare.xml153
-rw-r--r--tests/pjsua/scripts-sipp/uas-reinv-no-media.xml116
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-late-notify.py11
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-late-notify.xml152
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.py11
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.xml119
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.py10
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.xml108
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.py11
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.xml109
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.py11
-rw-r--r--tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.xml120
-rw-r--r--tests/pjsua/scripts-sipp/uas-template.xml84
-rw-r--r--tests/pjsua/scripts-sipp/uas-timer-reinvite.xml108
-rw-r--r--tests/pjsua/scripts-sipp/uas-timer-update.xml126
-rw-r--r--tests/pjsua/tools/Makefile21
-rw-r--r--tests/pjsua/tools/cmp_wav.c262
-rw-r--r--tests/pjsua/wavs/.keep0
281 files changed, 13508 insertions, 0 deletions
diff --git a/tests/automated/README.txt b/tests/automated/README.txt
new file mode 100644
index 0000000..1d1cb81
--- /dev/null
+++ b/tests/automated/README.txt
@@ -0,0 +1,4 @@
+This directory contains files to run automated/unattended tests for PJSIP.
+
+See https://trac.pjsip.org/repos/wiki/AutomatedTesting for more info.
+
diff --git a/tests/automated/configure.py b/tests/automated/configure.py
new file mode 100755
index 0000000..d277471
--- /dev/null
+++ b/tests/automated/configure.py
@@ -0,0 +1,354 @@
+#!/usr/bin/python
+
+import optparse
+import os
+import platform
+import socket
+import subprocess
+import sys
+
+PROG = "r" + "$Rev: 17 $".strip("$ ").replace("Rev: ", "")
+PYTHON = os.path.basename(sys.executable)
+build_type = ""
+vs_target = ""
+s60_target = ""
+no_test = False
+no_pjsua_test = False
+
+#
+# Get gcc version
+#
+def gcc_version(gcc):
+ proc = subprocess.Popen(gcc + " -v", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, shell=True)
+ ver = ""
+ while True:
+ s = proc.stdout.readline()
+ if not s:
+ break
+ if s.find("gcc version") >= 0:
+ ver = s.split(None, 3)[2]
+ break
+ proc.wait()
+ return "gcc-" + ver
+
+#
+# Get Visual Studio info
+#
+class VSVersion:
+ def __init__(self):
+ self.version = "8"
+ self.release = "2005"
+
+ proc = subprocess.Popen("cl", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ while True:
+ s = proc.stdout.readline()
+ if s=="":
+ break
+ pos = s.find("Version")
+ if pos > 0:
+ proc.wait()
+ s = s[pos+8:]
+ ver = s.split(None, 1)[0]
+ major = ver[0:2]
+ if major=="12":
+ self.version = "6"
+ self.release = "98"
+ break
+ elif major=="13":
+ self.version = "7"
+ self.release = "2003"
+ break
+ elif major=="14":
+ self.version = "8"
+ self.release = "2005"
+ break
+ elif major=="15":
+ self.version = "9"
+ self.release = "2008"
+ break
+ elif major=="16":
+ self.version = "10"
+ self.release = "2010"
+ break
+ else:
+ self.version = "11"
+ self.release = "2012"
+ break
+ proc.wait()
+ self.vs_version = "vs" + self.version
+ self.vs_release = "vs" + self.release
+
+
+#
+# Get S60 SDK info
+#
+class S60SDK:
+ def __init__(self):
+ self.epocroot = ""
+ self.sdk = ""
+ self.device = ""
+
+ # Check that EPOCROOT is set
+ if not "EPOCROOT" in os.environ:
+ sys.stderr.write("Error: EPOCROOT environment variable is not set\n")
+ sys.exit(1)
+ epocroot = os.environ["EPOCROOT"]
+ # EPOCROOT must have trailing backslash
+ if epocroot[-1] != "\\":
+ epocroot = epocroot + "\\"
+ os.environ["EPOCROOT"] = epocroot
+ self.epocroot = epocroot
+ self.sdk = sdk1 = epocroot.split("\\")[-2]
+ self.device = "@" + self.sdk + ":com.nokia.s60"
+
+ # Check that correct device is set
+ proc = subprocess.Popen("devices", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, shell=True)
+ sdk2 = ""
+ while True:
+ line = proc.stdout.readline()
+ if line.find("- default") > 0:
+ sdk2 = line.split(":",1)[0]
+ break
+ proc.wait()
+
+ if sdk1 != sdk2:
+ sys.stderr.write("Error: default SDK in device doesn't match EPOCROOT\n")
+ sys.stderr.write("Default device SDK = '" + sdk2 + "'\n")
+ sys.stderr.write("EPOCROOT SDK = '" + sdk1 + "'\n")
+ sys.exit(1)
+
+ self.name = sdk2.replace("_", "-")
+
+
+
+def replace_vars(text):
+ global vs_target, s60_target, build_type, no_test, no_pjsua_test
+ suffix = ""
+
+ os_info = platform.system() + platform.release() + "-" + platform.machine()
+
+ # osinfo
+ s60sdk_var = None
+ if build_type == "s60":
+ s60sdk_var = S60SDK()
+ os_info = s60sdk_var.name
+ elif platform.system().lower() == "windows" or platform.system().lower() == "microsoft":
+ if platform.system().lower() == "microsoft":
+ os_info = platform.release() + "-" + platform.version() + "-" + platform.win32_ver()[2]
+ elif platform.system().lower() == "linux":
+ os_info = "-" + "-".join(platform.linux_distribution()[0:2])
+
+ # vs_target
+ if not vs_target and text.find("$(VSTARGET)") >= 0:
+ if build_type != "vs":
+ sys.stderr.write("Warning: $(VSTARGET) only valid for Visual Studio\n")
+ print "Enter Visual Studio vs_target name (e.g. Release, Debug) [Release]: ",
+ vs_target = sys.stdin.readline().replace("\n", "").replace("\r", "")
+ if not vs_target:
+ vs_target = "Release"
+
+ # s60_target
+ if not s60_target and text.find("$(S60TARGET)") >= 0:
+ if build_type != "s60":
+ sys.stderr.write("Warning: $(S60TARGET) only valid for S60\n")
+ print "Enter S60 target name (e.g. \"gcce urel\") [gcce urel]: ",
+ s60_target = sys.stdin.readline().replace("\n", "").replace("\r", "")
+ if not s60_target:
+ s60_target = "gcce urel"
+
+ # Suffix
+ if build_type == "vs":
+ suffix = "i386-Win32-vc8-" + vs_target
+ elif build_type == "s60":
+ suffix = s60sdk_var.name + "-" + s60_target.replace(" ", "-")
+ elif build_type == "gnu":
+ proc = subprocess.Popen("sh config.guess", cwd="../..",
+ shell=True, stdout=subprocess.PIPE)
+ suffix = proc.stdout.readline().rstrip(" \r\n")
+ else:
+ sys.stderr.write("Error: unsupported build type '" + build_type + "'\n")
+ sys.exit(1)
+
+ while True:
+ if text.find("$(PJSUA-TESTS)") >= 0:
+ if no_test==False and no_pjsua_test==False:
+ # Determine pjsua exe to use
+ exe = "../../pjsip-apps/bin/pjsua-" + suffix
+ proc = subprocess.Popen(PYTHON + " runall.py --list-xml -e " + exe,
+ cwd="../pjsua",
+ shell=True, stdout=subprocess.PIPE)
+ content = proc.stdout.read()
+ else:
+ content = ""
+ text = text.replace("$(PJSUA-TESTS)", content)
+ elif text.find("$(GCC)") >= 0:
+ text = text.replace("$(GCC)", gcc_version("gcc"))
+ elif text.find("$(VS)") >= 0:
+ vsver = VSVersion()
+ text = text.replace("$(VS)", VSVersion().vs_release)
+ elif text.find("$(VSTARGET)") >= 0:
+ text = text.replace("$(VSTARGET)", vs_target)
+ elif text.find("$(S60TARGET)") >= 0:
+ text = text.replace("$(S60TARGET)", s60_target)
+ elif text.find("$(S60TARGETNAME)") >= 0:
+ text = text.replace("$(S60TARGETNAME)", s60_target.replace(" ", "-"))
+ elif text.find("$(S60DEVICE)") >= 0:
+ text = text.replace("$(S60DEVICE)", s60sdk_var.device)
+ elif text.find("$(EPOCROOT)") >= 0:
+ text = text.replace("$(EPOCROOT)", s60sdk_var.epocroot)
+ elif text.find("$(DISABLED)") >= 0:
+ text = text.replace("$(DISABLED)", "0")
+ elif text.find("$(IPPROOT)") >= 0:
+ if not os.environ.has_key("IPPROOT"):
+ sys.stderr.write("Error: environment variable IPPROOT is needed but not set\n")
+ sys.exit(1)
+ text = text.replace("$(IPPROOT)", os.environ["IPPROOT"])
+ elif text.find("$(IPPSAMPLES)") >= 0:
+ if not os.environ.has_key("IPPSAMPLES"):
+ sys.stderr.write("Error: environment variable IPPSAMPLES is needed but not set\n")
+ sys.exit(1)
+ text = text.replace("$(IPPSAMPLES)", os.environ["IPPSAMPLES"])
+ elif text.find("$(IPPARCH)") >= 0:
+ if not os.environ.has_key("IPPARCH"):
+ text = text.replace("$(IPPARCH)", "")
+ else:
+ text = text.replace("$(IPPARCH)", os.environ["IPPARCH"])
+ elif text.find("$(OS)") >= 0:
+ text = text.replace("$(OS)", os_info)
+ elif text.find("$(SUFFIX)") >= 0:
+ text = text.replace("$(SUFFIX)", suffix)
+ elif text.find("$(HOSTNAME)") >= 0:
+ text = text.replace("$(HOSTNAME)", socket.gethostname())
+ elif text.find("$(PJDIR)") >= 0:
+ wdir = os.path.join(os.getcwd(), "../..")
+ wdir = os.path.normpath(wdir)
+ text = text.replace("$(PJDIR)", wdir)
+ elif text.find("$(NOP)") >= 0:
+ if platform.system().lower() == "windows" or platform.system().lower() == "microsoft":
+ cmd = "CMD /C echo Success"
+ else:
+ cmd = "echo Success"
+ text = text.replace("$(NOP)", cmd)
+ elif text.find("$(NOTEST)") >= 0:
+ if no_test:
+ str = '"1"'
+ else:
+ str = '"0"'
+ text = text.replace("$(NOTEST)", str)
+ else:
+ break
+ return text
+
+
+def main(args):
+ global vs_target, s60_target, build_type, no_test, no_pjsua_test
+ output = sys.stdout
+ usage = """Usage: configure.py [OPTIONS] scenario_template_file
+
+Where OPTIONS:
+ -o FILE Output to file, otherwise to stdout.
+ -t TYPE Specify build type. If not specified, it will be
+ asked if necessary. Values are:
+ vs: Visual Studio
+ gnu: Makefile based
+ s60: Symbian S60
+ -vstarget TARGETNAME Specify Visual Studio target name if build type is set
+ to vs. If not specified then it will be asked.
+ Sample target names:
+ - Debug
+ - Release
+ - or any other target in the project file
+ -s60target TARGETNAME Specify S60 target name if build type is set to s60.
+ If not specified then it will be asked. Sample target
+ names:
+ - "gcce udeb"
+ - "gcce urel"
+ -notest Disable all tests in the scenario.
+ -nopjsuatest Disable pjsua tests in the scenario.
+"""
+
+ args.pop(0)
+ while len(args):
+ if args[0]=='-o':
+ args.pop(0)
+ if len(args):
+ output = open(args[0], "wt")
+ args.pop(0)
+ else:
+ sys.stderr.write("Error: needs value for -o\n")
+ sys.exit(1)
+ elif args[0]=='-vstarget':
+ args.pop(0)
+ if len(args):
+ vs_target = args[0]
+ args.pop(0)
+ else:
+ sys.stderr.write("Error: needs value for -vstarget\n")
+ sys.exit(1)
+ elif args[0]=='-s60target':
+ args.pop(0)
+ if len(args):
+ s60_target = args[0]
+ args.pop(0)
+ else:
+ sys.stderr.write("Error: needs value for -s60target\n")
+ sys.exit(1)
+ elif args[0]=='-t':
+ args.pop(0)
+ if len(args):
+ build_type = args[0].lower()
+ args.pop(0)
+ else:
+ sys.stderr.write("Error: needs value for -t\n")
+ sys.exit(1)
+ if not ["vs", "gnu", "s60"].count(build_type):
+ sys.stderr.write("Error: invalid -t argument value\n")
+ sys.exit(1)
+ elif args[0]=='-notest' or args[0]=='-notests':
+ args.pop(0)
+ no_test = True
+ elif args[0]=='-nopjsuatest' or args[0]=='-nopjsuatests':
+ args.pop(0)
+ no_pjsua_test = True
+ else:
+ break
+
+ if len(args) != 1:
+ sys.stderr.write(usage + "\n")
+ return 1
+
+ if not build_type:
+ defval = "vs"
+ if "SHELL" in os.environ:
+ shell = os.environ["SHELL"]
+ if shell.find("sh") > -1:
+ defval = "gnu"
+ print "Enter the build type (values: vs, gnu, s60) [%s]: " % (defval),
+ build_type = sys.stdin.readline().replace("\n", "").replace("\r", "")
+ if not build_type:
+ build_type = defval
+
+
+ tpl_file = args[len(args)-1]
+ if not os.path.isfile(tpl_file):
+ print "Error: unable to find template file '%s'" % (tpl_file)
+ return 1
+
+ f = open(tpl_file, "r")
+ tpl = f.read()
+ f.close()
+
+ tpl = replace_vars(tpl)
+ output.write(tpl)
+ if output != sys.stdout:
+ output.close()
+ return 0
+
+
+if __name__ == "__main__":
+ rc = main(sys.argv)
+ sys.exit(rc)
+
diff --git a/tests/automated/gnu-ipp.xml.template b/tests/automated/gnu-ipp.xml.template
new file mode 100644
index 0000000..f6daf51
--- /dev/null
+++ b/tests/automated/gnu-ipp.xml.template
@@ -0,0 +1,28 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+ <Submit group="Experimental" build="$(SUFFIX)-$(GCC)-IPP" disabled="$(DISABLED)" >
+ <Update />
+ <FileWrite file="user.mak">
+ <![CDATA[
+# Written by ccdash
+export CFLAGS += -Wno-unused-label -g
+]]>
+ </FileWrite>
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_HAS_IPV6 1
+#define PJMEDIA_HAS_G7221_CODEC 0
+#define PJMEDIA_HAS_INTEL_IPP 1
+]]>
+ </FileWrite>
+ <Configure cmd='./aconfigure --enable-ipp --with-ipp="$(IPPROOT)" --with-ipp-samples="$(IPPSAMPLES)" --with-ipp-arch=$(IPPARCH)' />
+ <Build cmd="make dep &amp;&amp; make clean &amp;&amp; make" />
+ <Test name="pjlib-test" wdir="pjlib/bin" cmd="./pjlib-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjlib-util-test" wdir="pjlib-util/bin" cmd="./pjlib-util-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjnath-test" wdir="pjnath/bin" cmd="./pjnath-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjmedia-test" wdir="pjmedia/bin" cmd="./pjmedia-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjsip-test" wdir="pjsip/bin" cmd="./pjsip-test-$(SUFFIX)" disabled=$(NOTEST) />
+ $(PJSUA-TESTS)
+ </Submit>
+</Scenario>
diff --git a/tests/automated/gnu.xml.template b/tests/automated/gnu.xml.template
new file mode 100644
index 0000000..d453f44
--- /dev/null
+++ b/tests/automated/gnu.xml.template
@@ -0,0 +1,29 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+
+ <Submit group="Experimental" build="$(SUFFIX)-$(GCC)" exclude="(.*amr.*)">
+ <Update />
+ <FileWrite file="user.mak">
+ <![CDATA[
+# Written by ccdash
+export CFLAGS += -Wno-unused-label -g
+]]>
+ </FileWrite>
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_HAS_IPV6 1
+#define PJMEDIA_HAS_G7221_CODEC 1
+]]>
+ </FileWrite>
+ <Configure cmd="./aconfigure" />
+ <Build cmd="make dep &amp;&amp; make clean &amp;&amp; make" />
+ <Test name="pjlib-test" wdir="pjlib/bin" cmd="./pjlib-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjlib-util-test" wdir="pjlib-util/bin" cmd="./pjlib-util-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjnath-test" wdir="pjnath/bin" cmd="./pjnath-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjmedia-test" wdir="pjmedia/bin" cmd="./pjmedia-test-$(SUFFIX)" disabled=$(NOTEST) />
+ <Test name="pjsip-test" wdir="pjsip/bin" cmd="./pjsip-test-$(SUFFIX)" disabled=$(NOTEST) />
+ $(PJSUA-TESTS)
+ </Submit>
+
+</Scenario>
diff --git a/tests/automated/iphone.xml.template b/tests/automated/iphone.xml.template
new file mode 100644
index 0000000..b4b0c9d
--- /dev/null
+++ b/tests/automated/iphone.xml.template
@@ -0,0 +1,23 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+
+ <Submit group="Experimental" build="iPhoneOS-default">
+ <Update />
+ <FileWrite file="user.mak">
+ <![CDATA[
+# Written by ccdash
+export CFLAGS += -Wno-unused-label -g
+]]>
+ </FileWrite>
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_CONFIG_IPHONE 1
+#include <pj/config_site_sample.h>
+]]>
+ </FileWrite>
+ <Configure cmd="./configure-iphone" />
+ <Build cmd="make distclean &amp;&amp; make dep &amp;&amp; make clean &amp;&amp; make" />
+ </Submit>
+
+</Scenario>
diff --git a/tests/automated/msvc.xml.template b/tests/automated/msvc.xml.template
new file mode 100644
index 0000000..d4dc8ff
--- /dev/null
+++ b/tests/automated/msvc.xml.template
@@ -0,0 +1,24 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+
+ <Submit group="Experimental" build="$(OS)-$(VS)-$(VSTARGET)-default" exclude="(.*amr.*)">
+ <Update />
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_HAS_IPV6 1
+#define PJMEDIA_HAS_G7221_CODEC 1
+#define PJ_TODO(x)
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c echo success" />
+ <Build cmd='vcbuild.exe /nologo /nohtmllog /nocolor /rebuild pjproject-vs8.sln "$(VSTARGET)|Win32"' />
+ <Test name="pjlib-test" info="" wdir="pjlib/bin" cmd="pjlib-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST)/>
+ <Test name="pjlib-util-test" info="" wdir="pjlib-util/bin" cmd="pjlib-util-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
+ <Test name="pjnath-test" info="" wdir="pjnath/bin" cmd="pjnath-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
+ <Test name="pjmedia-test" info="" wdir="pjmedia/bin" cmd="pjmedia-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
+ <Test name="pjsip-test" info="" wdir="pjsip/bin" cmd="pjsip-test-i386-Win32-vc8-$(VSTARGET)" disabled=$(NOTEST) />
+ $(PJSUA-TESTS)
+ </Submit>
+
+</Scenario>
diff --git a/tests/automated/prepare.xml.template b/tests/automated/prepare.xml.template
new file mode 100644
index 0000000..cadfb34
--- /dev/null
+++ b/tests/automated/prepare.xml.template
@@ -0,0 +1,46 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)/tests/automated">
+
+ <Submit group="Experimental" build="Test-Preparation">
+ <Configure cmd="$(NOP)" />
+ <Build cmd="$(NOP)" />
+
+ <!-- GNU Makefile based scenario
+ Requirement:
+ - none
+ -->
+ <Test name="Configuring GNU scenario" cmd="python configure.py -t gnu -o gnu.xml gnu.xml.template" />
+
+ <!-- GNU Makefile with Intel IPP scenario.
+ Requirements:
+ - IPPROOT
+ - IPPSAMPLES
+ - IPPARCH (optional)
+
+ -->
+ <Test name="Configuring GNU IPP scenario" cmd="python configure.py -t gnu -o gnu-ipp.xml gnu-ipp.xml.template" />
+
+ <!-- iPhone target.
+ Requriement(s):
+ - valid SDK is installed
+
+ -->
+ <Test name="Configuring iPhone scenario" cmd="python configure.py -t gnu -o iphone.xml iphone.xml.template" />
+
+ <!-- MSVC target.
+ Requirements:
+ - Build from VS successfully
+ - VS paths are set
+
+ -->
+ <Test name="Configuring Visual Studio for Win32" cmd="python configure.py -t vs -vstarget Release -o msvc-win32.xml -nopjsuatest msvc.xml.template" />
+
+ <!-- Symbian target.
+ Requirement:
+ - EPOCROOT (modify below)
+ -->
+ <Test name="Configuring Symbian scenario" cmd='CMD /C SET EPOCROOT=\S60\devices\S60_5th_Edition_SDK_v1.0&amp;&amp; devices -setdefault @S60_5th_Edition_SDK_v1.0:com.nokia.s60&amp;&amp; python configure.py -t s60 -s60target &quot;gcce urel&quot; -o symbian.xml symbian.xml.template' />
+
+ </Submit>
+
+</Scenario>
diff --git a/tests/automated/run_continuous.py b/tests/automated/run_continuous.py
new file mode 100755
index 0000000..07e45ab
--- /dev/null
+++ b/tests/automated/run_continuous.py
@@ -0,0 +1,140 @@
+#!/usr/bin/python
+import os
+import sys
+import time
+import datetime
+import ccdash
+
+INTERVAL = 300
+DELAY = 0
+ONCE = False
+SUFFIX = ""
+FORCE = False
+
+def run_scenarios(scenarios, group):
+ # Run each scenario
+ rc = 0
+ for scenario in scenarios:
+ argv = []
+ argv.append("ccdash.py")
+ argv.append("scenario")
+ argv.append(scenario)
+ argv.append("--group")
+ argv.append(group)
+ thisrc = ccdash.main(argv)
+ if rc==0 and thisrc:
+ rc = thisrc
+ return rc
+
+
+def usage():
+ print """Periodically monitor working directory for Continuous and Nightly builds
+
+Usage:
+ run_continuous.py [options] scenario1.xml [scenario2.xml ...]
+
+options:
+ These are options which will be processed by run_continuous.py:
+
+ --delay MIN Delay both Continuous and Nightly builds by MIN minutes.
+ This is useful to coordinate the build with other build
+ machines. By default, Continuous build will be done right
+ after changes are detected, and Nightly build will be done
+ at 00:00 GMT. MIN is a float number.
+
+ --once Just run one loop to see if anything needs to be done and
+ if so just do it once. Quit after that.
+
+ --suffix SFX Set group suffix to SFX. For example, if SFX is "-2.x", then
+ tests will be submitted to "Nightly-2.x", "Continuous-2.x",
+ and "Experimental-2.x"
+
+ --force Force running the test even when nothing has changed.
+"""
+ sys.exit(1)
+
+if __name__ == "__main__":
+ if len(sys.argv)<=1 or sys.argv[1]=="-h" or sys.argv[1]=="--h" or sys.argv[1]=="--help" or sys.argv[1]=="/h":
+ usage()
+
+ # Splice list
+ scenarios = []
+ i = 1
+ while i < len(sys.argv):
+ if sys.argv[i]=="--delay":
+ i = i + 1
+ if i >= len(sys.argv):
+ print "Error: missing argument"
+ sys.exit(1)
+ DELAY = float(sys.argv[i]) * 60
+ print "Delay is set to %f minute(s)" % (DELAY / 60)
+ elif sys.argv[i]=="--suffix":
+ i = i + 1
+ if i >= len(sys.argv):
+ print "Error: missing argument"
+ sys.exit(1)
+ SUFFIX = sys.argv[i]
+ print "Suffix is set to %s" % (SUFFIX)
+ elif sys.argv[i]=="--once":
+ ONCE = True
+ elif sys.argv[i]=="--force":
+ FORCE = True
+ else:
+ # Check if scenario exists
+ scenario = sys.argv[i]
+ if not os.path.exists(scenario):
+ print "Error: file " + scenario + " does not exist"
+ sys.exit(1)
+ scenarios.append(scenario)
+ print "Scenario %s added" % (scenario)
+ i = i + 1
+
+ if len(scenarios) < 1:
+ print "Error: scenario is required"
+ sys.exit(1)
+
+ # Current date
+ utc = time.gmtime(None)
+ day = utc.tm_mday
+
+ # Loop foreva
+ while True:
+ argv = []
+
+ # Anything changed recently?
+ argv.append("ccdash.py")
+ argv.append("status")
+ argv.append("-w")
+ argv.append("../..")
+ rc = ccdash.main(argv)
+
+ utc = time.gmtime(None)
+
+ if utc.tm_mday != day or rc != 0 or FORCE:
+ group = ""
+ if utc.tm_mday != day:
+ day = utc.tm_mday
+ group = "Nightly" + SUFFIX
+ elif rc != 0:
+ group = "Continuous" + SUFFIX
+ else:
+ group = "Experimental" + SUFFIX
+ if DELAY > 0:
+ print "Will run %s after %f s.." % (group, DELAY)
+ time.sleep(DELAY)
+ rc = run_scenarios(scenarios, group)
+ msg = str(datetime.datetime.now()) + \
+ ": done running " + group + \
+ "tests, will check again in " + str(INTERVAL) + "s.."
+ if ONCE:
+ sys.exit(0)
+ else:
+ # Nothing changed
+ msg = str(datetime.datetime.now()) + \
+ ": No update, will check again in " + str(INTERVAL) + "s.."
+ if ONCE:
+ sys.exit(1)
+
+ print msg
+ time.sleep(INTERVAL)
+
diff --git a/tests/automated/run_scenario.py b/tests/automated/run_scenario.py
new file mode 100644
index 0000000..bfd06d1
--- /dev/null
+++ b/tests/automated/run_scenario.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+import sys
+import ccdash
+
+if __name__ == "__main__":
+ sys.argv[0] = "ccdash.py"
+ sys.argv.insert(1, "scenario")
+ rc = ccdash.main(sys.argv)
+ sys.exit(rc)
+
+
diff --git a/tests/automated/symbian-aps.xml.template b/tests/automated/symbian-aps.xml.template
new file mode 100644
index 0000000..1a7befc
--- /dev/null
+++ b/tests/automated/symbian-aps.xml.template
@@ -0,0 +1,78 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+ <!-- *********************************************************
+ ** This file contains scenario for APS and APS-Direct **
+ ********************************************************* -->
+
+ <!-- ******************************
+ ** APS **
+ ****************************** -->
+ <Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-APS" >
+ <Update />
+ <!-- Configure config_site.h -->
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJMEDIA_AUDIO_DEV_HAS_SYMB_APS 1
+#define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA 0
+#include <pj/config_site_sample.h>
+]]>
+ </FileWrite>
+ <!-- Configure symbian_ua.mmp -->
+ <FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 1
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 0
+]]>
+ </FileWrite>
+ <!-- Configure symbian_ua_gui.mmp -->
+ <FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 1
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 0
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c echo success" />
+ <Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
+ </Submit>
+
+
+ <!-- ******************************
+ ** APS-Direct **
+ ****************************** -->
+ <Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-APS-Direct" >
+ <Update />
+ <!-- Configure config_site.h -->
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_CONFIG_NOKIA_APS_DIRECT
+#include <pj/config_site_sample.h>
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c echo success" />
+ <Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
+
+ <!-- Restore symbian_ua.mmp -->
+ <FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 1
+]]>
+ </FileWrite>
+ <!-- Restore symbian_ua_gui.mmp -->
+ <FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 1
+]]>
+ </FileWrite>
+
+ </Submit>
+
+</Scenario>
+
diff --git a/tests/automated/symbian-vas.xml.template b/tests/automated/symbian-vas.xml.template
new file mode 100644
index 0000000..119d1e5
--- /dev/null
+++ b/tests/automated/symbian-vas.xml.template
@@ -0,0 +1,79 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+ <!-- *********************************************************
+ ** This file contains scenario for VAS and VAS-Direct **
+ ********************************************************* -->
+
+ <!-- ******************************
+ ** VAS **
+ ****************************** -->
+ <Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-VAS1" >
+ <Update />
+ <!-- Configure config_site.h -->
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJMEDIA_AUDIO_DEV_HAS_SYMB_VAS 1
+#define PJMEDIA_AUDIO_DEV_HAS_SYMB_APS 0
+#define PJMEDIA_AUDIO_DEV_HAS_SYMB_MDA 0
+#include <pj/config_site_sample.h>
+]]>
+ </FileWrite>
+ <!-- Configure symbian_ua.mmp -->
+ <FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 1
+#define SND_HAS_MDA 0
+]]>
+ </FileWrite>
+ <!-- Configure symbian_ua_gui.mmp -->
+ <FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 1
+#define SND_HAS_MDA 0
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c echo success" />
+ <Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
+ </Submit>
+
+
+ <!-- ******************************
+ ** VAS-Direct **
+ ****************************** -->
+ <Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-VAS1-Direct" >
+ <Update />
+ <!-- Configure config_site.h -->
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#define PJ_CONFIG_NOKIA_VAS_DIRECT
+#include <pj/config_site_sample.h>
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c echo success" />
+ <Build wdir="build.symbian" cmd='cmd /C &quot;bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
+
+ <!-- Restore symbian_ua.mmp -->
+ <FileWrite file="build.symbian/symbian_ua.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 1
+]]>
+ </FileWrite>
+ <!-- Restore symbian_ua_gui.mmp -->
+ <FileWrite file="pjsip-apps/src/symbian_ua_gui/group/symbian_ua_gui.mmp" replace_begin="// =BEGIN" replace_end="// =END">
+ <![CDATA[
+#define SND_HAS_APS 0
+#define SND_HAS_VAS 0
+#define SND_HAS_MDA 1
+]]>
+ </FileWrite>
+
+ </Submit>
+
+</Scenario>
+
diff --git a/tests/automated/symbian.xml.template b/tests/automated/symbian.xml.template
new file mode 100644
index 0000000..4f36dd9
--- /dev/null
+++ b/tests/automated/symbian.xml.template
@@ -0,0 +1,20 @@
+<?xml version="1.0" ?>
+<Scenario site="$(HOSTNAME)" url="http://my.cdash.org/submit.php?project=PJSIP" wdir="$(PJDIR)">
+ <!-- Symbian S60 default -->
+ <Submit group="Experimental" build="$(OS)-$(S60TARGETNAME)-default" >
+ <Update disabled="1" />
+ <FileWrite file="pjlib/include/pj/config_site.h">
+ <![CDATA[
+/* Written by ccdash */
+#include <pj/config_site_sample.h>
+#undef PJ_HAS_IPV6
+#define PJ_HAS_IPV6 1
+#undef PJMEDIA_HAS_G7221_CODEC
+#define PJMEDIA_HAS_G7221_CODEC 1
+]]>
+ </FileWrite>
+ <Configure cmd="cmd /c devices -setdefault $(S60DEVICE)" />
+ <Build wdir="build.symbian" cmd='cmd /C &quot;SET EPOCROOT=$(EPOCROOT)&amp;&amp; bldmake bldfiles &amp;&amp; abld reallyclean $(S60TARGET) &amp;&amp; abld build $(S60TARGET)&quot;' />
+ </Submit>
+</Scenario>
+
diff --git a/tests/automated/testvars.template b/tests/automated/testvars.template
new file mode 100644
index 0000000..e3f5cf0
--- /dev/null
+++ b/tests/automated/testvars.template
@@ -0,0 +1,33 @@
+Variables:
+-----------------------------
+DISABLED = "$(DISABLED)"
+GCC = "$(GCC)"
+HOSTNAME = "$(HOSTNAME)"
+OS = "$(OS)"
+PJDIR = "$(PJDIR)"
+SUFFIX = "$(SUFFIX)"
+NOTEST = "$(NOTEST)"
+
+S60 only:
+------------------------------
+S60TARGET = "$(S60TARGET)"
+S60TARGETNAME = "$(S60TARGETNAME)"
+S60DEVICE = "$(S60DEVICE)"
+EPOCROOT = "$(EPOCROOT)"
+
+VS only:
+------------------------------
+VS = "$(VS)"
+VSTARGET = "$(VSTARGET)"
+
+PJSUA-TESTS:
+------------------------------
+$(PJSUA-TESTS)
+------------------------------
+
+OTHER:
+------------------------------
+IPPROOT
+IPPSAMPLES
+IPPARCH
+NOP (cmdline to do nothing)
diff --git a/tests/cdash/README.TXT b/tests/cdash/README.TXT
new file mode 100644
index 0000000..69728b7
--- /dev/null
+++ b/tests/cdash/README.TXT
@@ -0,0 +1,59 @@
+
+ PJSIP CDASH AUTOMATED TESTS
+ --------------------------------
+
+
+1. What is this
+
+ This directory contains the scripts to run the automated, Python based tests
+of PJSIP source codes, across platforms, and submit the test results to a CDash
+test monitoring dashboard.
+
+ Stuffs that are included in the test scope:
+ - configure (for GNU platforms, e.g. Linux, msys, and MacOS X)
+ - build
+ - standard unit tests (pjlib-test, pjsip-test, etc.)
+ - pjsua's Python based blackbox tests
+
+
+2. Requirements
+
+ To run this test, you will need:
+ - Python (2.4 or later)
+ - curl (http://curl.haxx.se)
+ - a CDash server to receive test submissions (http://www.cdash.org)
+ - ccdash to submit the tests (http://trac.pjsip.org/ccdash)
+
+
+3. Configuration
+
+ Create a Python configuration file by copying from "cfg_site_sample.py".
+Save it as "cfg_site.py". You may create more than one configurations for your
+site and save them as different files.
+
+
+4. Running
+
+ To execute tests for GNU based targets:
+
+ $ python main.py cfg_gnu
+
+
+ To execute tests for MSVC based target:
+
+ $ python main.py cfg_msvc
+
+ To execute tests for Symbian target:
+
+ $ python main.py cfg_symbian
+
+
+ If you have a different site configuration file, you may specify it in the
+arguments, e.g.:
+
+ $ python main.py cfg_gnu my_site_config
+
+ For more information you can also pass "-h" or "--help", e.g.:
+
+ $ python main.py cfg_gnu --help
+
diff --git a/tests/cdash/builder.py b/tests/cdash/builder.py
new file mode 100644
index 0000000..79066e8
--- /dev/null
+++ b/tests/cdash/builder.py
@@ -0,0 +1,501 @@
+#
+# builder.py - PJSIP test scenarios builder
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+
+import ccdash
+import os
+import platform
+import re
+import subprocess
+import sys
+import time
+
+class Operation:
+ """\
+ The Operation class describes the individual ccdash operation to be
+ performed.
+
+ """
+ # Types:
+ UPDATE = "update" # Update operation
+ CONFIGURE = "configure" # Configure operation
+ BUILD = "build" # Build operation
+ TEST = "test" # Unit test operation
+
+ def __init__(self, type, cmdline, name="", wdir=""):
+ self.type = type
+ self.cmdline = cmdline
+ self.name = name
+ self.wdir = wdir
+ if self.type==self.TEST and not self.name:
+ raise "name required for tests"
+
+ def encode(self, base_dir):
+ s = [self.type]
+ if self.type == self.TEST:
+ s.append(self.name)
+ if self.type != self.UPDATE:
+ s.append(self.cmdline)
+ s.append("-w")
+ if self.wdir:
+ s.append(base_dir + "/" + self.wdir)
+ else:
+ s.append(base_dir)
+ return s
+
+
+#
+# Update operation
+#
+update_ops = [Operation(Operation.UPDATE, "")]
+
+#
+# The standard library tests (e.g. pjlib-test, pjsip-test, etc.)
+#
+std_test_ops= [
+ Operation(Operation.TEST, "./pjlib-test$SUFFIX", name="pjlib test",
+ wdir="pjlib/bin"),
+ Operation(Operation.TEST, "./pjlib-util-test$SUFFIX",
+ name="pjlib-util test", wdir="pjlib-util/bin"),
+ Operation(Operation.TEST, "./pjnath-test$SUFFIX", name="pjnath test",
+ wdir="pjnath/bin"),
+ Operation(Operation.TEST, "./pjmedia-test$SUFFIX", name="pjmedia test",
+ wdir="pjmedia/bin"),
+ Operation(Operation.TEST, "./pjsip-test$SUFFIX", name="pjsip test",
+ wdir="pjsip/bin")
+]
+
+#
+# These are pjsua Python based unit test operations
+#
+def build_pjsua_test_ops(pjsua_exe=""):
+ ops = []
+ if pjsua_exe:
+ exe = " -e ../../pjsip-apps/bin/" + pjsua_exe
+ else:
+ exe = ""
+ cwd = os.getcwd()
+ os.chdir("../pjsua")
+ os.system("python runall.py --list > list")
+ f = open("list", "r")
+ for e in f:
+ e = e.rstrip("\r\n ")
+ (mod,param) = e.split(None,2)
+ name = mod[4:mod.find(".py")] + "_" + \
+ param[param.find("/")+1:param.find(".py")]
+ ops.append(Operation(Operation.TEST, "python run.py" + exe + " " + \
+ e, name=name, wdir="tests/pjsua"))
+ f.close()
+ os.remove("list")
+ os.chdir(cwd)
+ return ops
+
+#
+# Get gcc version
+#
+def gcc_version(gcc):
+ proc = subprocess.Popen(gcc + " -v", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, shell=True)
+ ver = ""
+ while True:
+ s = proc.stdout.readline()
+ if not s:
+ break
+ if s.find("gcc version") >= 0:
+ ver = s.split(None, 3)[2]
+ break
+ proc.wait()
+ return "gcc-" + ver
+
+#
+# Get Visual Studio version
+#
+def vs_get_version():
+ proc = subprocess.Popen("cl", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT)
+ while True:
+ s = proc.stdout.readline()
+ if s=="":
+ break
+ pos = s.find("Version")
+ if pos > 0:
+ proc.wait()
+ s = s[pos+8:]
+ ver = s.split(None, 1)[0]
+ major = ver[0:2]
+ if major=="12":
+ return "vs6"
+ elif major=="13":
+ return "vs2003"
+ elif major=="14":
+ return "vs2005"
+ elif major=="15":
+ return "vs2008"
+ else:
+ return "vs-" + major
+ proc.wait()
+ return "vs-unknown"
+
+
+#
+# Test config
+#
+class BaseConfig:
+ def __init__(self, base_dir, url, site, group, options=None):
+ self.base_dir = base_dir
+ self.url = url
+ self.site = site
+ self.group = group
+ self.options = options
+
+#
+# Base class for test configurator
+#
+class TestBuilder:
+ def __init__(self, config, build_config_name="",
+ user_mak="", config_site="", exclude=[], not_exclude=[]):
+ self.config = config # BaseConfig instance
+ self.build_config_name = build_config_name # Optional build suffix
+ self.user_mak = user_mak # To be put in user.mak
+ self.config_site = config_site # To be put in config_s..
+ self.saved_user_mak = "" # To restore user.mak
+ self.saved_config_site = "" # To restore config_s..
+ self.exclude = exclude # List of exclude pattern
+ self.not_exclude = not_exclude # List of include pattern
+ self.ccdash_args = [] # ccdash cmd line
+
+ def stamp(self):
+ return time.strftime("%Y%m%d-%H%M", time.localtime())
+
+ def pre_action(self):
+ # Override user.mak
+ name = self.config.base_dir + "/user.mak"
+ if os.access(name, os.F_OK):
+ f = open(name, "r")
+ self.saved_user_mak = f.read()
+ f.close()
+ if True:
+ f = open(name, "w")
+ f.write(self.user_mak)
+ f.close()
+ # Override config_site.h
+ name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
+ if os.access(name, os.F_OK):
+ f = open(name, "r")
+ self.saved_config_site= f.read()
+ f.close()
+ if True:
+ f = open(name, "wt")
+ f.write(self.config_site)
+ f.close()
+
+
+ def post_action(self):
+ # Restore user.mak
+ name = self.config.base_dir + "/user.mak"
+ f = open(name, "wt")
+ f.write(self.saved_user_mak)
+ f.close()
+ # Restore config_site.h
+ name = self.config.base_dir + "/pjlib/include/pj/config_site.h"
+ f = open(name, "wt")
+ f.write(self.saved_config_site)
+ f.close()
+
+ def build_tests(self):
+ # This should be overridden by subclasses
+ pass
+
+ def execute(self):
+ if len(self.ccdash_args)==0:
+ self.build_tests()
+ self.pre_action()
+ mandatory_op = ["update", "configure", "build"]
+ counter = 0
+ for a in self.ccdash_args:
+ # Check if this test is in exclusion list
+ fullcmd = " ".join(a)
+ excluded = False
+ included = False
+ for pat in self.exclude:
+ if pat and re.search(pat, fullcmd) != None:
+ excluded = True
+ break
+ if excluded:
+ for pat in self.not_exclude:
+ if pat and re.search(pat, fullcmd) != None:
+ included = True
+ break
+ if excluded and not included:
+ if len(fullcmd)>60:
+ fullcmd = fullcmd[0:60] + ".."
+ print "Skipping '%s'" % (fullcmd)
+ continue
+
+ b = ["ccdash.py"]
+ b.extend(a)
+ a = b
+ #print a
+ try:
+ rc = ccdash.main(a)
+ except Exception, e:
+ errmsg = str(e)
+ print "**** Error: ccdash got exception %s ****" % errmsg
+ rc = -1
+ except:
+ print "**** Error: ccdash got unknown exception ****"
+ rc = -1
+
+ if rc!=0 and a[1] in mandatory_op:
+ print "Stopping because of error.."
+ break
+ counter = counter + 1
+ self.post_action()
+
+
+#
+# GNU test configurator
+#
+class GNUTestBuilder(TestBuilder):
+ """\
+ This class creates list of tests suitable for GNU targets.
+
+ """
+ def __init__(self, config, build_config_name="", user_mak="", \
+ config_site="", cross_compile="", exclude=[], not_exclude=[]):
+ """\
+ Parameters:
+ config - BaseConfig instance
+ build_config_name - Optional name to be added as suffix to the build
+ name. Sample: "min-size", "O4", "TLS", etc.
+ user_mak - Contents to be put on user.mak
+ config_site - Contents to be put on config_site.h
+ cross_compile - Optional cross-compile prefix. Must include the
+ trailing dash, e.g. "arm-unknown-linux-"
+ exclude - List of regular expression patterns for tests
+ that will be excluded from the run
+ not_exclude - List of regular expression patterns for tests
+ that will be run regardless of whether they
+ match the excluded pattern.
+
+ """
+ TestBuilder.__init__(self, config, build_config_name=build_config_name,
+ user_mak=user_mak, config_site=config_site,
+ exclude=exclude, not_exclude=not_exclude)
+ self.cross_compile = cross_compile
+ if self.cross_compile and self.cross_compile[-1] != '-':
+ self.cross_compile.append("-")
+
+ def build_tests(self):
+ if self.cross_compile:
+ suffix = "-" + self.cross_compile[0:-1]
+ build_name = self.cross_compile + \
+ gcc_version(self.cross_compile + "gcc")
+ else:
+ proc = subprocess.Popen("sh "+self.config.base_dir+"/config.guess",
+ shell=True, stdout=subprocess.PIPE)
+ plat = proc.stdout.readline().rstrip(" \r\n")
+ build_name = plat + "-"+gcc_version(self.cross_compile + "gcc")
+ suffix = "-" + plat
+
+ if self.build_config_name:
+ build_name = build_name + "-" + self.build_config_name
+ cmds = []
+ cmds.extend(update_ops)
+ cmds.append(Operation(Operation.CONFIGURE, "sh ./configure"))
+ if sys.platform=="win32":
+ # Don't build python module on Mingw
+ cmds.append(Operation(Operation.BUILD,
+ "sh -c 'make distclean && make dep && make'"))
+ else:
+ cmds.append(Operation(Operation.BUILD,
+ "sh -c 'make distclean && make dep && make" + \
+ " && cd pjsip-apps/src/python && " + \
+ "python setup.py clean build'"))
+
+ cmds.extend(std_test_ops)
+ cmds.extend(build_pjsua_test_ops())
+ self.ccdash_args = []
+ for c in cmds:
+ c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
+ args = c.encode(self.config.base_dir)
+ args.extend(["-U", self.config.url,
+ "-S", self.config.site,
+ "-T", self.stamp(),
+ "-B", build_name,
+ "-G", self.config.group])
+ args.extend(self.config.options)
+ self.ccdash_args.append(args)
+
+#
+# MSVC test configurator
+#
+class MSVCTestBuilder(TestBuilder):
+ """\
+ This class creates list of tests suitable for Visual Studio builds.
+ You need to set the MSVC environment variables (typically by calling
+ vcvars32.bat) prior to running this class.
+
+ """
+ def __init__(self, config, target="Release|Win32", build_config_name="",
+ config_site="", exclude=[], not_exclude=[]):
+ """\
+ Parameters:
+ config - BaseConfig instance
+ target - Visual Studio build configuration to build.
+ Sample: "Debug|Win32", "Release|Win32".
+ build_config_name - Optional name to be added as suffix to the build
+ name. Sample: "Debug", "Release", "IPv6", etc.
+ config_site - Contents to be put on config_site.h
+ exclude - List of regular expression patterns for tests
+ that will be excluded from the run
+ not_exclude - List of regular expression patterns for tests
+ that will be run regardless of whether they
+ match the excluded pattern.
+
+ """
+ TestBuilder.__init__(self, config, build_config_name=build_config_name,
+ config_site=config_site, exclude=exclude,
+ not_exclude=not_exclude)
+ self.target = target.lower()
+
+ def build_tests(self):
+
+ (vsbuild,sys) = self.target.split("|",2)
+
+ build_name = sys + "-" + vs_get_version() + "-" + vsbuild
+
+ if self.build_config_name:
+ build_name = build_name + "-" + self.build_config_name
+
+ vccmd = "vcbuild.exe /nologo /nohtmllog /nocolor /rebuild " + \
+ "pjproject-vs8.sln " + " \"" + self.target + "\""
+
+ suffix = "-i386-win32-vc8-" + vsbuild
+ pjsua = "pjsua_vc8"
+ if vsbuild=="debug":
+ pjsua = pjsua + "d"
+
+ cmds = []
+ cmds.extend(update_ops)
+ cmds.append(Operation(Operation.CONFIGURE, "CMD /C echo Nothing to do"))
+ cmds.append(Operation(Operation.BUILD, vccmd))
+ cmds.extend(std_test_ops)
+ cmds.extend(build_pjsua_test_ops(pjsua))
+
+ self.ccdash_args = []
+ for c in cmds:
+ c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
+ args = c.encode(self.config.base_dir)
+ args.extend(["-U", self.config.url,
+ "-S", self.config.site,
+ "-T", self.stamp(),
+ "-B", build_name,
+ "-G", self.config.group])
+ args.extend(self.config.options)
+ self.ccdash_args.append(args)
+
+
+#
+# Symbian test configurator
+#
+class SymbianTestBuilder(TestBuilder):
+ """\
+ This class creates list of tests suitable for Symbian builds. You need to
+ set the command line build settings prior to running this class (typically
+ that involves setting the EPOCROOT variable and current device).
+
+ """
+ def __init__(self, config, target="gcce urel", build_config_name="",
+ config_site="", exclude=[], not_exclude=[]):
+ """\
+ Parameters:
+ config - BaseConfig instance
+ target - Symbian target to build. Default is "gcce urel".
+ build_config_name - Optional name to be added as suffix to the build
+ name. Sample: "APS", "VAS", etc.
+ config_site - Contents to be put on config_site.h
+ exclude - List of regular expression patterns for tests
+ that will be excluded from the run
+ not_exclude - List of regular expression patterns for tests
+ that will be run regardless of whether they
+ match the excluded pattern.
+
+ """
+ TestBuilder.__init__(self, config, build_config_name=build_config_name,
+ config_site=config_site, exclude=exclude,
+ not_exclude=not_exclude)
+ self.target = target.lower()
+
+ def build_tests(self):
+
+ # Check that EPOCROOT is set
+ if not "EPOCROOT" in os.environ:
+ print "Error: EPOCROOT environment variable is not set"
+ sys.exit(1)
+ epocroot = os.environ["EPOCROOT"]
+ # EPOCROOT must have trailing backslash
+ if epocroot[-1] != "\\":
+ epocroot = epocroot + "\\"
+ os.environ["EPOCROOT"] = epocroot
+ sdk1 = epocroot.split("\\")[-2]
+
+ # Check that correct device is set
+ proc = subprocess.Popen("devices", stdout=subprocess.PIPE,
+ stderr=subprocess.STDOUT, shell=True)
+ sdk2 = ""
+ while True:
+ line = proc.stdout.readline()
+ if line.find("- default") > 0:
+ sdk2 = line.split(":",1)[0]
+ break
+ proc.wait()
+
+ if sdk1 != sdk2:
+ print "Error: default SDK in device doesn't match EPOCROOT"
+ print "Default device SDK =", sdk2
+ print "EPOCROOT SDK =", sdk1
+ sys.exit(1)
+
+ build_name = sdk2.replace("_", "-") + "-" + \
+ self.target.replace(" ", "-")
+
+ if self.build_config_name:
+ build_name = build_name + "-" + self.build_config_name
+
+ cmdline = "cmd /C \"cd build.symbian && bldmake bldfiles && abld build %s\"" % (self.target)
+
+ cmds = []
+ cmds.extend(update_ops)
+ cmds.append(Operation(Operation.CONFIGURE, "CMD /C echo Nothing to do"))
+ cmds.extend([Operation(Operation.BUILD, cmdline)])
+
+ self.ccdash_args = []
+ suffix = ""
+ for c in cmds:
+ c.cmdline = c.cmdline.replace("$SUFFIX", suffix)
+ args = c.encode(self.config.base_dir)
+ args.extend(["-U", self.config.url,
+ "-S", self.config.site,
+ "-T", self.stamp(),
+ "-B", build_name,
+ "-G", self.config.group])
+ args.extend(self.config.options)
+ self.ccdash_args.append(args)
+
diff --git a/tests/cdash/cfg_gnu.py b/tests/cdash/cfg_gnu.py
new file mode 100644
index 0000000..8411b65
--- /dev/null
+++ b/tests/cdash/cfg_gnu.py
@@ -0,0 +1,73 @@
+#
+# cfg_gnu.py - GNU target configurator
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+import builder
+import os
+import sys
+
+# Each configurator must export this function
+def create_builder(args):
+ usage = """\
+Usage:
+ main.py cfg_gnu [-h|--help] [cfg_site]
+
+Arguments:
+ cfg_site: site configuration module. If not specified, "cfg_site"
+ is implied
+ -h, --help Show this help screen
+
+"""
+ # (optional) args format:
+ # site configuration module. If not specified, "cfg_site" is implied
+
+ cfg_site = "cfg_site"
+
+ for arg in args:
+ if arg=="-h" or arg=="--help":
+ print usage
+ sys.exit(0)
+ elif arg[0]=="-":
+ print usage
+ sys.exit(1)
+ else:
+ cfg_site = arg
+
+ if os.access(cfg_site+".py", os.F_OK) == False:
+ print "Error: file '%s.py' doesn't exist." % (cfg_site)
+ sys.exit(1)
+
+ cfg_site = __import__(cfg_site)
+ test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
+ cfg_site.URL, \
+ cfg_site.SITE_NAME, \
+ cfg_site.GROUP, \
+ cfg_site.OPTIONS)
+
+ config_site = "#define PJ_TODO(x)\n" + cfg_site.CONFIG_SITE
+ user_mak = "export CFLAGS+=-Wall\n" + cfg_site.USER_MAK
+
+ builders = [
+ builder.GNUTestBuilder(test_cfg, build_config_name="default",
+ user_mak=user_mak,
+ config_site=config_site,
+ exclude=cfg_site.EXCLUDE,
+ not_exclude=cfg_site.NOT_EXCLUDE)
+ ]
+
+ return builders
diff --git a/tests/cdash/cfg_msvc.py b/tests/cdash/cfg_msvc.py
new file mode 100644
index 0000000..26b0785
--- /dev/null
+++ b/tests/cdash/cfg_msvc.py
@@ -0,0 +1,82 @@
+#
+# cfg_msvc.py - MSVC/Visual Studio target configurator
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+import builder
+import os
+import sys
+
+# Each configurator must export this function
+def create_builder(args):
+ usage = """\
+Usage:
+ main.py cfg_msvc [-h|--help] [-t|--target TARGET] [cfg_site]
+
+Arguments:
+ cfg_site: site configuration module. If not specified, "cfg_site"
+ is implied
+ -t,--target TARGET: Visual Studio build configuration to build. Default is
+ "Release|Win32". Sample values: "Debug|Win32"
+ -h, --help Show this help screen
+
+"""
+
+ cfg_site = "cfg_site"
+ target = "Release|Win32"
+ in_option = ""
+
+ for arg in args:
+ if in_option=="-t":
+ target = arg
+ in_option = ""
+ elif arg=="--target" or arg=="-t":
+ in_option = "-t"
+ elif arg=="-h" or arg=="--help":
+ print usage
+ sys.exit(0)
+ elif arg[0]=="-":
+ print usage
+ sys.exit(1)
+ else:
+ cfg_site = arg
+
+ if os.access(cfg_site+".py", os.F_OK) == False:
+ print "Error: file '%s.py' doesn't exist." % (cfg_site)
+ sys.exit(1)
+
+ cfg_site = __import__(cfg_site)
+ test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
+ cfg_site.URL, \
+ cfg_site.SITE_NAME, \
+ cfg_site.GROUP, \
+ cfg_site.OPTIONS)
+
+ config_site = "#define PJ_TODO(x)\n" + cfg_site.CONFIG_SITE
+ user_mak = cfg_site.USER_MAK
+
+ builders = [
+ builder.MSVCTestBuilder(test_cfg,
+ target=target,
+ build_config_name="default",
+ config_site=config_site,
+ exclude=cfg_site.EXCLUDE,
+ not_exclude=cfg_site.NOT_EXCLUDE)
+ ]
+
+ return builders
+
diff --git a/tests/cdash/cfg_site_sample.py b/tests/cdash/cfg_site_sample.py
new file mode 100644
index 0000000..b059642
--- /dev/null
+++ b/tests/cdash/cfg_site_sample.py
@@ -0,0 +1,50 @@
+#
+# cfg_site_sample.py - Sample site configuration
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+import builder
+
+# Your site name
+SITE_NAME="Newham3"
+
+# The URL where tests will be submitted to
+URL = "http://192.168.0.2/dash/submit.php?project=PJSIP"
+
+# Test group
+GROUP = "Experimental"
+
+# PJSIP base directory
+BASE_DIR = "/root/project/pjproject"
+
+# List of additional ccdash options
+#OPTIONS = ["-o", "out.xml", "-y"]
+OPTIONS = []
+
+# What's the content of config_site.h
+CONFIG_SITE = ""
+
+# What's the content of user.mak
+USER_MAK = ""
+
+# List of regular expression of test patterns to be excluded
+EXCLUDE = []
+
+# List of regular expression of test patterns to be included (even
+# if they match EXCLUDE patterns)
+NOT_EXCLUDE = []
+#"configure", "update", "build.*make", "build", "run.py mod_run.*100_simple"]
diff --git a/tests/cdash/cfg_symbian.py b/tests/cdash/cfg_symbian.py
new file mode 100644
index 0000000..94f5f3f
--- /dev/null
+++ b/tests/cdash/cfg_symbian.py
@@ -0,0 +1,86 @@
+#
+# cfg_symbian.py - Symbian target configurator
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+import builder
+import os
+import sys
+
+# Each configurator must export this function
+def create_builder(args):
+ usage = """\
+Usage:
+ main.py cfg_symbian [-h|--help] [-t|--target TARGET] [cfg_site]
+
+Arguments:
+ cfg_site: site configuration module. If not specified, "cfg_site"
+ is implied
+ -t,--target TARGET: Symbian target to build. Default is "gcce urel".
+ Other values:
+ "winscw udeb", "gcce udeb", etc.
+ -h, --help Show this help screen
+"""
+
+ cfg_site = "cfg_site"
+ target = "gcce urel"
+ in_option = ""
+
+ for arg in args:
+ if in_option=="-t":
+ target = arg
+ in_option = ""
+ elif arg=="--target" or arg=="-t":
+ in_option = "-t"
+ elif arg=="--help" or arg=="-h":
+ print usage
+ sys.exit(0)
+ elif arg[0]=="-":
+ print usage
+ sys.exit(1)
+ else:
+ cfg_site = arg
+
+ if os.access(cfg_site+".py", os.F_OK) == False:
+ print "Error: file '%s.py' doesn't exist." % (cfg_site)
+ sys.exit(1)
+
+ cfg_site = __import__(cfg_site)
+ test_cfg = builder.BaseConfig(cfg_site.BASE_DIR, \
+ cfg_site.URL, \
+ cfg_site.SITE_NAME, \
+ cfg_site.GROUP, \
+ cfg_site.OPTIONS)
+ config_site1 = """\
+#define PJ_TODO(x)
+#include <pj/config_site_sample.h>
+
+"""
+
+ config_Site = config_site1 + cfg_site.CONFIG_SITE
+
+ builders = [
+ builder.SymbianTestBuilder(test_cfg,
+ target=target,
+ build_config_name="default",
+ config_site=config_site1,
+ exclude=cfg_site.EXCLUDE,
+ not_exclude=cfg_site.NOT_EXCLUDE)
+ ]
+
+ return builders
+
diff --git a/tests/cdash/inc_test.py b/tests/cdash/inc_test.py
new file mode 100644
index 0000000..8b13789
--- /dev/null
+++ b/tests/cdash/inc_test.py
@@ -0,0 +1 @@
+
diff --git a/tests/cdash/main.py b/tests/cdash/main.py
new file mode 100644
index 0000000..8a99371
--- /dev/null
+++ b/tests/cdash/main.py
@@ -0,0 +1,42 @@
+#!/bin/env python
+
+#
+# main.py - main entry for PJSIP's CDash tests
+#
+# Copyright (C) 2008-2009 Teluu Inc. (http://www.teluu.com)
+#
+# 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
+#
+
+import sys
+
+if len(sys.argv)==1:
+ print "Usage: main.py cfg_file [cfg_site]"
+ print "Example:"
+ print " main.py cfg_gnu"
+ print " main.py cfg_gnu custom_cfg_site"
+ sys.exit(1)
+
+
+args = []
+args.extend(sys.argv)
+args.remove(args[1])
+args.remove(args[0])
+
+cfg_file = __import__(sys.argv[1])
+builders = cfg_file.create_builder(args)
+
+for builder in builders:
+ builder.execute()
diff --git a/tests/cdash/starttest_sample.bat b/tests/cdash/starttest_sample.bat
new file mode 100644
index 0000000..752e38d
--- /dev/null
+++ b/tests/cdash/starttest_sample.bat
@@ -0,0 +1,44 @@
+@echo off
+
+rem ***
+rem ************** VS 2005 **************
+rem ***
+set OLD_PATH=%PATH%
+set OLD_INCLUDE=%INCLUDE%
+set OLD_LIB=%LIB%
+set OLD_LIBPATH=%LIBPATH%
+
+call "C:\Program Files\Microsoft Visual Studio 8\VC\bin\vcvars32.bat" x86
+python main.py cfg_msvc -t "Debug|Win32"
+python main.py cfg_msvc -t "Release|Win32"
+
+set PATH=%OLD_PATH%
+set INCLUDE=%OLD_INCLUDE%
+set LIB=%OLD_LIB%
+set LIBPATH=%OLD_LIBPATH%
+
+
+rem ***
+rem ************** S60 3rd FP1 **************
+rem ***
+set EPOCROOT=\symbian\9.2\S60_3rd_FP1\
+devices -setdefault @S60_3rd_FP1:com.nokia.s60
+python main.py cfg_symbian -t "winscw udeb"
+python main.py cfg_symbian -t "gcce udeb"
+python main.py cfg_symbian -t "gcce urel"
+
+
+rem ***
+rem ************** Mingw **************
+rem ***
+set MSYSTEM=MINGW32
+set DISPLAY=
+C:\msys\1.0\bin\sh -c "python main.py cfg_gnu"
+
+
+rem ***
+rem ************** Linux **************
+rem ***
+set PATH=%PATH%;c:\msys\1.0\bin
+set HOME=C:\msys\1.0\home\Administrator
+C:\mingw\bin\ssh test@192.168.0.12 "cd project/pjproject/tests/cdash && python main.py cfg_gnu"
diff --git a/tests/pjsua/README.TXT b/tests/pjsua/README.TXT
new file mode 100644
index 0000000..0475bac
--- /dev/null
+++ b/tests/pjsua/README.TXT
@@ -0,0 +1,65 @@
+
+ PJSUA TEST FRAMEWORK
+ =========================
+
+0. What is this
+---------------
+This is the automated testing scripts for pjsua. It can do many things (just
+don't ask it to write good documentation :) ).
+
+
+1. Requirements
+---------------
+To run the tests you need:
+ - Python (tested with Python 2.5.2)
+ - pjsua application, built and placed in pjsip-apps/bin directory
+ - the pjsua must be built with:
+ - SRTP enabled (the default)
+
+
+2. Using
+--------
+To run all the tests:
+ $ python [OPTIONS] runall.py
+
+To run individual test:
+ $ python [OPTIONS] run.py MODULE CONFIG
+
+Where options:
+ -e EXE use EXE as pjsua executable
+ -n use null audio
+ -r TEST (for runall.py only) resume test at TEST
+
+
+For each individual tests, the run.py is the main entry for the test. It
+imports the various inc_xxx.py files, and it will load the MODULE. The MODULE
+contains specific test flows, and we have few of them:
+
+ - mod_run.py:
+ a simple test which just run pjsua with the configuration from CONFIG
+ file and checks if pjsua can start properly.
+
+ - mod_call.py:
+ call testing where it spawns two pjsua instances each with configura-
+ tions as specified in CONFIG file, makes one pjsua call the other, and
+ checks if the call can be established.
+
+ - mod_pres.py:
+ presence testing
+
+ - mod_sendto.py:
+ Simple UAC to send arbitrary SIP message to pjsua. Good to test
+ various incoming INVITE scenarios
+
+ - mod_media_playrec.py:
+ Mainly for resampling quality testing
+
+ - mod_pesq.py
+ Measure call quality of various call settings with PESQ, for people
+ who have PESQ tool and license
+
+Example:
+ $ python run.py mod_run.py scripts-run/100_simple.py
+ $ python run.py mod_call.py scripts-call/100_simple.py
+
+
diff --git a/tests/pjsua/config_site.py b/tests/pjsua/config_site.py
new file mode 100644
index 0000000..a626e56
--- /dev/null
+++ b/tests/pjsua/config_site.py
@@ -0,0 +1,4 @@
+# $Id: config_site.py 2237 2008-08-26 12:13:25Z bennylp $
+
+# Specify if host has sound device, or test should be performed using sound device
+HAS_SND_DEV = 0
diff --git a/tests/pjsua/inc_cfg.py b/tests/pjsua/inc_cfg.py
new file mode 100644
index 0000000..3661b64
--- /dev/null
+++ b/tests/pjsua/inc_cfg.py
@@ -0,0 +1,107 @@
+# $Id: inc_cfg.py 2237 2008-08-26 12:13:25Z bennylp $
+import random
+import config_site
+
+DEFAULT_ECHO = True
+DEFAULT_TRACE = True
+DEFAULT_START_SIP_PORT = 50000
+
+# Shared vars
+ARGS = [] # arguments containing script module & config
+HAS_SND_DEV = config_site.HAS_SND_DEV
+
+# Individual pjsua instance configuration class
+class InstanceParam:
+ # Name to identify this pjsua instance (e.g. "caller", "callee", etc.)
+ name = ""
+ # pjsua command line arguments, concatenated in string
+ arg = ""
+ # Specify whether pjsua output should be echoed to stdout
+ echo_enabled = DEFAULT_ECHO
+ # Enable/disable test tracing
+ trace_enabled = DEFAULT_TRACE
+ # SIP URI to send request to this instance
+ uri = ""
+ # SIP port number, zero to automatically assign
+ sip_port = 0
+ # Does this have registration? If yes then the test function will
+ # wait until the UA is registered before doing anything else
+ have_reg = False
+ # Does this have PUBLISH?
+ have_publish = False
+ # Enable stdout buffer?
+ enable_buffer = False
+ def __init__( self,
+ name, # Instance name
+ arg, # Cmd-line arguments
+ uri="", # URI
+ uri_param="", # Additional URI param
+ sip_port=0, # SIP port
+ have_reg=False, # Have registration?
+ have_publish=False, # Have publish?
+ echo_enabled=DEFAULT_ECHO,
+ trace_enabled=DEFAULT_TRACE,
+ enable_buffer = False):
+ # Instance name
+ self.name = name
+ # Give random sip_port if it's not specified
+ if sip_port==0:
+ self.sip_port = random.randint(DEFAULT_START_SIP_PORT, 65534)
+ else:
+ self.sip_port = sip_port
+ # Autogenerate URI if it's empty.
+ self.uri = uri
+ if self.uri=="":
+ self.uri = "sip:pjsip@127.0.0.1:" + str(self.sip_port)
+ # Add uri_param to the URI
+ self.uri = self.uri + uri_param
+ # Add bracket to the URI
+ if self.uri[0] != "<":
+ self.uri = "<" + self.uri + ">"
+ # Add SIP local port to the argument
+ self.arg = arg + " --local-port=" + str(self.sip_port)
+ self.have_reg = have_reg
+ self.have_publish = have_publish
+ if have_publish and have_reg and not ("--publish" in self.arg):
+ self.arg = self.arg + " --publish"
+ self.echo_enabled = echo_enabled
+ self.trace_enabled = trace_enabled
+ self.enable_buffer = enable_buffer
+
+
+############################################
+# Test parameter class
+class TestParam:
+ title = ""
+ # params is list containing InstanceParams objects
+ inst_params = []
+ # flag if this tes should be skipped
+ skip = None
+ # list of Expect instances, to be filled at run-time by
+ # the test program
+ process = []
+ # the function for test body
+ test_func = None
+ post_func = None
+ def __init__( self,
+ title, # Test title
+ inst_params, # InstanceParam's as list
+ func=None,
+ skip=False,
+ post_func=None,
+ need_stdout_buffer=False):
+ self.title = title
+ self.inst_params = inst_params
+ self.skip = skip
+ self.test_func = func
+ self.post_func = post_func
+
+
+###################################
+# TestError exception
+class TestError:
+ desc = ""
+ def __init__(self, desc):
+ self.desc = desc
+
+
diff --git a/tests/pjsua/inc_const.py b/tests/pjsua/inc_const.py
new file mode 100644
index 0000000..9edcfef
--- /dev/null
+++ b/tests/pjsua/inc_const.py
@@ -0,0 +1,64 @@
+# $Id: inc_const.py 4177 2012-06-26 02:28:59Z nanang $
+# Useful constants
+
+
+##########################
+# MENU OUTPUT
+#
+
+
+##########################
+# EVENTS
+#
+
+# Text to expect when there is incoming call
+EVENT_INCOMING_CALL = "Press .* answer"
+
+
+##########################
+# CALL STATES
+#
+
+# Call state is CALLING
+STATE_CALLING = "state.*CALLING"
+# Call state is EARLY
+STATE_EARLY = "state.*EARLY"
+# Call state is CONFIRMED
+STATE_CONFIRMED = "state.*CONFIRMED"
+# Call state is DISCONNECTED
+STATE_DISCONNECTED = "Call .* DISCONNECTED"
+
+# Media call is put on-hold
+MEDIA_HOLD = "Call [0-9]+ media [0-9]+ .*, status is .* hold"
+# Media call is active
+MEDIA_ACTIVE = "Call [0-9]+ media [0-9]+ .*, status is Active"
+#MEDIA_ACTIVE = "Media for call [0-9]+ is active"
+# RX_DTMF
+RX_DTMF = "Incoming DTMF on call [0-9]+: "
+
+##########################
+# MEDIA
+#
+
+# Connecting/disconnecting ports
+MEDIA_CONN_PORT_SUCCESS = "Port \d+ \(.+\) transmitting to port"
+MEDIA_DISCONN_PORT_SUCCESS = "Port \d+ \(.+\) stop transmitting to port"
+
+# Filename to play / record
+MEDIA_PLAY_FILE = "--play-file\s+(\S+)"
+MEDIA_REC_FILE = "--rec-file\s+(\S+)"
+
+##########################
+# MISC
+#
+
+# The command prompt
+PROMPT = ">>>"
+# When pjsua has been destroyed
+DESTROYED = "PJSUA destroyed"
+# Assertion failure
+ASSERT = "Assertion failed"
+# Stdout refresh text
+STDOUT_REFRESH = "XXSTDOUT_REFRESHXX"
+
+
diff --git a/tests/pjsua/inc_sdp.py b/tests/pjsua/inc_sdp.py
new file mode 100644
index 0000000..f9f26f5
--- /dev/null
+++ b/tests/pjsua/inc_sdp.py
@@ -0,0 +1,38 @@
+# $Id: inc_sdp.py 2392 2008-12-22 18:54:58Z bennylp $
+
+# SDP template
+sdp_templ = \
+"""v=0\r
+o=- 1 1 $NET_TYPE $ADDR_TYPE $LOCAL_IP\r
+s=pjmedia\r
+t=0 0\r
+$SDP_LINES"""
+
+sdp_media_templ = \
+"""m=$MEDIA_TYPE $PORT $TRANSPORT 0\r
+c=$NET_TYPE $ADDR_TYPE $LOCAL_IP\r
+$SDP_LINES"""
+
+# Create SDP session
+def session(local_ip="127.0.0.1", extra_lines="", net_type="IN", addr_type="IP4"):
+ sdp = sdp_templ
+ sdp = sdp.replace("$NET_TYPE", net_type)
+ sdp = sdp.replace("$ADDR_TYPE", addr_type)
+ sdp = sdp.replace("$LOCAL_IP", local_ip)
+ sdp = sdp.replace("$SDP_LINES", extra_lines)
+ return sdp
+
+# Create basic SDP media
+def media(media_type="audio", local_port=4000, local_ip="127.0.0.1", extra_lines="",
+ net_type = "IN", addr_type="IP4", transport="RTP/AVP"):
+ sdp = sdp_media_templ
+ sdp = sdp.replace("$MEDIA_TYPE", media_type)
+ sdp = sdp.replace("$LOCAL_IP", local_ip)
+ sdp = sdp.replace("$PORT", str(local_port))
+ sdp = sdp.replace("$NET_TYPE", net_type)
+ sdp = sdp.replace("$ADDR_TYPE", addr_type)
+ sdp = sdp.replace("$TRANSPORT", transport)
+ sdp = sdp.replace("$SDP_LINES", extra_lines)
+ return sdp
+
+
diff --git a/tests/pjsua/inc_sip.py b/tests/pjsua/inc_sip.py
new file mode 100644
index 0000000..1e9a267
--- /dev/null
+++ b/tests/pjsua/inc_sip.py
@@ -0,0 +1,343 @@
+# $Id: inc_sip.py 3283 2010-08-18 07:37:29Z bennylp $
+#
+from socket import *
+import re
+import random
+import time
+import sys
+import inc_cfg as cfg
+from select import *
+
+# SIP request template
+req_templ = \
+"""$METHOD $TARGET_URI SIP/2.0\r
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;branch=z9hG4bK$BRANCH\r
+Max-Forwards: 70\r
+From: <sip:caller@pjsip.org>$FROM_TAG\r
+To: <$TARGET_URI>$TO_TAG\r
+Contact: <sip:$LOCAL_IP:$LOCAL_PORT;transport=udp>\r
+Call-ID: $CALL_ID@pjsip.org\r
+CSeq: $CSEQ $METHOD\r
+Allow: PRACK, INVITE, ACK, BYE, CANCEL, UPDATE, REFER\r
+Supported: replaces, 100rel, norefersub\r
+User-Agent: pjsip.org Python tester\r
+Content-Length: $CONTENT_LENGTH\r
+$SIP_HEADERS"""
+
+
+def is_request(msg):
+ return msg.split(" ", 1)[0] != "SIP/2.0"
+
+def is_response(msg):
+ return msg.split(" ", 1)[0] == "SIP/2.0"
+
+def get_code(msg):
+ if msg=="":
+ return 0
+ return int(msg.split(" ", 2)[1])
+
+def get_tag(msg, hdr="To"):
+ pat = "^" + hdr + ":.*"
+ result = re.search(pat, msg, re.M | re.I)
+ if result==None:
+ return ""
+ line = result.group()
+ #print "line=", line
+ tags = line.split(";tag=")
+ if len(tags)>1:
+ return tags[1]
+ return ""
+ #return re.split("[;& ]", s)
+
+def get_header(msg, hname):
+ headers = msg.splitlines()
+ for hdr in headers:
+ hfields = hdr.split(": ", 2)
+ if hfields[0]==hname:
+ return hfields[1]
+ return None
+
+class Dialog:
+ sock = None
+ dst_addr = ""
+ dst_port = 5060
+ local_ip = ""
+ local_port = 0
+ tcp = False
+ call_id = str(random.random())
+ cseq = 0
+ local_tag = ";tag=" + str(random.random())
+ rem_tag = ""
+ last_resp_code = 0
+ inv_branch = ""
+ trace_enabled = True
+ last_request = ""
+ def __init__(self, dst_addr, dst_port=5060, tcp=False, trace=True, local_port=0):
+ self.dst_addr = dst_addr
+ self.dst_port = dst_port
+ self.tcp = tcp
+ self.trace_enabled = trace
+ if tcp==True:
+ self.sock = socket(AF_INET, SOCK_STREAM)
+ self.sock.connect(dst_addr, dst_port)
+ else:
+ self.sock = socket(AF_INET, SOCK_DGRAM)
+ self.sock.bind(("127.0.0.1", local_port))
+
+ self.local_ip, self.local_port = self.sock.getsockname()
+ self.trace("Dialog socket bound to " + self.local_ip + ":" + str(self.local_port))
+
+ def trace(self, txt):
+ if self.trace_enabled:
+ print str(time.strftime("%H:%M:%S ")) + txt
+
+ def update_fields(self, msg):
+ if self.tcp:
+ transport_param = ";transport=tcp"
+ else:
+ transport_param = ""
+ msg = msg.replace("$TARGET_URI", "sip:"+self.dst_addr+":"+str(self.dst_port) + transport_param)
+ msg = msg.replace("$LOCAL_IP", self.local_ip)
+ msg = msg.replace("$LOCAL_PORT", str(self.local_port))
+ msg = msg.replace("$FROM_TAG", self.local_tag)
+ msg = msg.replace("$TO_TAG", self.rem_tag)
+ msg = msg.replace("$CALL_ID", self.call_id)
+ msg = msg.replace("$CSEQ", str(self.cseq))
+ branch=str(random.random())
+ msg = msg.replace("$BRANCH", branch)
+ return msg
+
+ def create_req(self, method, sdp, branch="", extra_headers="", body=""):
+ if branch=="":
+ self.cseq = self.cseq + 1
+ msg = req_templ
+ msg = msg.replace("$METHOD", method)
+ msg = msg.replace("$SIP_HEADERS", extra_headers)
+ if branch=="":
+ branch=str(random.random())
+ msg = msg.replace("$BRANCH", branch)
+ if sdp!="":
+ msg = msg.replace("$CONTENT_LENGTH", str(len(sdp)))
+ msg = msg + "Content-Type: application/sdp\r\n"
+ msg = msg + "\r\n"
+ msg = msg + sdp
+ elif body!="":
+ msg = msg.replace("$CONTENT_LENGTH", str(len(body)))
+ msg = msg + "\r\n"
+ msg = msg + body
+ else:
+ msg = msg.replace("$CONTENT_LENGTH", "0")
+ return self.update_fields(msg)
+
+ def create_response(self, request, code, reason, to_tag=""):
+ response = "SIP/2.0 " + str(code) + " " + reason + "\r\n"
+ lines = request.splitlines()
+ for line in lines:
+ hdr = line.split(":", 1)[0]
+ if hdr in ["Via", "From", "To", "CSeq", "Call-ID"]:
+ if hdr=="To" and to_tag!="":
+ line = line + ";tag=" + to_tag
+ elif hdr=="Via":
+ line = line + ";received=127.0.0.1"
+ response = response + line + "\r\n"
+ return response
+
+ def create_invite(self, sdp, extra_headers="", body=""):
+ self.inv_branch = str(random.random())
+ return self.create_req("INVITE", sdp, branch=self.inv_branch, extra_headers=extra_headers, body=body)
+
+ def create_ack(self, sdp="", extra_headers=""):
+ return self.create_req("ACK", sdp, extra_headers=extra_headers, branch=self.inv_branch)
+
+ def create_bye(self, extra_headers=""):
+ return self.create_req("BYE", "", extra_headers)
+
+ def send_msg(self, msg, dst_addr=None):
+ if (is_request(msg)):
+ self.last_request = msg.split(" ", 1)[0]
+ if not dst_addr:
+ dst_addr = (self.dst_addr, self.dst_port)
+ self.trace("============== TX MSG to " + str(dst_addr) + " ============= \n" + msg)
+ self.sock.sendto(msg, 0, dst_addr)
+
+ def wait_msg_from(self, timeout):
+ endtime = time.time() + timeout
+ msg = ""
+ src_addr = None
+ while time.time() < endtime:
+ readset = select([self.sock], [], [], 1)
+ if len(readset[0]) < 1 or not self.sock in readset[0]:
+ if len(readset[0]) < 1:
+ print "select() timeout (will wait for " + str(int(endtime - time.time())) + "more secs)"
+ elif not self.sock in readset[0]:
+ print "select() alien socket"
+ else:
+ print "select other error"
+ continue
+ try:
+ msg, src_addr = self.sock.recvfrom(4096)
+ break
+ except:
+ print "recv() exception: ", sys.exc_info()[0]
+ continue
+
+ if msg=="":
+ return "", None
+ if self.last_request=="INVITE" and self.rem_tag=="":
+ self.rem_tag = get_tag(msg, "To")
+ self.rem_tag = self.rem_tag.rstrip("\r\n;")
+ if self.rem_tag != "":
+ self.rem_tag = ";tag=" + self.rem_tag
+ self.trace("=== rem_tag:" + self.rem_tag)
+ self.trace("=========== RX MSG from " + str(src_addr) + " ===========\n" + msg)
+ return (msg, src_addr)
+
+ def wait_msg(self, timeout):
+ return self.wait_msg_from(timeout)[0]
+
+ # Send request and wait for final response
+ def send_request_wait(self, msg, timeout):
+ t1 = 1.0
+ endtime = time.time() + timeout
+ resp = ""
+ code = 0
+ for i in range(0,5):
+ self.send_msg(msg)
+ resp = self.wait_msg(t1)
+ if resp!="" and is_response(resp):
+ code = get_code(resp)
+ break
+ last_resp = resp
+ while code < 200 and time.time() < endtime:
+ resp = self.wait_msg(endtime - time.time())
+ if resp != "" and is_response(resp):
+ code = get_code(resp)
+ last_resp = resp
+ elif resp=="":
+ break
+ return last_resp
+
+ def hangup(self, last_code=0):
+ self.trace("====== hangup =====")
+ if last_code!=0:
+ self.last_resp_code = last_code
+ if self.last_resp_code>0 and self.last_resp_code<200:
+ msg = self.create_req("CANCEL", "", branch=self.inv_branch, extra_headers="")
+ self.send_request_wait(msg, 5)
+ msg = self.create_ack()
+ self.send_msg(msg)
+ elif self.last_resp_code>=200 and self.last_resp_code<300:
+ msg = self.create_ack()
+ self.send_msg(msg)
+ msg = self.create_bye()
+ self.send_request_wait(msg, 5)
+ else:
+ msg = self.create_ack()
+ self.send_msg(msg)
+
+
+class SendtoCfg:
+ # Test name
+ name = ""
+ # pjsua InstanceParam
+ inst_param = None
+ # Complete INVITE message. If this is not empty, then this
+ # message will be sent instead and the "sdp" and "extra_headers"
+ # settings will be ignored.
+ complete_msg = ""
+ # Initial SDP
+ sdp = ""
+ # Extra headers to add to request
+ extra_headers = ""
+ # Expected code
+ resp_code = 0
+ # Use TCP?
+ use_tcp = False
+ # List of RE patterns that must exist in response
+ resp_include = []
+ # List of RE patterns that must NOT exist in response
+ resp_exclude = []
+ # Full (non-SDP) body
+ body = ""
+ # Constructor
+ def __init__(self, name, pjsua_args, sdp, resp_code,
+ resp_inc=[], resp_exc=[], use_tcp=False,
+ extra_headers="", body="", complete_msg="",
+ enable_buffer = False):
+ self.complete_msg = complete_msg
+ self.sdp = sdp
+ self.resp_code = resp_code
+ self.resp_include = resp_inc
+ self.resp_exclude = resp_exc
+ self.use_tcp = use_tcp
+ self.extra_headers = extra_headers
+ self.body = body
+ self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
+ self.inst_param.enable_buffer = enable_buffer
+
+
+class RecvfromTransaction:
+ # The test title for this transaction
+ title = ""
+ # Optinal list of pjsua command and optional expect patterns
+ # to be invoked to make pjsua send a request
+ # Sample:
+ # (to make call and wait for INVITE to be sent)
+ # cmds = [ ["m"], ["sip:127.0.0.1", "INVITE sip:"] ]
+ cmds = []
+ # Check if the CSeq must be greater than last Cseq?
+ check_cseq = True
+ # List of RE patterns that must exists in incoming request
+ include = []
+ # List of RE patterns that MUST NOT exist in incoming request
+ exclude = []
+ # Response code to send
+ resp_code = 0
+ # Additional list of headers to be sent on the response
+ # Note: no need to add CRLF on the header
+ resp_hdr = []
+ # Message body. This should include the Content-Type header too.
+ # Sample:
+ # body = """Content-Type: application/sdp\r\n
+ # \r\n
+ # v=0\r\n
+ # ...
+ # """
+ body = None
+ # Pattern to be expected on pjsua when receiving the response
+ expect = ""
+
+ def __init__(self, title, resp_code, check_cseq=True,
+ include=[], exclude=[], cmds=[], resp_hdr=[], resp_body=None, expect=""):
+ self.title = title
+ self.cmds = cmds
+ self.include = include
+ self.exclude = exclude
+ self.resp_code = resp_code
+ self.resp_hdr = resp_hdr
+ self.body = resp_body
+ self.expect = expect
+
+
+class RecvfromCfg:
+ # Test name
+ name = ""
+ # pjsua InstanceParam
+ inst_param = None
+ # List of RecvfromTransaction
+ transaction = None
+ # Use TCP?
+ tcp = False
+
+ # Note:
+ # Any "$PORT" string in the pjsua_args will be replaced
+ # by server port
+ def __init__(self, name, pjsua_args, transaction, tcp=False):
+ self.name = name
+ self.inst_param = cfg.InstanceParam("pjsua", pjsua_args)
+ self.transaction = transaction
+ self.tcp=tcp
+
+
+
+
diff --git a/tests/pjsua/mod_call.py b/tests/pjsua/mod_call.py
new file mode 100644
index 0000000..c725f21
--- /dev/null
+++ b/tests/pjsua/mod_call.py
@@ -0,0 +1,226 @@
+# $Id: mod_call.py 2078 2008-06-27 21:12:12Z nanang $
+import time
+import imp
+import sys
+import inc_const as const
+from inc_cfg import *
+
+# Load configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# Check media flow between ua1 and ua2
+def check_media(ua1, ua2):
+ ua1.send("#")
+ ua1.expect("#")
+ ua1.send("1122")
+ ua2.expect(const.RX_DTMF + "1")
+ ua2.expect(const.RX_DTMF + "1")
+ ua2.expect(const.RX_DTMF + "2")
+ ua2.expect(const.RX_DTMF + "2")
+
+
+# Test body function
+def test_func(t):
+ callee = t.process[0]
+ caller = t.process[1]
+
+ # if have_reg then wait for couple of seconds for PUBLISH
+ # to complete (just in case pUBLISH is used)
+ if callee.inst_param.have_reg:
+ time.sleep(1)
+ if caller.inst_param.have_reg:
+ time.sleep(1)
+
+ # Caller making call
+ caller.send("m")
+ caller.send(t.inst_params[0].uri)
+ caller.expect(const.STATE_CALLING)
+
+ # Callee waits for call and answers with 180/Ringing
+ time.sleep(0.2)
+ callee.expect(const.EVENT_INCOMING_CALL)
+ callee.send("a")
+ callee.send("180")
+ callee.expect("SIP/2.0 180")
+ caller.expect("SIP/2.0 180")
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Callee answers with 200/OK
+ callee.send("a")
+ callee.send("200")
+
+ # Wait until call is connected in both endpoints
+ time.sleep(0.2)
+ caller.expect(const.STATE_CONFIRMED)
+ callee.expect(const.STATE_CONFIRMED)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+ time.sleep(0.1)
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is okay
+ time.sleep(0.3)
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # Hold call by caller
+ caller.send("H")
+ caller.expect("INVITE sip:")
+ callee.expect("INVITE sip:")
+ caller.expect(const.MEDIA_HOLD)
+ callee.expect(const.MEDIA_HOLD)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Release hold
+ time.sleep(0.5)
+ caller.send("v")
+ caller.expect("INVITE sip:")
+ callee.expect("INVITE sip:")
+ caller.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
+ callee.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is okay
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Hold call by callee
+ callee.send("H")
+ callee.expect("INVITE sip:")
+ caller.expect("INVITE sip:")
+ caller.expect(const.MEDIA_HOLD)
+ callee.expect(const.MEDIA_HOLD)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Release hold
+ time.sleep(0.1)
+ callee.send("v")
+ callee.expect("INVITE sip:")
+ caller.expect("INVITE sip:")
+ callee.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
+ caller.expect(const.MEDIA_ACTIVE, title="waiting for media active after call hold")
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is okay
+ # Wait for some time for ICE negotiation
+ time.sleep(0.6)
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # UPDATE (by caller)
+ caller.send("U")
+ #caller.sync_stdout()
+ callee.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
+ caller.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is okay
+ time.sleep(0.1)
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # UPDATE (by callee)
+ callee.send("U")
+ callee.expect("UPDATE sip:")
+ caller.expect("UPDATE sip:")
+ caller.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
+ callee.expect(const.MEDIA_ACTIVE, title="waiting for media active with UPDATE")
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is okay
+ time.sleep(0.1)
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # Synchronize stdout
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Set codecs in both caller and callee so that there is
+ # no common codec between them.
+ # In caller we only enable PCMU, in callee we only enable PCMA
+ caller.send("Cp")
+ caller.expect("Enter codec")
+ caller.send("* 0")
+ caller.send("Cp")
+ caller.expect("Enter codec")
+ caller.send("pcmu 120")
+
+ callee.send("Cp")
+ callee.expect("Enter codec")
+ callee.send("* 0")
+ callee.send("Cp")
+ callee.expect("Enter codec")
+ callee.send("pcma 120")
+
+ # Test when UPDATE fails (by callee)
+ callee.send("U")
+ caller.expect("SIP/2.0 488")
+ callee.expect("SIP/2.0 488")
+ callee.sync_stdout()
+ caller.sync_stdout()
+
+ # Test that media is still okay
+ time.sleep(0.1)
+ check_media(caller, callee)
+ check_media(callee, caller)
+
+ # Test when UPDATE fails (by caller)
+ caller.send("U")
+ caller.expect("UPDATE sip:")
+ callee.expect("UPDATE sip:")
+ callee.expect("SIP/2.0 488")
+ caller.expect("SIP/2.0 488")
+ caller.sync_stdout()
+ callee.sync_stdout()
+
+ # Test that media is still okay
+ time.sleep(0.1)
+ check_media(callee, caller)
+ check_media(caller, callee)
+
+ # Hangup call
+ time.sleep(0.1)
+ caller.send("h")
+
+ # Wait until calls are cleared in both endpoints
+ caller.expect(const.STATE_DISCONNECTED)
+ callee.expect(const.STATE_DISCONNECTED)
+
+
+# Here where it all comes together
+test = cfg_file.test_param
+test.test_func = test_func
+
diff --git a/tests/pjsua/mod_media_playrec.py b/tests/pjsua/mod_media_playrec.py
new file mode 100644
index 0000000..897cb63
--- /dev/null
+++ b/tests/pjsua/mod_media_playrec.py
@@ -0,0 +1,108 @@
+# $Id: mod_media_playrec.py 2884 2009-08-17 08:29:47Z bennylp $
+
+# PLAYFILE -> RECFILE:
+# Input file is played and is recorded to output, then compare them.
+# Useful to tes clock rates compatibility and resample quality
+# null-audio
+# port 1: wav file input xxxxxx.clock_rate.wav, e.g: test1.8.wav
+# port 2: wav file ouput xxxxxx.clock_rate.wav, e.g: res1.8.wav
+# wav input must be more than 3 seconds long
+
+import time
+import imp
+import sys
+import re
+import subprocess
+import inc_const as const
+from inc_cfg import *
+
+# Load configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# WAV similarity calculator
+COMPARE_WAV_EXE = ""
+if sys.platform.find("win32")!=-1:
+ COMPARE_WAV_EXE = "tools/cmp_wav.exe"
+ G_INUNIX = False
+else:
+ COMPARE_WAV_EXE = "tools/cmp_wav"
+ G_INUNIX = True
+
+
+# Threshold to declare degradation is too high when result is lower than this value
+COMPARE_THRESHOLD = 2
+
+# COMPARE params
+input_filename = "" # Input filename
+output_filename = "" # Output filename
+
+# Test body function
+def test_func(t):
+ global input_filename
+ global output_filename
+
+ endpt = t.process[0]
+
+ # Get input file name
+ input_filename = re.compile(const.MEDIA_PLAY_FILE).search(endpt.inst_param.arg).group(1)
+ endpt.trace("Input file = " + input_filename)
+
+ # Get output file name
+ output_filename = re.compile(const.MEDIA_REC_FILE).search(endpt.inst_param.arg).group(1)
+ endpt.trace("Output file = " + output_filename)
+
+ # Find appropriate clock rate for the input file
+ clock_rate = re.compile(".+(\.\d+\.wav)$").match(output_filename).group(1)
+ if (clock_rate==None):
+ endpt.trace("Cannot compare input & output, incorrect output filename format")
+ return
+ input_filename = re.sub("\.\d+\.wav$", clock_rate, input_filename)
+ endpt.trace("WAV file to be compared with output = " + input_filename)
+
+ # Connect input-output file
+ endpt.sync_stdout()
+
+ endpt.send("cc 1 2")
+ endpt.expect(const.MEDIA_CONN_PORT_SUCCESS)
+
+ # Wait
+ time.sleep(3)
+
+ endpt.sync_stdout()
+
+ # Disconnect input-output file
+ endpt.send("cd 1 2")
+ endpt.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
+
+
+# Post body function
+def post_func(t):
+ global input_filename
+ global output_filename
+
+ endpt = t.process[0]
+
+ # Check WAV similarity
+ fullcmd = COMPARE_WAV_EXE + " " + input_filename + " " + output_filename + " " + "3000"
+ endpt.trace("Popen " + fullcmd)
+ cmp_proc = subprocess.Popen(fullcmd, shell=G_INUNIX, stdout=subprocess.PIPE, universal_newlines=True)
+
+ # Parse similarity ouput
+ line = cmp_proc.stdout.readline()
+ mo_sim_val = re.match(".+=\s+(\d+)", line)
+ if (mo_sim_val == None):
+ raise TestError("Error comparing WAV files")
+ return
+
+ # Evaluate the similarity value
+ sim_val = mo_sim_val.group(1)
+ if (sim_val >= COMPARE_THRESHOLD):
+ endpt.trace("WAV similarity = " + sim_val)
+ else:
+ raise TestError("WAV degraded heavily, similarity = " + sim_val)
+
+
+# Here where it all comes together
+test = cfg_file.test_param
+test.test_func = test_func
+test.post_func = post_func
diff --git a/tests/pjsua/mod_pesq.py b/tests/pjsua/mod_pesq.py
new file mode 100644
index 0000000..e2dbb60
--- /dev/null
+++ b/tests/pjsua/mod_pesq.py
@@ -0,0 +1,167 @@
+# $Id: mod_pesq.py 2417 2009-01-05 15:31:25Z bennylp $
+
+# Quality test of media calls.
+# - UA1 calls UA2
+# - UA1 plays a file until finished to be streamed to UA2
+# - UA2 records from stream
+# - Apply PESQ to played file (reference) and recorded file (degraded)
+#
+# File should be:
+# - naming: xxxxxx.CLOCK_RATE.wav, e.g: test1.8.wav
+# - clock-rate of those files can only be 8khz or 16khz
+
+import time
+import imp
+import os
+import sys
+import re
+import subprocess
+import wave
+import shutil
+import inc_const as const
+
+from inc_cfg import *
+
+# Load configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# PESQ configs
+PESQ = "tools/pesq" # PESQ executable path
+PESQ_DEFAULT_THRESHOLD = 3.4 # Default minimum acceptable PESQ MOS value
+
+# PESQ params
+pesq_sample_rate_opt = "" # Sample rate option for PESQ
+input_filename = "" # Input/Reference filename
+output_filename = "" # Output/Degraded filename
+
+
+# Test body function
+def test_func(t):
+ global pesq_sample_rate_opt
+ global input_filename
+ global output_filename
+
+ ua1 = t.process[0]
+ ua2 = t.process[1]
+
+ # Get input file name
+ input_filename = re.compile(const.MEDIA_PLAY_FILE).search(ua1.inst_param.arg).group(1)
+
+ # Get output file name
+ output_filename = re.compile(const.MEDIA_REC_FILE).search(ua2.inst_param.arg).group(1)
+
+ # Get WAV input length, in seconds
+ fin = wave.open(input_filename, "r")
+ if fin == None:
+ raise TestError("Failed opening input WAV file")
+ inwavlen = fin.getnframes() * 1.0 / fin.getframerate()
+ inwavlen += 0.2
+ fin.close()
+ print "WAV input len = " + str(inwavlen) + "s"
+
+ # Get clock rate of the output
+ mo_clock_rate = re.compile("\.(\d+)\.wav").search(output_filename)
+ if (mo_clock_rate==None):
+ raise TestError("Cannot compare input & output, incorrect output filename format")
+ clock_rate = mo_clock_rate.group(1)
+
+ # Get channel count of the output
+ channel_count = 1
+ if re.search("--stereo", ua2.inst_param.arg) != None:
+ channel_count = 2
+
+ # Get matched input file from output file
+ # (PESQ evaluates only files whose same clock rate & channel count)
+ if channel_count == 2:
+ if re.search("\.\d+\.\d+\.wav", input_filename) != None:
+ input_filename = re.sub("\.\d+\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
+ else:
+ input_filename = re.sub("\.\d+\.wav", "." + str(channel_count) + "."+clock_rate+".wav", input_filename)
+
+ if (clock_rate != "8") & (clock_rate != "16"):
+ raise TestError("PESQ only works on clock rate 8kHz or 16kHz, clock rate used = "+clock_rate+ "kHz")
+
+ # Get conference clock rate of UA2 for PESQ sample rate option
+ pesq_sample_rate_opt = "+" + clock_rate + "000"
+
+ # UA1 making call
+ ua1.send("m")
+ ua1.send(t.inst_params[1].uri)
+ ua1.expect(const.STATE_CALLING)
+
+ # UA2 wait until call established
+ ua2.expect(const.STATE_CONFIRMED)
+
+ ua1.sync_stdout()
+ ua2.sync_stdout()
+ time.sleep(2)
+
+ # Disconnect mic -> rec file, to avoid echo recorded when using sound device
+ # Disconnect stream -> spk, make it silent
+ # Connect stream -> rec file, start recording
+ ua2.send("cd 0 1\ncd 4 0\ncc 4 1")
+
+ # Disconnect mic -> stream, make stream purely sending from file
+ # Disconnect stream -> spk, make it silent
+ # Connect file -> stream, start sending
+ ua1.send("cd 0 4\ncd 4 0\ncc 1 4")
+
+ time.sleep(inwavlen)
+
+ # Disconnect files from bridge
+ ua2.send("cd 4 1")
+ ua2.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
+ ua1.send("cd 1 4")
+ ua1.expect(const.MEDIA_DISCONN_PORT_SUCCESS)
+
+
+# Post body function
+def post_func(t):
+ global pesq_sample_rate_opt
+ global input_filename
+ global output_filename
+
+ endpt = t.process[0]
+
+ # Execute PESQ
+ fullcmd = os.path.normpath(PESQ) + " " + pesq_sample_rate_opt + " " + input_filename + " " + output_filename
+ endpt.trace("Popen " + fullcmd)
+ pesq_proc = subprocess.Popen(fullcmd, shell=True, stdout=subprocess.PIPE, universal_newlines=True)
+ pesq_out = pesq_proc.communicate()
+
+ # Parse ouput
+ mo_pesq_out = re.compile("Prediction[^=]+=\s+([\-\d\.]+)\s*").search(pesq_out[0])
+ if (mo_pesq_out == None):
+ raise TestError("Failed to fetch PESQ result")
+
+ # Get threshold
+ if (cfg_file.pesq_threshold != None) | (cfg_file.pesq_threshold > -0.5 ):
+ threshold = cfg_file.pesq_threshold
+ else:
+ threshold = PESQ_DEFAULT_THRESHOLD
+
+ # Evaluate the PESQ MOS value
+ pesq_res = mo_pesq_out.group(1)
+ if (float(pesq_res) >= threshold):
+ endpt.trace("Success, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
+ else:
+ endpt.trace("Failed, PESQ result = " + pesq_res + " (target=" + str(threshold) + ").")
+ # Save the wav file
+ wavoutname = ARGS[1]
+ wavoutname = re.sub("[\\\/]", "_", wavoutname)
+ wavoutname = re.sub("\.py$", ".wav", wavoutname)
+ wavoutname = "logs/" + wavoutname
+ try:
+ shutil.copyfile(output_filename, wavoutname)
+ print "Output WAV is copied to " + wavoutname
+ except:
+ print "Couldn't copy output WAV, please check if 'logs' directory exists."
+
+ raise TestError("WAV seems to be degraded badly, PESQ = "+ pesq_res + " (target=" + str(threshold) + ").")
+
+
+# Here where it all comes together
+test = cfg_file.test_param
+test.test_func = test_func
+test.post_func = post_func
+
diff --git a/tests/pjsua/mod_pres.py b/tests/pjsua/mod_pres.py
new file mode 100644
index 0000000..1dbcc2c
--- /dev/null
+++ b/tests/pjsua/mod_pres.py
@@ -0,0 +1,125 @@
+# $Id: mod_pres.py 2078 2008-06-27 21:12:12Z nanang $
+import time
+import imp
+import sys
+import inc_const as const
+from inc_cfg import *
+
+# Load configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+
+# Test body function
+def test_func(t):
+ u1 = t.process[0]
+ uri1 = cfg_file.test_param.inst_params[0].uri
+ acc1 = "-1"
+ u2 = t.process[1]
+ uri2 = cfg_file.test_param.inst_params[1].uri
+ acc2 = "-1"
+
+ # if have_reg then wait for couple of seconds for PUBLISH
+ # to complete (just in case pUBLISH is used)
+ if u1.inst_param.have_reg:
+ time.sleep(1)
+ if u2.inst_param.have_reg:
+ time.sleep(1)
+
+ # U1 adds U2 as buddy
+ u1.send("+b")
+ u1.send(uri2)
+ u1.expect("Subscription state changed NULL --> SENT")
+ u1.expect("Presence subscription.*is ACCEPTED")
+ if not u2.inst_param.have_publish:
+ # Process incoming SUBSCRIBE in U2
+ # Finds out which account gets the subscription in U2
+ line = u2.expect("pjsua_pres.*subscription.*using account")
+ acc2 = line.split("using account ")[1]
+ # wait until we've got Online notification
+ u1.expect(uri2 + ".*Online")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # U2 adds U1 as buddy
+ u2.send("+b")
+ u2.send(uri1)
+ u2.expect("Subscription state changed NULL --> SENT")
+ u2.expect("Presence subscription.*is ACCEPTED")
+ if not u1.inst_param.have_publish:
+ # Process incoming SUBSCRIBE in U1
+ # Finds out which account gets the subscription in U1
+ line = u1.expect("pjsua_pres.*subscription.*using account")
+ acc1 = line.split("using account ")[1]
+ # wait until we've got Online notification
+ u2.expect(uri1 + ".*Online")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # Set current account in both U1 and U2
+ if acc1!="-1":
+ u1.send(">")
+ u1.send(acc1)
+ u1.expect("Current account changed")
+ if acc2!="-1":
+ u2.send(">")
+ u2.send(acc2)
+ u2.expect("Current account changed")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # u2 toggles online status
+ u2.send("t")
+ u1.expect(uri2 + ".*status.*Offline")
+ u2.expect("offline")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # u1 toggles online status
+ u1.send("t")
+ u2.expect(uri1 + ".*status.*Offline")
+ u1.expect("offline")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # u2 set online status to On the phone
+ u2.send("T")
+ u2.send("3")
+ u1.expect(uri2 + ".*status.*On the phone")
+ u2.expect("On the phone")
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+ # U1 send IM
+ im_text = "Hello World from U1"
+ u1.send("i")
+ u1.send(uri2)
+ u2.expect(" is typing")
+ u1.send(im_text)
+ u1.expect(im_text+".*delivered successfully")
+ u2.expect("MESSAGE from.*"+im_text)
+
+ # Synchronize stdout
+ u1.sync_stdout()
+ u2.sync_stdout()
+
+
+# Here where it all comes together
+test = cfg_file.test_param
+test.test_func = test_func
+
diff --git a/tests/pjsua/mod_recvfrom.py b/tests/pjsua/mod_recvfrom.py
new file mode 100644
index 0000000..8aaa716
--- /dev/null
+++ b/tests/pjsua/mod_recvfrom.py
@@ -0,0 +1,97 @@
+# $Id: mod_recvfrom.py 3259 2010-08-09 07:31:34Z nanang $
+import imp
+import sys
+import inc_sip as sip
+import inc_const as const
+import re
+from inc_cfg import *
+
+# Read configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# Default server port (should we randomize?)
+srv_port = 50070
+
+def test_func(test):
+ pjsua = test.process[0]
+ dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port,
+ local_port=srv_port,
+ tcp=cfg_file.recvfrom_cfg.tcp)
+
+ last_cseq = 0
+ last_method = ""
+ last_call_id = ""
+ for t in cfg_file.recvfrom_cfg.transaction:
+ # Print transaction title
+ if t.title != "":
+ dlg.trace(t.title)
+ # Run command and expect patterns
+ for c in t.cmds:
+ if c[0] and c[0] != "":
+ pjsua.send(c[0])
+ if len(c)>1 and c[1] and c[1] != "":
+ pjsua.expect(c[1])
+ # Wait for request
+ if t.check_cseq:
+ # Absorbs retransmissions
+ cseq = 0
+ method = last_method
+ call_id = last_call_id
+ while cseq <= last_cseq and method == last_method and call_id == last_call_id:
+ request, src_addr = dlg.wait_msg_from(30)
+ if request==None or request=="":
+ raise TestError("Timeout waiting for request")
+ method = request.split(" ", 1)[0]
+ cseq_hval = sip.get_header(request, "CSeq")
+ cseq_hval = cseq_hval.split(" ")[0]
+ cseq = int(cseq_hval)
+ call_id = sip.get_header(request, "Call-ID")
+ last_cseq = cseq
+ last_method = method
+ else:
+ request, src_addr = dlg.wait_msg_from(30)
+ if request==None or request=="":
+ raise TestError("Timeout waiting for request")
+
+ # Check for include patterns
+ for pat in t.include:
+ if re.search(pat, request, re.M | re.I)==None:
+ if t.title:
+ tname = " in " + t.title + " transaction"
+ else:
+ tname = ""
+ raise TestError("Pattern " + pat + " not found" + tname)
+ # Check for exclude patterns
+ for pat in t.exclude:
+ if re.search(pat, request, re.M | re.I)!=None:
+ if t.title:
+ tname = " in " + t.title + " transaction"
+ else:
+ tname = ""
+ raise TestError("Excluded pattern " + pat + " found" + tname)
+ # Create response
+ if t.resp_code!=0:
+ response = dlg.create_response(request, t.resp_code, "Status reason")
+ # Add headers to response
+ for h in t.resp_hdr:
+ response = response + h + "\r\n"
+ # Add message body if required
+ if t.body:
+ response = response + t.body
+ # Send response
+ dlg.send_msg(response, src_addr)
+
+ # Expect something to happen in pjsua
+ if t.expect != "":
+ pjsua.expect(t.expect)
+ # Sync
+ pjsua.sync_stdout()
+
+# Replace "$PORT" with server port in pjsua args
+cfg_file.recvfrom_cfg.inst_param.arg = cfg_file.recvfrom_cfg.inst_param.arg.replace("$PORT", str(srv_port))
+
+# Here where it all comes together
+test = TestParam(cfg_file.recvfrom_cfg.name,
+ [cfg_file.recvfrom_cfg.inst_param],
+ test_func)
+
diff --git a/tests/pjsua/mod_run.py b/tests/pjsua/mod_run.py
new file mode 100644
index 0000000..4f2964a
--- /dev/null
+++ b/tests/pjsua/mod_run.py
@@ -0,0 +1,11 @@
+# $Id: mod_run.py 2078 2008-06-27 21:12:12Z nanang $
+import imp
+import sys
+
+from inc_cfg import *
+
+# Read configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# Here where it all comes together
+test = cfg_file.test_param
diff --git a/tests/pjsua/mod_sendto.py b/tests/pjsua/mod_sendto.py
new file mode 100644
index 0000000..09042a3
--- /dev/null
+++ b/tests/pjsua/mod_sendto.py
@@ -0,0 +1,53 @@
+# $Id: mod_sendto.py 3243 2010-08-01 09:48:51Z bennylp $
+import imp
+import sys
+import inc_sip as sip
+import inc_const as const
+import re
+from inc_cfg import *
+
+# Read configuration
+cfg_file = imp.load_source("cfg_file", ARGS[1])
+
+# Test body function
+def test_func(t):
+ pjsua = t.process[0]
+ # Create dialog
+ dlg = sip.Dialog("127.0.0.1", pjsua.inst_param.sip_port,
+ tcp=cfg_file.sendto_cfg.use_tcp)
+ #dlg = sip.Dialog("127.0.0.1", 5060, tcp=cfg_file.sendto_cfg.use_tcp)
+ cfg = cfg_file.sendto_cfg
+
+ if len(cfg.complete_msg) != 0:
+ req = dlg.update_fields(cfg.complete_msg)
+ else:
+ req = dlg.create_invite(cfg.sdp, cfg.extra_headers, cfg.body)
+ resp = dlg.send_request_wait(req, 10)
+ if resp=="":
+ raise TestError("Timed-out waiting for response")
+ # Check response code
+ code = int(sip.get_code(resp))
+ if code != cfg.resp_code:
+ dlg.hangup(code)
+ raise TestError("Expecting code " + str(cfg.resp_code) +
+ " got " + str(code))
+ # Check for patterns that must exist
+ for p in cfg.resp_include:
+ if re.search(p, resp, re.M | re.I)==None:
+ dlg.hangup(code)
+ raise TestError("Pattern " + p + " not found")
+ # Check for patterns that must not exist
+ for p in cfg.resp_exclude:
+ if re.search(p, resp, re.M | re.I)!=None:
+ dlg.hangup(code)
+ raise TestError("Excluded pattern " + p + " found")
+ pjsua.sync_stdout()
+ dlg.hangup(code)
+ pjsua.sync_stdout()
+
+# Here where it all comes together
+test = TestParam(cfg_file.sendto_cfg.name,
+ [cfg_file.sendto_cfg.inst_param],
+ test_func)
+
+
diff --git a/tests/pjsua/mod_sipp.py b/tests/pjsua/mod_sipp.py
new file mode 100644
index 0000000..163a8c7
--- /dev/null
+++ b/tests/pjsua/mod_sipp.py
@@ -0,0 +1,275 @@
+# $Id: mod_sipp.py 4188 2012-06-29 09:01:17Z nanang $
+
+## Automatic test module for SIPp.
+##
+## This module will need a test driver for each SIPp scenario:
+## - For simple scenario, i.e: make/receive call (including auth), this
+## test module can auto-generate a default test driver, i.e: make call
+## or apply auto answer. Just name the SIPp scenario using "uas" or
+## "uac" prefix accordingly.
+## - Custom test driver can be defined in a python script file containing
+## a list of the PJSUA instances and another list for PJSUA expects/
+## commands. The custom test driver file must use the same filename as
+## the SIPp XML scenario. See samples of SIPp scenario + its driver
+## in tests/pjsua/scripts-sipp/ folder for detail.
+##
+## Here are defined macros that can be used in the custom driver:
+## - $SIPP_PORT : SIPp binding port
+## - $SIPP_URI : SIPp SIP URI
+## - $PJSUA_PORT[N] : binding port of PJSUA instance #N
+## - $PJSUA_URI[N] : SIP URI of PJSUA instance #N
+
+import ctypes
+import time
+import imp
+import sys
+import os
+import re
+import subprocess
+from inc_cfg import *
+import inc_const
+
+# flags that test is running in Unix
+G_INUNIX = False
+if sys.platform.lower().find("win32")!=-1 or sys.platform.lower().find("microsoft")!=-1:
+ G_INUNIX = False
+else:
+ G_INUNIX = True
+
+# /dev/null handle, for redirecting output when SIPP is not in background mode
+FDEVNULL = None
+
+# SIPp executable path and param
+#SIPP_PATH = '"C:\\Program Files (x86)\\Sipp_3.2\\sipp.exe"'
+SIPP_PATH = 'sipp'
+SIPP_PORT = 6000
+SIPP_PARAM = "-m 1 -i 127.0.0.1 -p " + str(SIPP_PORT)
+SIPP_TIMEOUT = 60
+# On BG mode, SIPp doesn't require special terminal
+# On non-BG mode, on win, it needs env var: "TERMINFO=c:\cygwin\usr\share\terminfo"
+# TODO: on unix with BG mode, waitpid() always fails, need to be fixed
+SIPP_BG_MODE = False
+#SIPP_BG_MODE = not G_INUNIX
+
+# Will be updated based on the test driver file (a .py file whose the same name as SIPp XML file)
+PJSUA_INST_PARAM = []
+PJSUA_EXPECTS = []
+
+# Default PJSUA param if test driver is not available:
+# - no-tcp as SIPp is on UDP only
+# - id, username, and realm: to allow PJSUA sending re-INVITE with auth after receiving 401/407 response
+PJSUA_DEF_PARAM = "--null-audio --max-calls=1 --no-tcp --id=sip:a@localhost --username=a --realm=*"
+
+# Get SIPp scenario (XML file)
+SIPP_SCEN_XML = ""
+if ARGS[1].endswith('.xml'):
+ SIPP_SCEN_XML = ARGS[1]
+else:
+ exit(-99)
+
+
+# Functions for resolving macros in the test driver
+def resolve_pjsua_port(mo):
+ return str(PJSUA_INST_PARAM[int(mo.group(1))].sip_port)
+
+def resolve_pjsua_uri(mo):
+ return PJSUA_INST_PARAM[int(mo.group(1))].uri[1:-1]
+
+def resolve_driver_macros(st):
+ st = re.sub("\$SIPP_PORT", str(SIPP_PORT), st)
+ st = re.sub("\$SIPP_URI", "sip:sipp@127.0.0.1:"+str(SIPP_PORT), st)
+ st = re.sub("\$PJSUA_PORT\[(\d+)\]", resolve_pjsua_port, st)
+ st = re.sub("\$PJSUA_URI\[(\d+)\]", resolve_pjsua_uri, st)
+ return st
+
+
+# Init test driver
+if os.access(SIPP_SCEN_XML[:-4]+".py", os.R_OK):
+ # Load test driver file (the corresponding .py file), if any
+ cfg_file = imp.load_source("cfg_file", SIPP_SCEN_XML[:-4]+".py")
+ for ua_idx, ua_param in enumerate(cfg_file.PJSUA):
+ ua_param = resolve_driver_macros(ua_param)
+ PJSUA_INST_PARAM.append(InstanceParam("pjsua"+str(ua_idx), ua_param))
+ PJSUA_EXPECTS = cfg_file.PJSUA_EXPECTS
+else:
+ # Generate default test driver
+ if os.path.basename(SIPP_SCEN_XML)[0:3] == "uas":
+ # auto make call when SIPp is as UAS
+ ua_param = PJSUA_DEF_PARAM + " sip:127.0.0.1:" + str(SIPP_PORT)
+ else:
+ # auto answer when SIPp is as UAC
+ ua_param = PJSUA_DEF_PARAM + " --auto-answer=200"
+ PJSUA_INST_PARAM.append(InstanceParam("pjsua", ua_param))
+
+
+# Start SIPp process, returning PID
+def start_sipp():
+ global SIPP_BG_MODE
+ sipp_proc = None
+
+ sipp_param = SIPP_PARAM + " -sf " + SIPP_SCEN_XML
+ if SIPP_BG_MODE:
+ sipp_param = sipp_param + " -bg"
+ if SIPP_TIMEOUT:
+ sipp_param = sipp_param + " -timeout "+str(SIPP_TIMEOUT)+"s -timeout_error" + " -deadcall_wait "+str(SIPP_TIMEOUT)+"s"
+
+ # add target param
+ sipp_param = sipp_param + " 127.0.0.1:" + str(PJSUA_INST_PARAM[0].sip_port)
+
+ # run SIPp
+ fullcmd = os.path.normpath(SIPP_PATH) + " " + sipp_param
+ print "Running SIPP: " + fullcmd
+ if SIPP_BG_MODE:
+ sipp_proc = subprocess.Popen(fullcmd, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, shell=G_INUNIX, universal_newlines=False)
+ else:
+ # redirect output to NULL
+ global FDEVNULL
+ #FDEVNULL = open(os.devnull, 'w')
+ FDEVNULL = open("logs/sipp_output.tmp", 'w')
+ sipp_proc = subprocess.Popen(fullcmd, shell=G_INUNIX, stdout=FDEVNULL, stderr=FDEVNULL)
+
+ if not SIPP_BG_MODE:
+ if sipp_proc == None or sipp_proc.poll():
+ return None
+ return sipp_proc
+
+ else:
+ # get SIPp child process PID
+ pid = 0
+ r = re.compile("PID=\[(\d+)\]", re.I)
+
+ while True:
+ line = sipp_proc.stdout.readline()
+ pid_r = r.search(line)
+ if pid_r:
+ pid = int(pid_r.group(1))
+ break
+ if not sipp_proc.poll():
+ break
+
+ if pid != 0:
+ # Win specific: get process handle from PID, as on win32, os.waitpid() takes process handle instead of pid
+ if (sys.platform == "win32"):
+ SYNCHRONIZE = 0x00100000
+ PROCESS_QUERY_INFORMATION = 0x0400
+ hnd = ctypes.windll.kernel32.OpenProcess(SYNCHRONIZE | PROCESS_QUERY_INFORMATION, False, pid)
+ pid = hnd
+
+ return pid
+
+
+# Wait SIPp process to exit, returning SIPp exit code
+def wait_sipp(sipp):
+ if not SIPP_BG_MODE:
+ global FDEVNULL
+ sipp.wait()
+ FDEVNULL.close()
+ return sipp.returncode
+
+ else:
+ print "Waiting SIPp (PID=" + str(sipp) + ") to exit.."
+ wait_cnt = 0
+ while True:
+ try:
+ wait_cnt = wait_cnt + 1
+ [pid_, ret_code] = os.waitpid(sipp, 0)
+ if sipp == pid_:
+ #print "SIPP returned ", ret_code
+ ret_code = ret_code >> 8
+
+ # Win specific: Close process handle
+ if (sys.platform == "win32"):
+ ctypes.windll.kernel32.CloseHandle(sipp)
+
+ return ret_code
+ except os.error:
+ if wait_cnt <= 5:
+ print "Retry ("+str(wait_cnt)+") waiting SIPp.."
+ else:
+ return -99
+
+
+# Execute PJSUA flow
+def exec_pjsua_expects(t, sipp):
+ # Get all PJSUA instances
+ ua = []
+ for ua_idx in range(len(PJSUA_INST_PARAM)):
+ ua.append(t.process[ua_idx])
+
+ ua_err_st = ""
+ while len(PJSUA_EXPECTS):
+ expect = PJSUA_EXPECTS.pop(0)
+ ua_idx = expect[0]
+ expect_st = expect[1]
+ send_cmd = resolve_driver_macros(expect[2])
+ # Handle exception in pjsua flow, to avoid zombie SIPp process
+ try:
+ if expect_st != "":
+ ua[ua_idx].expect(expect_st, raise_on_error = True)
+ if send_cmd != "":
+ ua[ua_idx].send(send_cmd)
+ except TestError, e:
+ ua_err_st = e.desc
+ break;
+ except:
+ ua_err_st = "Unknown error"
+ break;
+
+ # Need to poll here for handling these cases:
+ # - If there is no PJSUA EXPECT scenario, we must keep polling the stdout,
+ # otherwise PJSUA process may stuck (due to stdout pipe buffer full?).
+ # - last PJSUA_EXPECT contains a pjsua command that needs time to
+ # finish, for example "v" (re-INVITE), the SIPp XML scenario may expect
+ # that re-INVITE transaction to be completed and without stdout poll
+ # PJSUA process may stuck.
+ # Ideally the poll should be done contiunously until SIPp process is
+ # terminated.
+ for ua_idx in range(len(ua)):
+ ua[ua_idx].expect(inc_const.STDOUT_REFRESH, raise_on_error = False)
+
+ return ua_err_st
+
+
+def sipp_err_to_str(err_code):
+ if err_code == 0:
+ return "All calls were successful"
+ elif err_code == 1:
+ return "At least one call failed"
+ elif err_code == 97:
+ return "exit on internal command. Calls may have been processed"
+ elif err_code == 99:
+ return "Normal exit without calls processed"
+ elif err_code == -1:
+ return "Fatal error (timeout)"
+ elif err_code == -2:
+ return "Fatal error binding a socket"
+ else:
+ return "Unknown error"
+
+
+# Test body function
+def TEST_FUNC(t):
+
+ sipp_ret_code = 0
+ ua_err_st = ""
+
+ sipp = start_sipp()
+ if not sipp:
+ raise TestError("Failed starting SIPp")
+
+ ua_err_st = exec_pjsua_expects(t, sipp)
+
+ sipp_ret_code = wait_sipp(sipp)
+
+ if ua_err_st != "":
+ raise TestError(ua_err_st)
+
+ if sipp_ret_code:
+ rc = ctypes.c_byte(sipp_ret_code).value
+ raise TestError("SIPp returned error " + str(rc) + ": " + sipp_err_to_str(rc))
+
+
+# Here where it all comes together
+test = TestParam(SIPP_SCEN_XML[:-4],
+ PJSUA_INST_PARAM,
+ TEST_FUNC)
diff --git a/tests/pjsua/run.py b/tests/pjsua/run.py
new file mode 100644
index 0000000..799b659
--- /dev/null
+++ b/tests/pjsua/run.py
@@ -0,0 +1,289 @@
+# $Id: run.py 4183 2012-06-28 09:16:03Z nanang $
+import sys
+import imp
+import re
+import os
+import subprocess
+import random
+import time
+import getopt
+
+import inc_const as const
+import inc_cfg as inc
+
+# Vars
+G_EXE = "" # pjsua executable path
+G_INUNIX = False # flags that test is running in Unix
+
+
+# Usage string
+usage = \
+"""
+run.py - Automated test driver
+
+Usage:
+ run.py [options] MODULE CONFIG
+Options:
+ --exe, -e pjsua executable path
+ --null-audio, -n use null audio
+Sample:
+ run.py -n mod_run.py scripts-run/100_simple.py
+"""
+
+# Parse arguments
+try:
+ opts, args = getopt.getopt(sys.argv[1:], "hne:", ["help", "null-audio", "exe="])
+except getopt.GetoptError, err:
+ print str(err)
+ print usage
+ sys.exit(2)
+for o, a in opts:
+ if o in ("-h", "--help"):
+ print usage
+ sys.exit()
+ elif o in ("-n", "--null-audio"):
+ inc.HAS_SND_DEV = 0
+ elif o in ("-e", "--exe"):
+ G_EXE = a
+ else:
+ print "Unknown options"
+ sys.exit(2)
+
+if len(args) != 2:
+ print "Invalid arguments"
+ print usage
+ sys.exit(2)
+
+# Set global ARGS to be used by modules
+inc.ARGS = args
+
+# Get the pjsua executable name
+if G_EXE == "":
+ if sys.platform.find("win32")!=-1:
+ EXE_DIR = "../../pjsip-apps/bin/"
+ EXECUTABLES = [ "pjsua_vc6d.exe",
+ "pjsua_vc6.exe",
+ "pjsua-i386-Win32-vc8-Debug.exe",
+ "pjsua-i386-Win32-vc8-Debug-Dynamic.exe",
+ "pjsua-i386-Win32-vc8-Debug-Static.exe",
+ "pjsua-i386-Win32-vc8-Release.exe",
+ "pjsua-i386-Win32-vc8-Release-Dynamic.exe",
+ "pjsua-i386-Win32-vc8-Release-Static.exe"
+ ]
+ e_ts = 0
+ for e in EXECUTABLES:
+ e = EXE_DIR + e
+ if os.access(e, os.F_OK):
+ st = os.stat(e)
+ if e_ts==0 or e_ts<st.st_mtime:
+ G_EXE = e
+ e_ts = st.st_mtime
+
+ if G_EXE=="":
+ print "Unable to find valid pjsua. Please build pjsip first"
+ sys.exit(1)
+
+ G_INUNIX = False
+ else:
+ f = open("../../build.mak", "r")
+ while True:
+ line = f.readline()
+ if not line:
+ break
+ if line.find("TARGET_NAME")!=-1:
+ print line
+ G_EXE="../../pjsip-apps/bin/pjsua-" + line.split(":= ")[1]
+ break
+ if G_EXE=="":
+ print "Unable to find ../../../build.mak. Please build pjsip first"
+ sys.exit(1)
+ G_INUNIX = True
+else:
+ if sys.platform.lower().find("win32")!=-1 or sys.platform.lower().find("microsoft")!=-1:
+ G_INUNIX = False
+ else:
+ G_INUNIX = True
+
+
+G_EXE = G_EXE.rstrip("\n\r \t")
+
+###################################
+# Poor man's 'expect'-like class
+class Expect:
+ proc = None
+ echo = False
+ trace_enabled = False
+ name = ""
+ inst_param = None
+ rh = re.compile(const.DESTROYED)
+ ra = re.compile(const.ASSERT, re.I)
+ rr = re.compile(const.STDOUT_REFRESH)
+ t0 = time.time()
+ def __init__(self, inst_param):
+ self.inst_param = inst_param
+ self.name = inst_param.name
+ self.echo = inst_param.echo_enabled
+ self.trace_enabled = inst_param.trace_enabled
+ fullcmd = G_EXE + " " + inst_param.arg + " --stdout-refresh=5 --stdout-refresh-text=" + const.STDOUT_REFRESH
+ if not inst_param.enable_buffer:
+ fullcmd = fullcmd + " --stdout-no-buf"
+ self.trace("Popen " + fullcmd)
+ self.proc = subprocess.Popen(fullcmd, shell=G_INUNIX, bufsize=0, stdin=subprocess.PIPE, stdout=subprocess.PIPE, universal_newlines=False)
+ def send(self, cmd):
+ self.trace("send " + cmd)
+ self.proc.stdin.writelines(cmd + "\n")
+ self.proc.stdin.flush()
+ def expect(self, pattern, raise_on_error=True, title=""):
+ self.trace("expect " + pattern)
+ r = re.compile(pattern, re.I)
+ refresh_cnt = 0
+ while True:
+ line = self.proc.stdout.readline()
+ if line == "":
+ raise inc.TestError(self.name + ": Premature EOF")
+ # Print the line if echo is ON
+ if self.echo:
+ print self.name + ": " + line.rstrip()
+ # Trap assertion error
+ if self.ra.search(line) != None:
+ if raise_on_error:
+ raise inc.TestError(self.name + ": " + line)
+ else:
+ return None
+ # Count stdout refresh text.
+ if self.rr.search(line) != None:
+ refresh_cnt = refresh_cnt+1
+ if refresh_cnt >= 6:
+ self.trace("Timed-out!")
+ if raise_on_error:
+ raise inc.TestError(self.name + " " + title + ": Timeout expecting pattern: \"" + pattern + "\"")
+ else:
+ return None # timeout
+ # Search for expected text
+ if r.search(line) != None:
+ return line
+
+ def sync_stdout(self):
+ self.trace("sync_stdout")
+ cmd = "echo 1" + str(random.randint(1000,9999))
+ self.send(cmd)
+ self.expect(cmd)
+
+ def wait(self):
+ self.trace("wait")
+ self.proc.communicate()
+
+ def trace(self, s):
+ if self.trace_enabled:
+ now = time.time()
+ fmt = self.name + ": " + "================== " + s + " ==================" + " [at t=%(time)03d]"
+ print fmt % {'time':int(now - self.t0)}
+
+#########################
+# Error handling
+def handle_error(errmsg, t, close_processes = True):
+ print "====== Caught error: " + errmsg + " ======"
+ if (close_processes):
+ time.sleep(1)
+ for p in t.process:
+ # Protect against 'Broken pipe' exception
+ try:
+ p.send("q")
+ p.send("q")
+ except:
+ pass
+ is_err = False
+ try:
+ ret = p.expect(const.DESTROYED, False)
+ if not ret:
+ is_err = True
+ except:
+ is_err = True
+ if is_err:
+ if sys.hexversion >= 0x02060000:
+ p.proc.terminate()
+ else:
+ p.wait()
+ else:
+ p.wait()
+ print "Test completed with error: " + errmsg
+ sys.exit(1)
+
+
+#########################
+# MAIN
+
+# Import the test script
+script = imp.load_source("script", inc.ARGS[0])
+
+# Init random seed
+random.seed()
+
+# Validate
+if script.test == None:
+ print "Error: no test defined"
+ sys.exit(1)
+
+if script.test.skip:
+ print "Test " + script.test.title + " is skipped"
+ sys.exit(0)
+
+if len(script.test.inst_params) == 0:
+ print "Error: test doesn't contain pjsua run descriptions"
+ sys.exit(1)
+
+# Instantiate pjsuas
+print "====== Running " + script.test.title + " ======"
+print "Using " + G_EXE + " as pjsua executable"
+
+for inst_param in script.test.inst_params:
+ try:
+ # Create pjsua's Expect instance from the param
+ p = Expect(inst_param)
+ # Wait until registration completes
+ if inst_param.have_reg:
+ p.expect(inst_param.uri+".*registration success")
+ # Synchronize stdout
+ p.send("")
+ p.expect(const.PROMPT)
+ p.send("echo 1")
+ p.send("echo 1")
+ p.expect("echo 1")
+ # add running instance
+ script.test.process.append(p)
+
+ except inc.TestError, e:
+ handle_error(e.desc, script.test)
+
+# Run the test function
+if script.test.test_func != None:
+ try:
+ script.test.test_func(script.test)
+ except inc.TestError, e:
+ handle_error(e.desc, script.test)
+
+# Shutdown all instances
+time.sleep(2)
+for p in script.test.process:
+ # Unregister if we have_reg to make sure that next tests
+ # won't wail
+ if p.inst_param.have_reg:
+ p.send("ru")
+ p.expect(p.inst_param.uri+".*unregistration success")
+ p.send("q")
+ p.send("q")
+ time.sleep(0.5)
+ p.expect(const.DESTROYED, False)
+ p.wait()
+
+# Run the post test function
+if script.test.post_func != None:
+ try:
+ script.test.post_func(script.test)
+ except inc.TestError, e:
+ handle_error(e.desc, script.test, False)
+
+# Done
+print "Test " + script.test.title + " completed successfully"
+sys.exit(0)
+
diff --git a/tests/pjsua/runall.py b/tests/pjsua/runall.py
new file mode 100644
index 0000000..7aeabe0
--- /dev/null
+++ b/tests/pjsua/runall.py
@@ -0,0 +1,187 @@
+# $Id: runall.py 4183 2012-06-28 09:16:03Z nanang $
+import os
+import sys
+import time
+import re
+import shutil
+
+PYTHON = os.path.basename(sys.executable)
+
+# Usage:
+# runall.py [test-to-resume]
+
+
+# Initialize test list
+tests = []
+
+# Excluded tests (because they fail?)
+excluded_tests = [ "svn",
+ "pyc",
+ "scripts-call/150_srtp_2_1", # SRTP optional 'cannot' call SRTP mandatory
+ "scripts-call/150_srtp_2_3.py", # temporarily disabled until #1267 done
+ "scripts-call/301_ice_public_a.py", # Unreliable, proxy returns 408 sometimes
+ "scripts-call/301_ice_public_b.py", # Doesn't work because OpenSER modifies SDP
+ "scripts-pres/200_publish.py", # Ok from cmdline, error from runall.py
+ "scripts-media-playrec/100_resample_lf_8_11.py", # related to clock-rate 11 kHz problem
+ "scripts-media-playrec/100_resample_lf_8_22.py", # related to clock-rate 22 kHz problem
+ "scripts-media-playrec/100_resample_lf_11" # related to clock-rate 11 kHz problem
+ ]
+
+# Add basic tests
+for f in os.listdir("scripts-run"):
+ tests.append("mod_run.py scripts-run/" + f)
+
+# Add basic call tests
+for f in os.listdir("scripts-call"):
+ tests.append("mod_call.py scripts-call/" + f)
+
+# Add presence tests
+for f in os.listdir("scripts-pres"):
+ tests.append("mod_pres.py scripts-pres/" + f)
+
+# Add mod_sendto tests
+for f in os.listdir("scripts-sendto"):
+ tests.append("mod_sendto.py scripts-sendto/" + f)
+
+# Add mod_media_playrec tests
+for f in os.listdir("scripts-media-playrec"):
+ tests.append("mod_media_playrec.py scripts-media-playrec/" + f)
+
+# Add mod_pesq tests
+for f in os.listdir("scripts-pesq"):
+ tests.append("mod_pesq.py scripts-pesq/" + f)
+
+# Add recvfrom tests
+for f in os.listdir("scripts-recvfrom"):
+ tests.append("mod_recvfrom.py scripts-recvfrom/" + f)
+
+# Add sipp tests
+for f in os.listdir("scripts-sipp"):
+ if f.endswith(".xml"):
+ tests.append("mod_sipp.py scripts-sipp/" + f)
+
+# Filter-out excluded tests
+for pat in excluded_tests:
+ tests = [t for t in tests if t.find(pat)==-1]
+
+
+resume_script=""
+shell_cmd=""
+
+# Parse arguments
+sys.argv.pop(0)
+while len(sys.argv):
+ if sys.argv[0]=='/h' or sys.argv[0]=='-h' or sys.argv[0]=='--help' or sys.argv[0]=='/help':
+ sys.argv.pop(0)
+ print "Usage:"
+ print " runall.py [OPTIONS] [run.py-OPTIONS]"
+ print "OPTIONS:"
+ print " --list"
+ print " List the tests"
+ print " --list-xml"
+ print " List the tests as XML format suitable for ccdash"
+ print " --resume,-r RESUME"
+ print " RESUME is string/substring to specify where to resume tests."
+ print " If this argument is omited, tests will start from the beginning."
+ print " --shell,-s SHELL"
+ print " Run the tests with the specified SHELL cmd. This can also be"
+ print " used to run the test with ccdash. Example:"
+ print " --shell '/bin/sh -c'"
+ print " run.py-OPTIONS are applicable here"
+ sys.exit(0)
+ elif sys.argv[0] == '-r' or sys.argv[0] == '--resume':
+ if len(sys.argv) > 1:
+ resume_script=sys.argv[1]
+ sys.argv.pop(0)
+ sys.argv.pop(0)
+ else:
+ sys.argv.pop(0)
+ sys.stderr.write("Error: argument value required")
+ sys.exit(1)
+ elif sys.argv[0] == '--list':
+ sys.argv.pop(0)
+ for t in tests:
+ print t
+ sys.exit(0)
+ elif sys.argv[0] == '--list-xml':
+ sys.argv.pop(0)
+ for t in tests:
+ (mod,param) = t.split(None,2)
+ tname = mod[4:mod.find(".py")] + "_" + \
+ param[param.find("/")+1:param.rfind(".")]
+ c = ""
+ if len(sys.argv):
+ c = " ".join(sys.argv) + " "
+ tcmd = PYTHON + ' run.py ' + c + t
+ print '\t\t<Test name="%s" cmd="%s" wdir="tests/pjsua" />' % (tname, tcmd)
+ sys.exit(0)
+ elif sys.argv[0] == '-s' or sys.argv[0] == '--shell':
+ if len(sys.argv) > 1:
+ shell_cmd = sys.argv[1]
+ sys.argv.pop(0)
+ sys.argv.pop(0)
+ else:
+ sys.argv.pop(0)
+ sys.stderr.write("Error: argument value required")
+ sys.exit(1)
+ else:
+ # should be run.py options
+ break
+
+
+# Generate arguments for run.py
+argv_st = " ".join(sys.argv) + " "
+
+# Init vars
+fails_cnt = 0
+tests_cnt = 0
+
+# Re-create "logs" directory
+try:
+ shutil.rmtree("logs")
+except:
+ print "Warning: failed in removing directory 'logs'"
+
+try:
+ os.mkdir("logs")
+except:
+ print "Warning: failed in creating directory 'logs'"
+
+# Now run the tests
+total_cnt = len(tests)
+for t in tests:
+ if resume_script!="" and t.find(resume_script)==-1:
+ print "Skipping " + t +".."
+ total_cnt = total_cnt - 1
+ continue
+ resume_script=""
+ cmdline = "python run.py " + argv_st + t
+ if shell_cmd:
+ cmdline = "%s '%s'" % (shell_cmd, cmdline)
+ t0 = time.time()
+ msg = "Running %d/%d: %s..." % (tests_cnt+1, total_cnt, cmdline)
+ sys.stdout.write(msg)
+ sys.stdout.flush()
+ ret = os.system(cmdline + " > output.log")
+ t1 = time.time()
+ if ret != 0:
+ dur = int(t1 - t0)
+ print " failed!! [" + str(dur) + "s]"
+ logname = re.search(".*\s+(.*)", t).group(1)
+ logname = re.sub("[\\\/]", "_", logname)
+ logname = re.sub("\.py$", ".log", logname)
+ logname = re.sub("\.xml$", ".log", logname)
+ logname = "logs/" + logname
+ shutil.move("output.log", logname)
+ print "Please see '" + logname + "' for the test log."
+ fails_cnt += 1
+ else:
+ dur = int(t1 - t0)
+ print " ok [" + str(dur) + "s]"
+ tests_cnt += 1
+
+if fails_cnt == 0:
+ print "All " + str(tests_cnt) + " tests completed successfully"
+else:
+ print str(tests_cnt) + " tests completed, " + str(fails_cnt) + " test(s) failed"
+
diff --git a/tests/pjsua/scripts-call/100_simplecall.py b/tests/pjsua/scripts-call/100_simplecall.py
new file mode 100644
index 0000000..bb26bc9
--- /dev/null
+++ b/tests/pjsua/scripts-call/100_simplecall.py
@@ -0,0 +1,12 @@
+# $Id: 100_simplecall.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# Simple call
+test_param = TestParam(
+ "Basic call",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1"),
+ InstanceParam("caller", "--null-audio --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_0_1.py b/tests/pjsua/scripts-call/150_srtp_0_1.py
new file mode 100644
index 0000000..fc84d6e
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_0_1.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_0_1.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+test_param= TestParam(
+ "Callee=no SRTP, caller=optional SRTP",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_0_3.py b/tests/pjsua/scripts-call/150_srtp_0_3.py
new file mode 100644
index 0000000..59a2259
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_0_3.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_0_3.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=no SRTP, caller=optional (with duplicated offer) SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=0 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_1_0.py b/tests/pjsua/scripts-call/150_srtp_1_0.py
new file mode 100644
index 0000000..4c44e12
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_1_0.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_1_0.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional SRTP, caller=no SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_1_1.py b/tests/pjsua/scripts-call/150_srtp_1_1.py
new file mode 100644
index 0000000..9b78395
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_1_1.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_1_1.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional SRTP, caller=optional SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_1_2.py b/tests/pjsua/scripts-call/150_srtp_1_2.py
new file mode 100644
index 0000000..8c2664e
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_1_2.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_1_2.py 2025 2008-06-15 19:43:43Z bennylp $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional SRTP, caller=mandatory SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_1_3.py b/tests/pjsua/scripts-call/150_srtp_1_3.py
new file mode 100644
index 0000000..5d181a6
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_1_3.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_1_3.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional SRTP, caller=optional (with duplicated offer) SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_2_1.py b/tests/pjsua/scripts-call/150_srtp_2_1.py
new file mode 100644
index 0000000..ffd0b3c
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_2_1.py
@@ -0,0 +1,12 @@
+# $Id: 150_srtp_2_1.py 2025 2008-06-15 19:43:43Z bennylp $
+#
+from inc_cfg import *
+
+# Simple call
+test_param = TestParam(
+ "Callee=mandatory SRTP, caller=optional SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_2_2.py b/tests/pjsua/scripts-call/150_srtp_2_2.py
new file mode 100644
index 0000000..88401f8
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_2_2.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_2_2.py 2025 2008-06-15 19:43:43Z bennylp $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=mandatory SRTP, caller=mandatory SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_2_3.py b/tests/pjsua/scripts-call/150_srtp_2_3.py
new file mode 100644
index 0000000..567f567
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_2_3.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_2_3.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=mandatory SRTP, caller=optional (with duplicated offer) SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_3_0.py b/tests/pjsua/scripts-call/150_srtp_3_0.py
new file mode 100644
index 0000000..af2741c
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_3_0.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_3_0.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional (with duplicated offer) SRTP, caller=no SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=0 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_3_1.py b/tests/pjsua/scripts-call/150_srtp_3_1.py
new file mode 100644
index 0000000..1a5c3ab
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_3_1.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_3_1.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional (with duplicated offer) SRTP, caller=optional SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=1 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_3_2.py b/tests/pjsua/scripts-call/150_srtp_3_2.py
new file mode 100644
index 0000000..7175ae6
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_3_2.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_3_2.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional (with duplicated offer) SRTP, caller=mandatory SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=2 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/150_srtp_3_3.py b/tests/pjsua/scripts-call/150_srtp_3_3.py
new file mode 100644
index 0000000..1ac50e0
--- /dev/null
+++ b/tests/pjsua/scripts-call/150_srtp_3_3.py
@@ -0,0 +1,11 @@
+# $Id: 150_srtp_3_3.py 3334 2010-10-05 16:32:04Z nanang $
+#
+from inc_cfg import *
+
+test_param = TestParam(
+ "Callee=optional (with duplicated offer) SRTP, caller=optional (with duplicated offer) SRTP",
+ [
+ InstanceParam("callee", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-srtp=3 --srtp-secure=0 --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/200_tcp.py b/tests/pjsua/scripts-call/200_tcp.py
new file mode 100644
index 0000000..fafb665
--- /dev/null
+++ b/tests/pjsua/scripts-call/200_tcp.py
@@ -0,0 +1,12 @@
+# $Id: 200_tcp.py 2028 2008-06-16 13:04:44Z bennylp $
+#
+from inc_cfg import *
+
+# TCP call
+test_param = TestParam(
+ "TCP transport",
+ [
+ InstanceParam("callee", "--null-audio --no-udp --max-calls=1", uri_param=";transport=tcp"),
+ InstanceParam("caller", "--null-audio --no-udp --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/300_ice_0_1.py b/tests/pjsua/scripts-call/300_ice_0_1.py
new file mode 100644
index 0000000..c29055c
--- /dev/null
+++ b/tests/pjsua/scripts-call/300_ice_0_1.py
@@ -0,0 +1,12 @@
+# $Id: 300_ice_0_1.py 2025 2008-06-15 19:43:43Z bennylp $
+#
+from inc_cfg import *
+
+# ICE mismatch
+test_param = TestParam(
+ "Callee=no ICE, caller=use ICE",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1"),
+ InstanceParam("caller", "--null-audio --use-ice --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/300_ice_1_0.py b/tests/pjsua/scripts-call/300_ice_1_0.py
new file mode 100644
index 0000000..1d920b3
--- /dev/null
+++ b/tests/pjsua/scripts-call/300_ice_1_0.py
@@ -0,0 +1,12 @@
+# $Id: 300_ice_1_0.py 2025 2008-06-15 19:43:43Z bennylp $
+#
+from inc_cfg import *
+
+# ICE mismatch
+test_param = TestParam(
+ "Callee=use ICE, caller=no ICE",
+ [
+ InstanceParam("callee", "--null-audio --use-ice --max-calls=1"),
+ InstanceParam("caller", "--null-audio --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/300_ice_1_1.py b/tests/pjsua/scripts-call/300_ice_1_1.py
new file mode 100644
index 0000000..faed5fb
--- /dev/null
+++ b/tests/pjsua/scripts-call/300_ice_1_1.py
@@ -0,0 +1,12 @@
+# $Id: 300_ice_1_1.py 2084 2008-06-27 23:53:00Z bennylp $
+#
+from inc_cfg import *
+
+# ICE mismatch
+test_param = TestParam(
+ "Callee=use ICE, caller=use ICE",
+ [
+ InstanceParam("callee", "--null-audio --use-ice --max-calls=1", enable_buffer=True),
+ InstanceParam("caller", "--null-audio --use-ice --max-calls=1", enable_buffer=True)
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/301_ice_public_a.py b/tests/pjsua/scripts-call/301_ice_public_a.py
new file mode 100644
index 0000000..3b63a18
--- /dev/null
+++ b/tests/pjsua/scripts-call/301_ice_public_a.py
@@ -0,0 +1,22 @@
+# $Id: 301_ice_public_a.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# Note:
+# - need --dis-codec to make INVITE packet less than typical MTU
+uas_args = "--null-audio --id=\"<sip:test1@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test1 --password=test1 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --stun-srv stun.pjsip.org --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g"
+
+uac_args = "--null-audio --id=\"<sip:test2@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test2 --password=test2 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --stun-srv stun.pjsip.org --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g"
+
+test_param = TestParam(
+ "ICE via public internet",
+ [
+ InstanceParam( "callee", uas_args,
+ uri="<sip:test1@pjsip.org>",
+ have_reg=True, have_publish=False),
+ InstanceParam( "caller", uac_args,
+ uri="<sip:test2@pjsip.org>",
+ have_reg=True, have_publish=False),
+ ]
+ )
+
diff --git a/tests/pjsua/scripts-call/301_ice_public_b.py b/tests/pjsua/scripts-call/301_ice_public_b.py
new file mode 100644
index 0000000..ba54a88
--- /dev/null
+++ b/tests/pjsua/scripts-call/301_ice_public_b.py
@@ -0,0 +1,25 @@
+# $Id: 301_ice_public_b.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# This test:
+# to make call with ICE but without STUN.
+
+# Note:
+# - need --dis-codec to make INVITE packet less than typical MTU
+uas_args = "--null-audio --id=\"<sip:test1@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test1 --password=test1 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g --log-file callee.log"
+
+uac_args = "--null-audio --id=\"<sip:test2@pjsip.org>\" --registrar=sip:sip.pjsip.org --username=test2 --password=test2 --realm=pjsip.org --proxy=\"sip:sip.pjsip.org;lr\" --rtp-port 0 --use-ice --use-compact-form --max-calls 1 --dis-codec=i --dis-codec=s --dis-codec=g --log-file caller.log"
+
+test_param = TestParam(
+ "ICE via public internet with no STUN",
+ [
+ InstanceParam( "callee", uas_args,
+ uri="<sip:test1@pjsip.org>",
+ have_reg=True, have_publish=False),
+ InstanceParam( "caller", uac_args,
+ uri="<sip:test2@pjsip.org>",
+ have_reg=True, have_publish=False),
+ ]
+ )
+
diff --git a/tests/pjsua/scripts-call/305_ice_comp_1_2.py b/tests/pjsua/scripts-call/305_ice_comp_1_2.py
new file mode 100644
index 0000000..d9717e6
--- /dev/null
+++ b/tests/pjsua/scripts-call/305_ice_comp_1_2.py
@@ -0,0 +1,12 @@
+# $Id: 305_ice_comp_1_2.py 2196 2008-08-07 09:55:52Z bennylp $
+#
+from inc_cfg import *
+
+# Different number of ICE components
+test_param = TestParam(
+ "Callee=use ICE, caller=use ICE",
+ [
+ InstanceParam("callee", "--null-audio --use-ice --max-calls=1 --ice-no-rtcp", enable_buffer=True),
+ InstanceParam("caller", "--null-audio --use-ice --max-calls=1", enable_buffer=True)
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/305_ice_comp_2_1.py b/tests/pjsua/scripts-call/305_ice_comp_2_1.py
new file mode 100644
index 0000000..57bd548
--- /dev/null
+++ b/tests/pjsua/scripts-call/305_ice_comp_2_1.py
@@ -0,0 +1,12 @@
+# $Id: 305_ice_comp_2_1.py 2196 2008-08-07 09:55:52Z bennylp $
+#
+from inc_cfg import *
+
+# Different number of ICE components
+test_param = TestParam(
+ "Callee=use ICE, caller=use ICE",
+ [
+ InstanceParam("callee", "--null-audio --use-ice --max-calls=1", enable_buffer=True),
+ InstanceParam("caller", "--null-audio --use-ice --max-calls=1 --ice-no-rtcp", enable_buffer=True)
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/350_prack_a.py b/tests/pjsua/scripts-call/350_prack_a.py
new file mode 100644
index 0000000..b018473
--- /dev/null
+++ b/tests/pjsua/scripts-call/350_prack_a.py
@@ -0,0 +1,12 @@
+# $Id: 350_prack_a.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# TCP call
+test_param = TestParam(
+ "Callee requires PRACK",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1 --use-100rel"),
+ InstanceParam("caller", "--null-audio --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/350_prack_b.py b/tests/pjsua/scripts-call/350_prack_b.py
new file mode 100644
index 0000000..f2b5673
--- /dev/null
+++ b/tests/pjsua/scripts-call/350_prack_b.py
@@ -0,0 +1,12 @@
+# $Id: 350_prack_b.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# TCP call
+test_param = TestParam(
+ "Caller requires PRACK",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1"),
+ InstanceParam("caller", "--null-audio --max-calls=1 --use-100rel")
+ ]
+ )
diff --git a/tests/pjsua/scripts-call/400_tel_uri.py b/tests/pjsua/scripts-call/400_tel_uri.py
new file mode 100644
index 0000000..114208f
--- /dev/null
+++ b/tests/pjsua/scripts-call/400_tel_uri.py
@@ -0,0 +1,12 @@
+# $Id: 400_tel_uri.py 3323 2010-09-28 07:43:18Z bennylp $
+#
+from inc_cfg import *
+
+# Simple call
+test_param = TestParam(
+ "tel: URI in From",
+ [
+ InstanceParam("callee", "--null-audio --max-calls=1 --id tel:+111"),
+ InstanceParam("caller", "--null-audio --max-calls=1")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_16.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_16.py
new file mode 100644
index 0000000..40651d7
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_16.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_16.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 16 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 16000 --play-file wavs/input.11.wav --rec-file wavs/tmp.16.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_22.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_22.py
new file mode 100644
index 0000000..23e6a9e
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_22.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_22.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 22 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 22050 --play-file wavs/input.11.wav --rec-file wavs/tmp.22.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_32.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_32.py
new file mode 100644
index 0000000..0edccf8
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_32.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_32.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 32 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 32000 --play-file wavs/input.11.wav --rec-file wavs/tmp.32.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_44.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_44.py
new file mode 100644
index 0000000..455eea9
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_44.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_44.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 44 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 44100 --play-file wavs/input.11.wav --rec-file wavs/tmp.44.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_48.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_48.py
new file mode 100644
index 0000000..46c4d36
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_48.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_48.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 48 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 48000 --play-file wavs/input.11.wav --rec-file wavs/tmp.48.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_11_8.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_8.py
new file mode 100644
index 0000000..cbef3e4
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_11_8.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_11_8.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 11 KHZ to 8 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 8000 --play-file wavs/input.11.wav --rec-file wavs/tmp.8.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_11.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_11.py
new file mode 100644
index 0000000..c463203
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_11.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_11.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 11 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 11025 --play-file wavs/input.8.wav --rec-file wavs/tmp.11.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_16.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_16.py
new file mode 100644
index 0000000..9fcb870
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_16.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_16.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 16 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 16000 --play-file wavs/input.8.wav --rec-file wavs/tmp.16.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_22.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_22.py
new file mode 100644
index 0000000..37fa531
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_22.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_22.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 22 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 22050 --play-file wavs/input.8.wav --rec-file wavs/tmp.22.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_32.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_32.py
new file mode 100644
index 0000000..dfeb4b4
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_32.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_32.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 32 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 32000 --play-file wavs/input.8.wav --rec-file wavs/tmp.32.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_44.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_44.py
new file mode 100644
index 0000000..da5e570
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_44.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_44.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 44 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 44100 --play-file wavs/input.8.wav --rec-file wavs/tmp.44.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-media-playrec/100_resample_lf_8_48.py b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_48.py
new file mode 100644
index 0000000..cb314da
--- /dev/null
+++ b/tests/pjsua/scripts-media-playrec/100_resample_lf_8_48.py
@@ -0,0 +1,11 @@
+# $Id: 100_resample_lf_8_48.py 2052 2008-06-25 18:18:32Z nanang $
+#
+from inc_cfg import *
+
+# simple test
+test_param = TestParam(
+ "Resample (large filter) 8 KHZ to 48 KHZ",
+ [
+ InstanceParam("endpt", "--null-audio --quality 10 --clock-rate 48000 --play-file wavs/input.8.wav --rec-file wavs/tmp.48.wav")
+ ]
+ )
diff --git a/tests/pjsua/scripts-pesq/100_defaults.py b/tests/pjsua/scripts-pesq/100_defaults.py
new file mode 100644
index 0000000..51737ba
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/100_defaults.py
@@ -0,0 +1,19 @@
+# $Id: 100_defaults.py 3286 2010-08-18 14:30:15Z bennylp $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with default pjsua settings
+test_param = TestParam(
+ "PESQ defaults pjsua settings",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --play-file wavs/input.16.wav --no-vad"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --rec-file wavs/tmp.16.wav --clock-rate 16000 --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.8
diff --git a/tests/pjsua/scripts-pesq/101_defaults.py b/tests/pjsua/scripts-pesq/101_defaults.py
new file mode 100644
index 0000000..97e208d
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/101_defaults.py
@@ -0,0 +1,18 @@
+# $Id: 101_defaults.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with default pjsua settings
+test_param = TestParam(
+ "PESQ defaults pjsua settings (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --play-file wavs/input.16.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --rec-file wavs/tmp.16.wav --clock-rate 16000 --auto-answer 200")
+ ]
+ )
+
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = None
diff --git a/tests/pjsua/scripts-pesq/200_codec_g711a.py b/tests/pjsua/scripts-pesq/200_codec_g711a.py
new file mode 100644
index 0000000..7b73e37
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_g711a.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_g711a.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with PCMA codec
+test_param = TestParam(
+ "PESQ codec PCMA",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec pcma --clock-rate 8000 --play-file wavs/input.8.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec pcma --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/200_codec_g711u.py b/tests/pjsua/scripts-pesq/200_codec_g711u.py
new file mode 100644
index 0000000..acb0147
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_g711u.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_g711u.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with PCMU codec
+test_param = TestParam(
+ "PESQ codec PCMU",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec pcmu --clock-rate 8000 --play-file wavs/input.8.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec pcmu --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/200_codec_g722.py b/tests/pjsua/scripts-pesq/200_codec_g722.py
new file mode 100644
index 0000000..30b14b2
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_g722.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_g722.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with G722 codec
+test_param = TestParam(
+ "PESQ codec G722",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec g722 --clock-rate 16000 --play-file wavs/input.16.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec g722 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.7
diff --git a/tests/pjsua/scripts-pesq/200_codec_gsm.py b/tests/pjsua/scripts-pesq/200_codec_gsm.py
new file mode 100644
index 0000000..2be167a
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_gsm.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_gsm.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with GSM codec
+test_param = TestParam(
+ "PESQ codec GSM",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec gsm --clock-rate 8000 --play-file wavs/input.8.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec gsm --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.0
diff --git a/tests/pjsua/scripts-pesq/200_codec_ilbc.py b/tests/pjsua/scripts-pesq/200_codec_ilbc.py
new file mode 100644
index 0000000..aff193c
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_ilbc.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_ilbc.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with iLBC codec
+test_param = TestParam(
+ "PESQ codec iLBC",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec ilbc --clock-rate 8000 --play-file wavs/input.8.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec ilbc --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.0
diff --git a/tests/pjsua/scripts-pesq/200_codec_l16_16000.py b/tests/pjsua/scripts-pesq/200_codec_l16_16000.py
new file mode 100644
index 0000000..dc202fa
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_l16_16000.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_l16_16000.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with L16/16000/1 codec
+test_param = TestParam(
+ "PESQ codec L16/16000/1",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --play-file wavs/input.16.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/200_codec_l16_16000_stereo.py b/tests/pjsua/scripts-pesq/200_codec_l16_16000_stereo.py
new file mode 100644
index 0000000..4dbc132
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_l16_16000_stereo.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_l16_16000_stereo.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with L16/16000/2 codec
+test_param = TestParam(
+ "PESQ defaults pjsua settings",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --play-file wavs/input.2.16.wav"),
+ InstanceParam("UA2", "--null-audio --stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --rec-file wavs/tmp.2.16.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = None
diff --git a/tests/pjsua/scripts-pesq/200_codec_l16_8000.py b/tests/pjsua/scripts-pesq/200_codec_l16_8000.py
new file mode 100644
index 0000000..34a9bb2
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_l16_8000.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_l16_8000.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with L16/8000/1 codec
+test_param = TestParam(
+ "PESQ codec L16/8000/1",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --play-file wavs/input.8.wav"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/200_codec_l16_8000_stereo.py b/tests/pjsua/scripts-pesq/200_codec_l16_8000_stereo.py
new file mode 100644
index 0000000..755050e
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_l16_8000_stereo.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_l16_8000_stereo.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with L16/8000/2 codec
+test_param = TestParam(
+ "PESQ defaults pjsua settings",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --play-file wavs/input.2.8.wav"),
+ InstanceParam("UA2", "--null-audio --stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --rec-file wavs/tmp.2.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = None
diff --git a/tests/pjsua/scripts-pesq/200_codec_speex_16000.py b/tests/pjsua/scripts-pesq/200_codec_speex_16000.py
new file mode 100644
index 0000000..bdacba9
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_speex_16000.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_speex_16000.py 3286 2010-08-18 14:30:15Z bennylp $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with Speex/16000 codec
+test_param = TestParam(
+ "PESQ codec Speex WB",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --clock-rate 16000 --add-codec speex/16000 --play-file wavs/input.16.wav --no-vad"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --clock-rate 16000 --add-codec speex/16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.8
diff --git a/tests/pjsua/scripts-pesq/200_codec_speex_8000.py b/tests/pjsua/scripts-pesq/200_codec_speex_8000.py
new file mode 100644
index 0000000..9c7c7df
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/200_codec_speex_8000.py
@@ -0,0 +1,19 @@
+# $Id: 200_codec_speex_8000.py 3286 2010-08-18 14:30:15Z bennylp $
+#
+from inc_cfg import *
+
+ADD_PARAM = ""
+
+if (HAS_SND_DEV == 0):
+ ADD_PARAM += "--null-audio"
+
+# Call with Speex/8000 codec
+test_param = TestParam(
+ "PESQ codec Speex NB",
+ [
+ InstanceParam("UA1", ADD_PARAM + " --max-calls=1 --add-codec speex/8000 --clock-rate 8000 --play-file wavs/input.8.wav --no-vad"),
+ InstanceParam("UA2", "--null-audio --max-calls=1 --add-codec speex/8000 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+pesq_threshold = 3.65
diff --git a/tests/pjsua/scripts-pesq/201_codec_g711a.py b/tests/pjsua/scripts-pesq/201_codec_g711a.py
new file mode 100644
index 0000000..7e7e744
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_g711a.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_g711a.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with PCMA codec
+test_param = TestParam(
+ "PESQ codec PCMA (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec pcma --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec pcma --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/201_codec_g711u.py b/tests/pjsua/scripts-pesq/201_codec_g711u.py
new file mode 100644
index 0000000..77f9e22
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_g711u.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_g711u.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with PCMU codec
+test_param = TestParam(
+ "PESQ codec PCMU (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec pcmu --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec pcmu --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/201_codec_g722.py b/tests/pjsua/scripts-pesq/201_codec_g722.py
new file mode 100644
index 0000000..ce959a0
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_g722.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_g722.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with G722 codec
+test_param = TestParam(
+ "PESQ codec G722 (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec g722 --clock-rate 16000 --play-file wavs/input.16.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec g722 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.7
diff --git a/tests/pjsua/scripts-pesq/201_codec_gsm.py b/tests/pjsua/scripts-pesq/201_codec_gsm.py
new file mode 100644
index 0000000..44443b0
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_gsm.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_gsm.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with GSM codec
+test_param = TestParam(
+ "PESQ codec GSM (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec gsm --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec gsm --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.0
diff --git a/tests/pjsua/scripts-pesq/201_codec_ilbc.py b/tests/pjsua/scripts-pesq/201_codec_ilbc.py
new file mode 100644
index 0000000..b04a8c2
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_ilbc.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_ilbc.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with iLBC codec
+test_param = TestParam(
+ "PESQ codec iLBC (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec ilbc --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec ilbc --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.0
diff --git a/tests/pjsua/scripts-pesq/201_codec_l16_16000.py b/tests/pjsua/scripts-pesq/201_codec_l16_16000.py
new file mode 100644
index 0000000..efd7744
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_l16_16000.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_l16_16000.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+# Call with L16/16000/1 codec
+test_param = TestParam(
+ "PESQ codec L16/16000/1 (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --play-file wavs/input.16.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec L16/16000/1 --clock-rate 16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/201_codec_l16_16000_stereo.py b/tests/pjsua/scripts-pesq/201_codec_l16_16000_stereo.py
new file mode 100644
index 0000000..c312218
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_l16_16000_stereo.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_l16_16000_stereo.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+# Call with L16/16000/2 codec
+test_param = TestParam(
+ "PESQ defaults pjsua settings",
+ [
+ InstanceParam("UA1", "--stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --play-file wavs/input.2.16.wav --null-audio"),
+ InstanceParam("UA2", "--stereo --max-calls=1 --clock-rate 16000 --add-codec L16/16000/2 --rec-file wavs/tmp.2.16.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = None
diff --git a/tests/pjsua/scripts-pesq/201_codec_l16_8000.py b/tests/pjsua/scripts-pesq/201_codec_l16_8000.py
new file mode 100644
index 0000000..90e2de9
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_l16_8000.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_l16_8000.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+# Call with L16/8000/1 codec
+test_param = TestParam(
+ "PESQ codec L16/8000/1 (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec L16/8000/1 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.5
diff --git a/tests/pjsua/scripts-pesq/201_codec_l16_8000_stereo.py b/tests/pjsua/scripts-pesq/201_codec_l16_8000_stereo.py
new file mode 100644
index 0000000..434a4ea
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_l16_8000_stereo.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_l16_8000_stereo.py 2075 2008-06-27 16:18:13Z nanang $
+#
+from inc_cfg import *
+
+# Call with L16/8000/2 codec
+test_param = TestParam(
+ "PESQ defaults pjsua settings",
+ [
+ InstanceParam("UA1", "--stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --play-file wavs/input.2.8.wav --null-audio"),
+ InstanceParam("UA2", "--stereo --max-calls=1 --clock-rate 8000 --add-codec L16/8000/2 --rec-file wavs/tmp.2.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = None
diff --git a/tests/pjsua/scripts-pesq/201_codec_speex_16000.py b/tests/pjsua/scripts-pesq/201_codec_speex_16000.py
new file mode 100644
index 0000000..92f3ccc
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_speex_16000.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_speex_16000.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with Speex/16000 codec
+test_param = TestParam(
+ "PESQ codec Speex WB (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --clock-rate 16000 --add-codec speex/16000 --play-file wavs/input.16.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --clock-rate 16000 --add-codec speex/16000 --rec-file wavs/tmp.16.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.7
diff --git a/tests/pjsua/scripts-pesq/201_codec_speex_8000.py b/tests/pjsua/scripts-pesq/201_codec_speex_8000.py
new file mode 100644
index 0000000..b48dcba
--- /dev/null
+++ b/tests/pjsua/scripts-pesq/201_codec_speex_8000.py
@@ -0,0 +1,17 @@
+# $Id: 201_codec_speex_8000.py 2063 2008-06-26 18:52:16Z nanang $
+#
+from inc_cfg import *
+
+# Call with Speex/8000 codec
+test_param = TestParam(
+ "PESQ codec Speex NB (RX side uses snd dev)",
+ [
+ InstanceParam("UA1", "--max-calls=1 --add-codec speex/8000 --clock-rate 8000 --play-file wavs/input.8.wav --null-audio"),
+ InstanceParam("UA2", "--max-calls=1 --add-codec speex/8000 --clock-rate 8000 --rec-file wavs/tmp.8.wav --auto-answer 200")
+ ]
+ )
+
+if (HAS_SND_DEV == 0):
+ test_param.skip = True
+
+pesq_threshold = 3.0
diff --git a/tests/pjsua/scripts-pres/100_peertopeer.py b/tests/pjsua/scripts-pres/100_peertopeer.py
new file mode 100644
index 0000000..a35f981
--- /dev/null
+++ b/tests/pjsua/scripts-pres/100_peertopeer.py
@@ -0,0 +1,12 @@
+# $Id: 100_peertopeer.py 2392 2008-12-22 18:54:58Z bennylp $
+#
+from inc_cfg import *
+
+# Direct peer to peer presence
+test_param = TestParam(
+ "Direct peer to peer presence",
+ [
+ InstanceParam("client1", "--null-audio"),
+ InstanceParam("client2", "--null-audio")
+ ]
+ )
diff --git a/tests/pjsua/scripts-pres/200_publish.py b/tests/pjsua/scripts-pres/200_publish.py
new file mode 100644
index 0000000..d06b190
--- /dev/null
+++ b/tests/pjsua/scripts-pres/200_publish.py
@@ -0,0 +1,35 @@
+# $Id: 200_publish.py 2028 2008-06-16 13:04:44Z bennylp $
+#
+from inc_cfg import *
+
+# Basic registration
+test_param = TestParam(
+ "Presence with PUBLISH",
+ [
+ InstanceParam( "ua1",
+ "--null-audio"+
+ " --id=\"<sip:test1@pjsip.org>\""+
+ " --registrar=sip:sip.pjsip.org" +
+ " --username=test1" +
+ " --password=test1" +
+ " --realm=*" +
+ " --proxy=\"sip:sip.pjsip.org;lr\"" +
+ " --publish",
+ uri="<sip:test1@pjsip.org>",
+ have_reg=True,
+ have_publish=True),
+ InstanceParam( "ua2",
+ "--null-audio"+
+ " --id=\"<sip:test2@pjsip.org>\""+
+ " --registrar=sip:sip.pjsip.org" +
+ " --username=test2" +
+ " --password=test2" +
+ " --realm=*" +
+ " --proxy=\"sip:sip.pjsip.org;lr\"" +
+ " --publish",
+ uri="<sip:test2@pjsip.org>",
+ have_reg=True,
+ have_publish=True),
+ ]
+ )
+
diff --git a/tests/pjsua/scripts-recvfrom/100_simple.py b/tests/pjsua/scripts-recvfrom/100_simple.py
new file mode 100644
index 0000000..7f65ee1
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/100_simple.py
@@ -0,0 +1,16 @@
+# $Id: 100_simple.py 3284 2010-08-18 07:38:48Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Registration", 200,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["Server: Snake Registrar", "Expires: 221", "Contact: sip:localhost"],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Simple registration test",
+ pjsua, [req1])
diff --git a/tests/pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py b/tests/pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py
new file mode 100644
index 0000000..3df45db
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/200_reg_good_enocredentiall.py
@@ -0,0 +1,15 @@
+# $Id: 200_reg_good_enocredentiall.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT"
+
+req1 = sip.RecvfromTransaction("", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="PJSIP_ENOCREDENTIAL"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration test",
+ pjsua, [req1])
diff --git a/tests/pjsua/scripts-recvfrom/201_reg_good_ok.py b/tests/pjsua/scripts-recvfrom/201_reg_good_ok.py
new file mode 100644
index 0000000..c6f524a
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/201_reg_good_ok.py
@@ -0,0 +1,23 @@
+# $Id: 201_reg_good_ok.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--username user --realm python --password passwd --auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial registration", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="SIP/2.0 401"
+ )
+
+req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
+ include=["REGISTER sip", "Authorization:",
+ "realm=\"python\"", "username=\"user\"",
+ "nonce=\"1234\"", "response="],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Successful registration test",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py b/tests/pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py
new file mode 100644
index 0000000..524d4cd
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/202_reg_good_ok_wildcard.py
@@ -0,0 +1,23 @@
+# $Id: 202_reg_good_ok_wildcard.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--username user --realm \"*\" --password passwd --auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial registration", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="SIP/2.0 401"
+ )
+
+req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
+ include=["REGISTER sip", "Authorization:",
+ "realm=\"python\"", "username=\"user\"",
+ "nonce=\"1234\"", "response="],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Successful registration with wildcard realm test",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/203_reg_good_empty_realm.py b/tests/pjsua/scripts-recvfrom/203_reg_good_empty_realm.py
new file mode 100644
index 0000000..e936438
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/203_reg_good_empty_realm.py
@@ -0,0 +1,31 @@
+# $Id: 203_reg_good_empty_realm.py 3150 2010-04-29 00:23:43Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=* --user=username --password=password " + \
+ "--auto-update-nat=0"
+
+# 401 Response, missing realm value
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=['WWW-Authenticate: Digest']
+ )
+
+# Client should retry, we giving it another 401 with empty realm
+req2 = sip.RecvfromTransaction("REGISTER retry #1 of 2", 407,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=['Proxy-Authenticate: Digest realm=""']
+ )
+
+# Client should retry
+req3 = sip.RecvfromTransaction("REGISTER retry #2 of 2", 200,
+ include=[],
+ exclude=[],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Registration with empty realm",
+ pjsua, [req1, req2, req3])
diff --git a/tests/pjsua/scripts-recvfrom/205_reg_good_no_realm.py b/tests/pjsua/scripts-recvfrom/205_reg_good_no_realm.py
new file mode 100644
index 0000000..5343854
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/205_reg_good_no_realm.py
@@ -0,0 +1,16 @@
+# $Id: 205_reg_good_no_realm.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=provider --user=username --password=password"
+
+req1 = sip.RecvfromTransaction("", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="PJSIP_ENOCREDENTIAL"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration because of realm test",
+ pjsua, [req1])
diff --git a/tests/pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py b/tests/pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py
new file mode 100644
index 0000000..9cd5ecb
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/206_reg_good_efailedcredential.py
@@ -0,0 +1,26 @@
+# $Id: 206_reg_good_efailedcredential.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Authentication failure test with same nonce
+
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password"
+
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
+ )
+
+req2 = sip.RecvfromTransaction("REGISTER retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"1\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""],
+ expect="PJSIP_EFAILEDCREDENTIAL"
+ )
+
+
+recvfrom_cfg = sip.RecvfromCfg("Authentication failure with same nonce",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py b/tests/pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py
new file mode 100644
index 0000000..ef862d0
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/208_reg_good_retry_nonce_ok.py
@@ -0,0 +1,29 @@
+# $Id: 208_reg_good_retry_nonce_ok.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
+ )
+
+req2 = sip.RecvfromTransaction("REGISTER first retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"1\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"]
+ )
+
+
+req3 = sip.RecvfromTransaction("REGISTER retry with new nonce", 200,
+ include=["REGISTER sip", "Authorization", "nonce=\"2\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Authentication okay after retry with new nonce",
+ pjsua, [req1, req2, req3])
diff --git a/tests/pjsua/scripts-recvfrom/209a_reg_handle_423_ok.py b/tests/pjsua/scripts-recvfrom/209a_reg_handle_423_ok.py
new file mode 100644
index 0000000..2b57342
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/209a_reg_handle_423_ok.py
@@ -0,0 +1,31 @@
+# $Id: 209a_reg_handle_423_ok.py 3105 2010-02-23 11:03:07Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0"
+
+# 423 Response without Min-Expires header
+req1 = sip.RecvfromTransaction("Initial request", 423,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=[]
+ )
+
+# Client should retry with Expires header containing special value (pjsip specific)
+req2 = sip.RecvfromTransaction("REGISTER retry after 423 response without Min-Expires header", 423,
+ include=["REGISTER sip", "Expires: 3601"],
+ exclude=[],
+ resp_hdr=["Min-Expires: 3612"]
+ )
+
+# Client should retry with proper Expires header now
+req3 = sip.RecvfromTransaction("REGISTER retry after proper 423", 200,
+ include=["Expires: 3612"],
+ exclude=[],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Reregistration after 423 response",
+ pjsua, [req1, req2, req3])
diff --git a/tests/pjsua/scripts-recvfrom/209b_reg_handle_423_bad_min_expires1.py b/tests/pjsua/scripts-recvfrom/209b_reg_handle_423_bad_min_expires1.py
new file mode 100644
index 0000000..3c22109
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/209b_reg_handle_423_bad_min_expires1.py
@@ -0,0 +1,20 @@
+# $Id: 209b_reg_handle_423_bad_min_expires1.py 3105 2010-02-23 11:03:07Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0 --reg-timeout 300"
+
+# 423 Response with Min-Expires header that is lower than what the client
+# had requested
+req1 = sip.RecvfromTransaction("Initial request", 423,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=["Min-Expires: 250"],
+ expect="invalid Min-Expires"
+
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Invalid 423 response to REGISTER",
+ pjsua, [req1])
diff --git a/tests/pjsua/scripts-recvfrom/209c_reg_handle_423_bad_min_expires2.py b/tests/pjsua/scripts-recvfrom/209c_reg_handle_423_bad_min_expires2.py
new file mode 100644
index 0000000..68fda46
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/209c_reg_handle_423_bad_min_expires2.py
@@ -0,0 +1,25 @@
+# $Id: 209c_reg_handle_423_bad_min_expires2.py 3105 2010-02-23 11:03:07Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0 --reg-timeout 300"
+
+# 423 without Min-Expires. PJSIP would retry with Expires: 3601
+req1 = sip.RecvfromTransaction("Initial request", 423,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=[]
+ )
+
+# Another 423, still without Min-Expires
+req2 = sip.RecvfromTransaction("Retry with guessed Expires header", 423,
+ include=["REGISTER sip", "Expires: 3601"],
+ exclude=[],
+ resp_hdr=[],
+ expect="without Min-Expires header is invalid"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Invalid 423 response to REGISTER",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py b/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
new file mode 100644
index 0000000..4b63a5e
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/215_reg_good_multi_ok.py
@@ -0,0 +1,28 @@
+# $Id: 215_reg_good_multi_ok.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--username theuser1 --realm python1 --password passwd --next-cred " + \
+ "--username theuser2 --realm python2 --password passwd " + \
+ "--auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial registration", 401,
+ include=["REGISTER sip"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python1\", nonce=\"1234\"",
+ "WWW-Authenticate: Digest realm=\"python2\", nonce=\"6789\""],
+ expect="SIP/2.0 401"
+ )
+
+req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
+ include=["REGISTER sip",
+ "Authorization:[\\s\\S]+Authorization:", # Must have 2 Auth hdrs
+ "realm=\"python1\"", "realm=\"python2\"",
+ "username=\"theuser1\"", "username=\"theuser2\"",
+ "nonce=\"1234\"", "nonce=\"6789\"",
+ "response="],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Multiple authentication challenges",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/220_reg_good_ims_ok.py b/tests/pjsua/scripts-recvfrom/220_reg_good_ims_ok.py
new file mode 100644
index 0000000..4d1ff16
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/220_reg_good_ims_ok.py
@@ -0,0 +1,26 @@
+# $Id: 220_reg_good_ims_ok.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--username user@ims-domain --realm python --password passwd --use-ims --auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial registration", 401,
+ include=["REGISTER sip", "Authorization",
+ "username=\"user@ims-domain\"",
+ "realm=\"python\""],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="SIP/2.0 401"
+ )
+
+req2 = sip.RecvfromTransaction("Registration retry with auth", 200,
+ include=["REGISTER sip", "Authorization:",
+ "realm=\"python\"", "username=\"user@ims-domain\"",
+ "nonce=\"1234\"", "response="],
+ # Must not have double Authorization header:
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Successful IMS registration test",
+ pjsua, [req1, req2])
diff --git a/tests/pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py b/tests/pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py
new file mode 100644
index 0000000..cfd7d00
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/230_reg_bad_fail_stale_true.py
@@ -0,0 +1,41 @@
+# $Id: 230_reg_bad_fail_stale_true.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# In this test we simulate broken server, where it always sends
+# stale=true with all 401 responses. We should expect pjsip to
+# retry the authentication until PJSIP_MAX_STALE_COUNT is
+# exceeded. When pjsip retries the authentication, it should
+# use the new nonce from server
+
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password"
+
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
+ )
+
+req2 = sip.RecvfromTransaction("First retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"1\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"]
+ )
+
+req3 = sip.RecvfromTransaction("Second retry retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"2\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\", stale=true"]
+ )
+
+req4 = sip.RecvfromTransaction("Third retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"3\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"4\", stale=true"],
+ expect="PJSIP_EAUTHSTALECOUNT"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration retry (server rejects with stale=true) ",
+ pjsua, [req1, req2, req3, req4])
diff --git a/tests/pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py b/tests/pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py
new file mode 100644
index 0000000..ed47d29
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/231_reg_bad_fail_stale_false_nonce_changed.py
@@ -0,0 +1,41 @@
+# $Id: 231_reg_bad_fail_stale_false_nonce_changed.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# In this test we simulate broken server, where:
+# - it wants to signal that NONCE has change
+# - but it sets stale=false
+# For this case pjsip will retry authentication until
+# PJSIP_MAX_STALE_COUNT is exceeded.
+#
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password"
+
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
+ )
+
+req2 = sip.RecvfromTransaction("First retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"1\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\", stale=true"]
+ )
+
+req3 = sip.RecvfromTransaction("Second retry retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"2\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\", stale=true"]
+ )
+
+req4 = sip.RecvfromTransaction("Third retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"3\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"4\", stale=true"],
+ expect="PJSIP_EAUTHSTALECOUNT"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration retry (server rejects with stale=true) ",
+ pjsua, [req1, req2, req3, req4])
diff --git a/tests/pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py b/tests/pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py
new file mode 100644
index 0000000..e50da60
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/234_reg_bad_stale_ok.py
@@ -0,0 +1,41 @@
+# $Id: 234_reg_bad_stale_ok.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# In this test we simulate broken server, where it wants to
+# change the nonce, but it fails to set stale to true. In this
+# case, we should expect pjsip to retry the authentication until
+# PJSIP_MAX_STALE_COUNT is exceeded as it should have detected
+# that that nonce has changed
+
+
+pjsua = "--null-audio --id=sip:CLIENT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0"
+
+req1 = sip.RecvfromTransaction("Initial request", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1\""]
+ )
+
+req2 = sip.RecvfromTransaction("First retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"1\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"2\""]
+ )
+
+req3 = sip.RecvfromTransaction("Second retry retry", 401,
+ include=["REGISTER sip", "Authorization", "nonce=\"2\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"3\""]
+ )
+
+req4 = sip.RecvfromTransaction("Third retry", 200,
+ include=["REGISTER sip", "Authorization", "nonce=\"3\""],
+ exclude=["Authorization:[\\s\\S]+Authorization:"],
+ expect="registration success"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Successful auth server changes nonce but with stale=false",
+ pjsua, [req1, req2, req3, req4])
diff --git a/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py b/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py
new file mode 100644
index 0000000..c15a77b
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/235_reg_good_tel_uri_enocredential.py
@@ -0,0 +1,15 @@
+# $Id: 235_reg_good_tel_uri_enocredential.py 3323 2010-09-28 07:43:18Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+pjsua = "--null-audio --id=tel:+12345 --registrar sip:127.0.0.1:$PORT"
+
+req1 = sip.RecvfromTransaction("", 401,
+ include=["REGISTER sip"],
+ exclude=["Authorization"],
+ resp_hdr=["WWW-Authenticate: Digest realm=\"python\", nonce=\"1234\""],
+ expect="PJSIP_ENOCREDENTIAL"
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Failed registration with tel: URI test",
+ pjsua, [req1])
diff --git a/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py b/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py
new file mode 100644
index 0000000..bd9a51d
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/240_publish_scenarios.py
@@ -0,0 +1,51 @@
+# $Id: 240_publish_scenarios.py 2661 2009-04-28 22:19:49Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Several PUBLISH failure scenarios that should be handled automatically
+
+
+pjsua = "--null-audio --id=sip:127.0.0.1:$PORT --registrar sip:127.0.0.1:$PORT " + \
+ "--realm=python --user=username --password=password " + \
+ "--auto-update-nat=0 --publish"
+#pjsua = "--null-audio --local-port 0 --rtp-port 0"
+
+# Handle REGISTER first
+req1 = sip.RecvfromTransaction("Initial REGISTER", 200,
+ include=["REGISTER sip"],
+ exclude=[],
+ resp_hdr=["Expires: 1800"]
+ )
+
+# First PUBLISH, reply with 412
+req2 = sip.RecvfromTransaction("Initial PUBLISH, will be replied with 412", 412,
+ include=["PUBLISH sip"],
+ exclude=["Expires:"]
+ )
+
+# Second PUBLISH
+req3 = sip.RecvfromTransaction("Second PUBLISH, will be replied with 200", 200,
+ include=["PUBLISH sip"],
+ exclude=["Expires:"],
+ resp_hdr=["Expires: 60", "SIP-ETag: dx200xyz"]
+ )
+
+# PUBLISH refresh, respond with 408
+req4 = sip.RecvfromTransaction("PUBLISH refresh, will be replied with 408", 408,
+ include=["PUBLISH sip", "SIP-If-Match: dx200xyz"],
+ exclude=["Expires:"],
+ resp_hdr=["Expires: 60", "SIP-ETag: dx200xyz"]
+ )
+
+# After 5 minutes, pjsua should retry again
+req5 = sip.RecvfromTransaction("PUBLISH retry", 200,
+ include=["PUBLISH sip"],
+ exclude=["Expires:", "SIP-If-Match:"],
+ resp_hdr=["Expires: 60", "SIP-ETag: abc"]
+ )
+
+
+
+recvfrom_cfg = sip.RecvfromCfg("PUBLISH scenarios",
+ pjsua, [req1, req2, req3])
+
diff --git a/tests/pjsua/scripts-recvfrom/300_timer_good.py b/tests/pjsua/scripts-recvfrom/300_timer_good.py
new file mode 100644
index 0000000..4281141
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/300_timer_good.py
@@ -0,0 +1,17 @@
+# $Id: 300_timer_good.py 3307 2010-09-08 05:38:49Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# INVITE session using session timer
+
+pjsua = "--null-audio sip:127.0.0.1:$PORT --use-timer 2 --timer-min-se 100 --timer-se 2000"
+
+req = sip.RecvfromTransaction("INVITE with session timer", 200,
+ include=["Session-Expires:\s*2000", "Min-SE:\s*100"],
+ exclude=[],
+ resp_hdr=["Session-Expires: 1000;refresher=uac"]
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("INVITE session using session timer",
+ pjsua, [req])
+
diff --git a/tests/pjsua/scripts-recvfrom/301_timer_good_retry_after_422.py b/tests/pjsua/scripts-recvfrom/301_timer_good_retry_after_422.py
new file mode 100644
index 0000000..3bd8a57
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/301_timer_good_retry_after_422.py
@@ -0,0 +1,30 @@
+# $Id: 301_timer_good_retry_after_422.py 3287 2010-08-18 14:30:17Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Session timers retry after 422
+
+
+pjsua = "--null-audio sip:127.0.0.1:$PORT --timer-min-se 100 --timer-se 1000"
+
+# First INVITE with timer rejected with 422
+req1 = sip.RecvfromTransaction("INVITE with SE too small", 422,
+ include=["Session-Expires:\s*1000"],
+ exclude=[],
+ resp_hdr=["Min-SE: 2000"]
+ )
+
+# Wait for ACK
+req2 = sip.RecvfromTransaction("Wait ACK", 0, include=["ACK sip"])
+
+# New INVITE with SE >= Min-SE
+req3 = sip.RecvfromTransaction("Retrying with acceptable SE", 200,
+ include=["Session-Expires:\s*2000", "Min-SE:\s*2000"],
+ exclude=[],
+ resp_hdr=["Session-Expires: 2000;refresher=uac"]
+ )
+
+
+recvfrom_cfg = sip.RecvfromCfg("Session timers retry after 422",
+ pjsua, [req1, req2, req3])
+
diff --git a/tests/pjsua/scripts-recvfrom/400_inv_answered_with_less_media.py b/tests/pjsua/scripts-recvfrom/400_inv_answered_with_less_media.py
new file mode 100644
index 0000000..2fd8c7f
--- /dev/null
+++ b/tests/pjsua/scripts-recvfrom/400_inv_answered_with_less_media.py
@@ -0,0 +1,32 @@
+# $Id: 400_inv_answered_with_less_media.py 3716 2011-08-19 12:24:48Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Offer with 2 media lines answered with only 1 media line
+
+pjsua = "--null-audio sip:127.0.0.1:$PORT --id=sip:1000@localhost --extra-audio --use-srtp=0"
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+req = sip.RecvfromTransaction("Receiving 2 media lines, answer with 1 media line", 200,
+ include=["m=audio \d+ RTP/AVP", "m=audio \d+ RTP/AVP"],
+ exclude=[],
+ resp_hdr=["Content-type: application/sdp"],
+ resp_body=sdp,
+ )
+
+recvfrom_cfg = sip.RecvfromCfg("Receiving answer with less media lines",
+ pjsua, [req])
+
diff --git a/tests/pjsua/scripts-run/100_simple.py b/tests/pjsua/scripts-run/100_simple.py
new file mode 100644
index 0000000..ed1b316
--- /dev/null
+++ b/tests/pjsua/scripts-run/100_simple.py
@@ -0,0 +1,13 @@
+# $Id: 100_simple.py 2028 2008-06-16 13:04:44Z bennylp $
+#
+# Just about the simple pjsua command line parameter, which should
+# never fail in any circumstances
+from inc_cfg import *
+
+test_param = TestParam(
+ "Basic run",
+ [
+ InstanceParam("pjsua", "--null-audio --rtp-port 0")
+ ]
+ )
+
diff --git a/tests/pjsua/scripts-run/200_register.py b/tests/pjsua/scripts-run/200_register.py
new file mode 100644
index 0000000..1ce0c26
--- /dev/null
+++ b/tests/pjsua/scripts-run/200_register.py
@@ -0,0 +1,20 @@
+# $Id: 200_register.py 2028 2008-06-16 13:04:44Z bennylp $
+#
+from inc_cfg import *
+
+# Basic registration
+test_param = TestParam(
+ "Basic registration",
+ [
+ InstanceParam( "client",
+ "--null-audio"+
+ " --id=\"<sip:test1@pjsip.org>\""+
+ " --registrar=sip:sip.pjsip.org" +
+ " --username=test1" +
+ " --password=test1" +
+ " --realm=*",
+ uri="sip:test1@pjsip.org",
+ have_reg=True),
+ ]
+ )
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py
new file mode 100644
index 0000000..f33a17d
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_1.py
@@ -0,0 +1,52 @@
+# $Id: 001_torture_4475_3_1_1_1.py 2505 2009-03-12 11:25:11Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1. Valid Messages
+# 3.1.1.1. A Short Tortuous INVITE
+complete_msg = \
+"""INVITE sip:vivekg@chair-dnrc.example.com;unknownparam SIP/2.0
+TO :
+ sip:vivekg@chair-dnrc.example.com ; tag = 1918181833n
+from : "J Rosenberg \\\\\\"" <sip:jdrosen@example.com>
+ ;
+ tag = 98asjd8
+MaX-fOrWaRdS: 0068
+Call-ID: wsinv.ndaksdj@192.0.2.1
+Content-Length : 150
+cseq: 0009
+ INVITE
+Via : SIP / 2.0
+ /UDP
+ 192.0.2.2;rport;branch=390skdjuw
+s :
+NewFangledHeader: newfangled value
+ continued newfangled value
+UnknownHeaderWithUnusualValue: ;;,,;;,;
+Content-Type: application/sdp
+Route:
+ <sip:services.example.com;lr;unknownwith=value;unknown-no-value>
+v: SIP / 2.0 / TCP spindle.example.com ;
+ branch = z9hG4bK9ikj8 ,
+ SIP / 2.0 / UDP 192.168.255.111 ; branch=
+ z9hG4bK30239
+m:"Quoted string \\"\\"" <sip:jdrosen@example.com> ; newparam =
+ newvalue ;
+ secondparam ; q = 0.33
+
+v=0
+o=mhandley 29739 7272939 IN IP4 192.0.2.3
+s=-
+c=IN IP4 192.0.2.4
+t=0 0
+m=audio 49217 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.1",
+ "--null-audio --auto-answer 200",
+ "", 481, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py
new file mode 100644
index 0000000..e5b08ef
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_2.py
@@ -0,0 +1,25 @@
+# $Id: 001_torture_4475_3_1_1_2.py 2505 2009-03-12 11:25:11Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1. Valid Messages
+# 3.1.1.2. Wide Range of Valid Characters
+complete_msg = \
+"""!interesting-Method0123456789_*+`.%indeed'~ sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*:&it+has=1,weird!*pas$wo~d_too.(doesn't-it)@example.com SIP/2.0
+Via: SIP/2.0/UDP host1.example.com;rport;branch=z9hG4bK-.!%66*_+`'~
+To: "BEL:\\\x07 NUL:\\\x00 DEL:\\\x7F" <sip:1_unusual.URI~(to-be!sure)&isn't+it$/crazy?,/;;*@example.com>
+From: token1~` token2'+_ token3*%!.- <sip:mundane@example.com> ;fromParam''~+*_!.-%="\xD1\x80\xD0\xB0\xD0\xB1\xD0\xBE\xD1\x82\xD0\xB0\xD1\x8E\xD1\x89\xD0\xB8\xD0\xB9";tag=_token~1'+`*%!-.
+Call-ID: intmeth.word%ZK-!.*_+'@word`~)(><:\\/"][?}{
+CSeq: 139122385 !interesting-Method0123456789_*+`.%indeed'~
+Max-Forwards: 255
+extensionHeader-!.%*+_`'~: \xEF\xBB\xBF\xE5\xA4\xA7\xE5\x81\x9C\xE9\x9B\xBB
+Content-Length: 0
+
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.2",
+ "--null-audio --auto-answer 200",
+ "", 405, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py
new file mode 100644
index 0000000..5e5848b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_3.py
@@ -0,0 +1,35 @@
+# $Id: 001_torture_4475_3_1_1_3.py 2505 2009-03-12 11:25:11Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1. Valid Messages
+# 3.1.1.3. Valid Use of the % Escaping Mechanism
+complete_msg = \
+"""INVITE sip:sips%3Auser%40example.com@example.net SIP/2.0
+To: sip:%75se%72@example.com
+From: <sip:I%20have%20spaces@example.net>;tag=$FROM_TAG
+Max-Forwards: 87
+i: esc01.239409asdfakjkn23onasd0-3234
+CSeq: 234234 INVITE
+Via: SIP/2.0/UDP host5.example.net;rport;branch=z9hG4bKkdjuw
+C: application/sdp
+Contact:
+ <sip:cal%6Cer@$LOCAL_IP:$LOCAL_PORT;%6C%72;n%61me=v%61lue%25%34%31>
+Content-Length: 150
+
+v=0
+o=mhandley 29739 7272939 IN IP4 192.0.2.1
+s=-
+c=IN IP4 192.0.2.1
+t=0 0
+m=audio 49217 RTP/AVP 0 12
+m=video 3227 RTP/AVP 31
+a=rtpmap:31 LPC
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.3",
+ "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py
new file mode 100644
index 0000000..4381db3
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_4.py
@@ -0,0 +1,25 @@
+# $Id: 001_torture_4475_3_1_1_4.py 3712 2011-08-18 17:34:29Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1. Valid Messages
+# 3.1.1.4. Escaped Nulls in URIs
+complete_msg = \
+"""REGISTER sip:example.com SIP/2.0
+To: sip:null-%00-null@example.com
+From: sip:null-%00-null@example.com;tag=839923423
+Max-Forwards: 70
+Call-ID: escnull.39203ndfvkjdasfkq3w4otrq0adsfdfnavd
+CSeq: 14398234 REGISTER
+Via: SIP/2.0/UDP host5.example.com;rport;branch=z9hG4bKkdjuw
+Contact: <sip:%00@host5.example.com>
+Contact: <sip:%00%00@host5.example.com>
+L:0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.4",
+ "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py
new file mode 100644
index 0000000..236d034
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/001_torture_4475_3_1_1_5.py
@@ -0,0 +1,25 @@
+# $Id: 001_torture_4475_3_1_1_5.py 2505 2009-03-12 11:25:11Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Torture message from RFC 4475
+# 3.1.1. Valid Messages
+# 3.1.1.5. Use of % When It Is Not an Escape
+complete_msg = \
+"""RE%47IST%45R sip:registrar.example.com SIP/2.0
+To: "%Z%45" <sip:resource@example.com>
+From: "%Z%45" <sip:resource@example.com>;tag=f232jadfj23
+Call-ID: esc02.asdfnqwo34rq23i34jrjasdcnl23nrlknsdf
+Via: SIP/2.0/TCP host.example.com;rport;branch=z9hG4bK209%fzsnel234
+CSeq: 29344 RE%47IST%45R
+Max-Forwards: 70
+Contact: <sip:alias1@host1.example.com>
+C%6Fntact: <sip:alias2@host2.example.com>
+Contact: <sip:alias3@host3.example.com>
+l: 0
+"""
+
+sendto_cfg = sip.SendtoCfg( "RFC 4475 3.1.1.5",
+ "--null-audio --auto-answer 200",
+ "", 405, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/100_simplecall.py b/tests/pjsua/scripts-sendto/100_simplecall.py
new file mode 100644
index 0000000..000f501
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/100_simplecall.py
@@ -0,0 +1,20 @@
+# $Id: 100_simplecall.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+sendto_cfg = sip.SendtoCfg( "simple call", "--null-audio --auto-answer 200", sdp, 200)
+
diff --git a/tests/pjsua/scripts-sendto/110_tel_uri.py b/tests/pjsua/scripts-sendto/110_tel_uri.py
new file mode 100644
index 0000000..70164c9
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/110_tel_uri.py
@@ -0,0 +1,46 @@
+# $Id: 110_tel_uri.py 2451 2009-02-13 10:13:08Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Handling of incoming tel: URI.
+complete_msg = \
+"""INVITE tel:+2065551212 SIP/2.0
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;rport;x-route-tag="tgrp:cococisco1";branch=z9hG4bK61E05
+From: <tel:12345>$FROM_TAG
+To: <tel:+2065551212>
+Date: Thu, 12 Feb 2009 18:32:33 GMT
+Call-ID: 58F8F7D6-F86A11DD-8013D591-5694EF79
+Supported: 100rel,timer,resource-priority
+Min-SE: 86400
+Cisco-Guid: 1492551325-4167700957-2148586897-1452601209
+User-Agent: Cisco-SIPGateway/IOS-12.x
+Allow: INVITE, OPTIONS, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY, INFO, REGISTER
+CSeq: 101 INVITE
+Max-Forwards: 70
+Timestamp: 1234463553
+Contact: <tel:+1234;ext=1>
+Contact: <sip:tester@$LOCAL_IP:$LOCAL_PORT>
+Record-Route: <sip:tester@$LOCAL_IP:$LOCAL_PORT;lr>
+Expires: 180
+Allow-Events: telephone-event
+Content-Type: application/sdp
+Content-Disposition: session;handling=required
+Content-Length: 265
+
+v=0
+o=CiscoSystemsSIP-GW-UserAgent 1296 9529 IN IP4 X.X.X.X
+s=SIP Call
+c=IN IP4 $LOCAL_IP
+t=0 0
+m=audio 18676 RTP/AVP 0 101 19
+c=IN IP4 $LOCAL_IP
+a=rtpmap:0 PCMU/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=rtpmap:19 CN/8000
+a=ptime:20
+"""
+
+sendto_cfg = sip.SendtoCfg( "tel: URI", "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_1.py b/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_1.py
new file mode 100644
index 0000000..57a73f9
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_1.py
@@ -0,0 +1,28 @@
+# $Id: 120_sdp_with_video_dynamic_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Video uses dynamic payload type
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=video 4000 RTP/AVP 100
+a=rtpmap:100 myvideo/80000
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=video 0 RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and video", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_2.py b/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_2.py
new file mode 100644
index 0000000..b5c8f5c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/120_sdp_with_video_dynamic_2.py
@@ -0,0 +1,28 @@
+# $Id: 120_sdp_with_video_dynamic_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# In this case the video codec uses dynamic payload type
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=video 4000 RTP/AVP 100
+a=rtpmap:100 myvideo/96000
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=video 0 RTP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and video", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/121_sdp_with_video_static_1.py b/tests/pjsua/scripts-sendto/121_sdp_with_video_static_1.py
new file mode 100644
index 0000000..c45f94c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/121_sdp_with_video_static_1.py
@@ -0,0 +1,28 @@
+# $Id: 121_sdp_with_video_static_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Video uses static payload type which will cause failure
+# when session.c looks-up the codec in codec manager
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=video 4000 RTP/AVP 54
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=video 0 RTP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and video", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/121_sdp_with_video_static_2.py b/tests/pjsua/scripts-sendto/121_sdp_with_video_static_2.py
new file mode 100644
index 0000000..0058e1b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/121_sdp_with_video_static_2.py
@@ -0,0 +1,28 @@
+# $Id: 121_sdp_with_video_static_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Video uses static payload type which will cause failure
+# when session.c looks-up the codec in codec manager
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=video 4000 RTP/AVP 54
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=video 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and video", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_1.py b/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_1.py
new file mode 100644
index 0000000..e4fc6a7
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_1.py
@@ -0,0 +1,27 @@
+# $Id: 122_sdp_with_unknown_dynamic_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=xapplicationx 4000 RTP/AVP 100
+a=rtpmap:100 myapp/80000
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=xapplicationx 0 RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and unknown", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_2.py b/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_2.py
new file mode 100644
index 0000000..bbdc902
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/122_sdp_with_unknown_dynamic_2.py
@@ -0,0 +1,27 @@
+# $Id: 122_sdp_with_unknown_dynamic_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=xapplicationx 4000 RTP/AVP 100
+a=rtpmap:100 myapp/80000
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=xapplicationx 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and unknown", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_1.py b/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_1.py
new file mode 100644
index 0000000..b21fc54
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_1.py
@@ -0,0 +1,27 @@
+# $Id: 123_sdp_with_unknown_static_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# The unknown media uses static payload type
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=xapplicationx 4000 RTP/AVP 54
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=xapplicationx 0 RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and unknown", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_2.py b/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_2.py
new file mode 100644
index 0000000..8e0e081
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/123_sdp_with_unknown_static_2.py
@@ -0,0 +1,27 @@
+# $Id: 123_sdp_with_unknown_static_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# The unknown media uses static payload type
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=xapplicationx 4000 RTP/AVP 54
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=xapplicationx 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and unknown", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/124_sdp_with_unknown_static_unknown_transport.py b/tests/pjsua/scripts-sendto/124_sdp_with_unknown_static_unknown_transport.py
new file mode 100644
index 0000000..c298503
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/124_sdp_with_unknown_static_unknown_transport.py
@@ -0,0 +1,27 @@
+# $Id: 124_sdp_with_unknown_static_unknown_transport.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=xapplicationx 4000 XRTPX/XAVPX 54
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=xapplicationx 0 XRTPX/XAVPX "
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mixed audio and unknown and with unknown transport",
+ pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_0.py b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_0.py
new file mode 100644
index 0000000..8f01152
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_0.py
@@ -0,0 +1,29 @@
+# $Id: 125_sdp_with_multi_audio_0.py 3711 2011-08-18 17:31:46Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Multiple good m=audio lines! The current algorithm in pjsua-lib will
+# select the first audio (note that in 1.x it will select the last audio)
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=audio 4000 RTP/AVP 0
+m=audio 3000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=audio 0 RTP/AVP[\\s\\S]+m=audio 0 RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Mutiple good m=audio lines", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_1.py b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_1.py
new file mode 100644
index 0000000..2331c3c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_1.py
@@ -0,0 +1,27 @@
+# $Id: 125_sdp_with_multi_audio_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Multiple m=audio, one of them is bad
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+m=audio 4000 UNKNOWN 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+m=audio 0 UNKNOWN"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Audio and bad audio", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_2.py b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_2.py
new file mode 100644
index 0000000..17fd297
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_2.py
@@ -0,0 +1,27 @@
+# $Id: 125_sdp_with_multi_audio_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Multiple m=audio, one of them is bad
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 UNKNOWN 0
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 UNKNOWN[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Audio and bad audio", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_3.py b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_3.py
new file mode 100644
index 0000000..9731b0e
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_3.py
@@ -0,0 +1,28 @@
+# $Id: 125_sdp_with_multi_audio_3.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Multiple m=audio, one of them has dynamic PT codec that we don't support
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 100
+a=rtpmap:100 someunknowncodec/8000
+m=audio 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 RTP/AVP[\s\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Multiple audio lines", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_4.py b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_4.py
new file mode 100644
index 0000000..e075449
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/125_sdp_with_multi_audio_4.py
@@ -0,0 +1,27 @@
+# $Id: 125_sdp_with_multi_audio_4.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Multiple m=audio, one of them has static PT codec that we don't support
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 80
+m=audio 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 RTP/AVP[\s\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Multiple audio lines", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py b/tests/pjsua/scripts-sendto/126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py
new file mode 100644
index 0000000..22e2b0f
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py
@@ -0,0 +1,26 @@
+# $Id: 126_sdp_with_port_0_and_no_rtpmap_for_dynamic_pt.py 3011 2009-11-10 10:58:20Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=video 0 RTP/AVP 100
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=video 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SDP media with port 0 and no rtpmap for dynamic PT", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_1.py b/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_1.py
new file mode 100644
index 0000000..8fd13c9
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_1.py
@@ -0,0 +1,28 @@
+# $Id: 140_sdp_with_direction_attr_in_session_1.py 3086 2010-02-03 14:43:25Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Offer contains "sendonly" attribute in the session. Answer should
+# respond with appropriate direction in session or media
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+a=sendonly
+m=audio 5000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "a=recvonly"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SDP direction in session", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_2.py b/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_2.py
new file mode 100644
index 0000000..76db859
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/140_sdp_with_direction_attr_in_session_2.py
@@ -0,0 +1,30 @@
+# $Id: 140_sdp_with_direction_attr_in_session_2.py 3086 2010-02-03 14:43:25Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Offer contains "inactive" attribute in the session, however the media
+# also has "sendonly" attribute. Answer should appropriately respond
+# direction attribute in media, instead of the one in session.
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+a=inactive
+m=audio 5000 RTP/AVP 0
+a=sendonly
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "a=recvonly"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SDP direction in session", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/150_err_extension.py b/tests/pjsua/scripts-sendto/150_err_extension.py
new file mode 100644
index 0000000..d5ebe0b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/150_err_extension.py
@@ -0,0 +1,27 @@
+# $Id: 150_err_extension.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = "Require: xxx-my-extension\n"
+include = ["Unsupported: xxx-my-extension"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Bad extension", pjsua_args, sdp, 420,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/151_err_sdp_video.py b/tests/pjsua/scripts-sendto/151_err_sdp_video.py
new file mode 100644
index 0000000..7401964
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/151_err_sdp_video.py
@@ -0,0 +1,23 @@
+# $Id: 151_err_sdp_video.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=video 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Video not acceptable", pjsua_args, sdp, 488,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/152_err_sdp_no_media.py b/tests/pjsua/scripts-sendto/152_err_sdp_no_media.py
new file mode 100644
index 0000000..1148085
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/152_err_sdp_no_media.py
@@ -0,0 +1,22 @@
+# $Id: 152_err_sdp_no_media.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("No media in SDP", pjsua_args, sdp, 400,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/153_err_sdp_unsupported_codec.py b/tests/pjsua/scripts-sendto/153_err_sdp_unsupported_codec.py
new file mode 100644
index 0000000..ec15495
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/153_err_sdp_unsupported_codec.py
@@ -0,0 +1,24 @@
+# $Id: 153_err_sdp_unsupported_codec.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=video 4000 RTP/AVP 101
+a=rtpmap:101 my-proprietary-codec
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Unsupported codec", pjsua_args, sdp, 488,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/155_err_sdp_bad_syntax.py b/tests/pjsua/scripts-sendto/155_err_sdp_bad_syntax.py
new file mode 100644
index 0000000..071217e
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/155_err_sdp_bad_syntax.py
@@ -0,0 +1,23 @@
+# $Id: 155_err_sdp_bad_syntax.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=
+o=
+s=
+c=
+t=
+a=
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = [ "Warning: " ] # better have Warning header
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Bad SDP syntax", pjsua_args, sdp, 400,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/156_err_sdp_bad_net_type.py b/tests/pjsua/scripts-sendto/156_err_sdp_bad_net_type.py
new file mode 100644
index 0000000..07d4db2
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/156_err_sdp_bad_net_type.py
@@ -0,0 +1,27 @@
+# $Id: 156_err_sdp_bad_net_type.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=AF IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = [ "Warning: " ] # better have Warning header
+exclude = []
+sendto_cfg = sip.SendtoCfg("Bad SDP network type", pjsua_args, sdp, 400,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/157_err_sdp_bad_addr_type.py b/tests/pjsua/scripts-sendto/157_err_sdp_bad_addr_type.py
new file mode 100644
index 0000000..3cb404a
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/157_err_sdp_bad_addr_type.py
@@ -0,0 +1,27 @@
+# $Id: 157_err_sdp_bad_addr_type.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP7 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = [ "Warning: " ] # better have Warning header
+exclude = []
+sendto_cfg = sip.SendtoCfg("Bad SDP address type", pjsua_args, sdp, 400,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/158_err_sdp_bad_transport_type.py b/tests/pjsua/scripts-sendto/158_err_sdp_bad_transport_type.py
new file mode 100644
index 0000000..915ba8a
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/158_err_sdp_bad_transport_type.py
@@ -0,0 +1,27 @@
+# $Id: 158_err_sdp_bad_transport_type.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/XAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = ""
+include = []
+exclude = []
+sendto_cfg = sip.SendtoCfg("Unsupported transport type", pjsua_args, sdp, 488,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/159_no_rport.py b/tests/pjsua/scripts-sendto/159_no_rport.py
new file mode 100644
index 0000000..f7a7468
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/159_no_rport.py
@@ -0,0 +1,38 @@
+# $Id: 159_no_rport.py 2442 2009-02-06 08:44:23Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Ticket http://trac.pjsip.org/repos/ticket/718
+# RTC doesn't put rport in Via, and it is report to have caused segfault.
+complete_msg = \
+"""INVITE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP $LOCAL_IP:$LOCAL_PORT;branch=z9hG4bK74a60ee5
+From: <sip:tester@localhost>;tag=as2858a32c
+To: <sip:pjsua@localhost>
+Contact: <sip:tester@$LOCAL_IP:$LOCAL_PORT>
+Call-ID: 123@localhost
+CSeq: 1 INVITE
+Max-Forwards: 70
+Content-Type: application/sdp
+Content-Length: 285
+
+v=0
+o=root 4236 4236 IN IP4 192.168.1.11
+s=session
+c=IN IP4 192.168.1.11
+t=0 0
+m=audio 14390 RTP/AVP 0 3 8 101
+a=rtpmap:0 PCMU/8000
+a=rtpmap:3 GSM/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=silenceSupp:off - - - -
+a=ptime:20
+a=sendrecv
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RTC no rport", "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/159_no_rport_nit.py b/tests/pjsua/scripts-sendto/159_no_rport_nit.py
new file mode 100644
index 0000000..073108e
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/159_no_rport_nit.py
@@ -0,0 +1,25 @@
+# $Id: 159_no_rport_nit.py 2442 2009-02-06 08:44:23Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Ticket http://trac.pjsip.org/repos/ticket/718
+# RTC doesn't put rport in Via, and it is reported to have caused segfault.
+#
+complete_msg = \
+"""MESSAGE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP localhost:$LOCAL_PORT;branch=z9hG4bK$BRANCH
+From: <sip:tester@localhost>;tag=as2858a32c
+To: <sip:pjsua@localhost>
+Call-ID: 123@localhost
+CSeq: 1 MESSAGE
+Max-Forwards: 70
+Content-Length: 11
+Content-Type: text/plain
+
+Hello world
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "RTC no rport", "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/160_err_duplicate_replaces.py b/tests/pjsua/scripts-sendto/160_err_duplicate_replaces.py
new file mode 100644
index 0000000..63da2e4
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/160_err_duplicate_replaces.py
@@ -0,0 +1,23 @@
+# $Id: 160_err_duplicate_replaces.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = "Replaces: abcd;from_tag=1\r\nReplaces: efgh;from_tag=2\r\n"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Duplicate replaces header", pjsua_args, sdp, 400,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/161_err_replaces_dlg_not_found.py b/tests/pjsua/scripts-sendto/161_err_replaces_dlg_not_found.py
new file mode 100644
index 0000000..33d934c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/161_err_replaces_dlg_not_found.py
@@ -0,0 +1,23 @@
+# $Id: 161_err_replaces_dlg_not_found.py 2066 2008-06-26 19:51:01Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = "Replaces: abcd;from_tag=1\r\n"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Replaced dialog not found", pjsua_args, sdp, 481,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/170_timer_required.py b/tests/pjsua/scripts-sendto/170_timer_required.py
new file mode 100644
index 0000000..9ac1708
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/170_timer_required.py
@@ -0,0 +1,27 @@
+# $Id: 170_timer_required.py 3307 2010-09-08 05:38:49Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-timer 2 --timer-min-se 90 --timer-se 1800"
+extra_headers = "Require: timer\nSupported: timer\nSession-Expires: 1800\n"
+include = ["Session-Expires: .*;refresher=.*"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer required", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/171_timer_initiated_by_uas.py b/tests/pjsua/scripts-sendto/171_timer_initiated_by_uas.py
new file mode 100644
index 0000000..4ce1a24
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/171_timer_initiated_by_uas.py
@@ -0,0 +1,36 @@
+# $Id: 171_timer_initiated_by_uas.py 3307 2010-09-08 05:38:49Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+# RFC 4028 Section 9:
+# If the incoming request contains a Supported header field with a
+# value 'timer' but does not contain a Session-Expires header, it means
+# that the UAS is indicating support for timers but is not requesting
+# one. The UAS may request a session timer in the 2XX response by
+# including a Session-Expires header field. The value MUST NOT be set
+# to a duration lower than the value in the Min-SE header field in the
+# request, if it is present.
+
+pjsua_args = "--null-audio --auto-answer 200 --use-timer 2 --timer-min-se 90 --timer-se 1800"
+extra_headers = "Supported: timer\n"
+include = ["Session-Expires: .*;refresher=.*"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer initiated by UAS", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
+
diff --git a/tests/pjsua/scripts-sendto/172_timer_supported_but_not_used.py b/tests/pjsua/scripts-sendto/172_timer_supported_but_not_used.py
new file mode 100644
index 0000000..88a4d99
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/172_timer_supported_but_not_used.py
@@ -0,0 +1,26 @@
+# $Id: 172_timer_supported_but_not_used.py 2858 2009-08-11 12:42:38Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200"
+extra_headers = "Supported: timer\n"
+include = []
+exclude = ["Session-Expires:"]
+sendto_cfg = sip.SendtoCfg("Session Timer supported but not used", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/173_timer_offer_no_refresher.py b/tests/pjsua/scripts-sendto/173_timer_offer_no_refresher.py
new file mode 100644
index 0000000..d6417cd
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/173_timer_offer_no_refresher.py
@@ -0,0 +1,26 @@
+# $Id: 173_timer_offer_no_refresher.py 2858 2009-08-11 12:42:38Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --timer-min-se 90"
+extra_headers = "Supported: timer\nSession-Expires: 1800\n"
+include = ["Session-Expires:.*;refresher=ua[cs]"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer without specifying refresher", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uac.py b/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uac.py
new file mode 100644
index 0000000..3629d4d
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uac.py
@@ -0,0 +1,26 @@
+# $Id: 173_timer_offer_refresher_uac.py 2858 2009-08-11 12:42:38Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --timer-min-se 90"
+extra_headers = "Supported: timer\nSession-Expires: 1800;refresher=uac\n"
+include = ["Session-Expires:.*;refresher=ua[cs]"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer offer refresher uac", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uas.py b/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uas.py
new file mode 100644
index 0000000..96508af
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/173_timer_offer_refresher_uas.py
@@ -0,0 +1,26 @@
+# $Id: 173_timer_offer_refresher_uas.py 2858 2009-08-11 12:42:38Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --timer-min-se 90"
+extra_headers = "Supported: timer\nSession-Expires: 1800;refresher=uas\n"
+include = ["Session-Expires:.*;refresher=ua[cs]"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer offer refresher uas", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/174_timer_se_too_small.py b/tests/pjsua/scripts-sendto/174_timer_se_too_small.py
new file mode 100644
index 0000000..cde4e9a
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/174_timer_se_too_small.py
@@ -0,0 +1,26 @@
+# $Id: 174_timer_se_too_small.py 2858 2009-08-11 12:42:38Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --timer-min-se 2000 --timer-se 2000"
+extra_headers = "Supported: timer\nSession-Expires: 1800\n"
+include = ["Min-SE:\s*2000"]
+exclude = []
+sendto_cfg = sip.SendtoCfg("Session Timer SE too small", pjsua_args, sdp, 422,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/200_ice_no_ice.py b/tests/pjsua/scripts-sendto/200_ice_no_ice.py
new file mode 100644
index 0000000..9344896
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/200_ice_no_ice.py
@@ -0,0 +1,26 @@
+# $Id: 200_ice_no_ice.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = []
+exclude = ["a=ice", "a=candidate"]
+
+sendto_cfg = sip.SendtoCfg( "caller has no ice, answer must not have ICE",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/200_ice_success_1.py b/tests/pjsua/scripts-sendto/200_ice_success_1.py
new file mode 100644
index 0000000..0340795
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/200_ice_success_1.py
@@ -0,0 +1,31 @@
+# $Id: 200_ice_success_1.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-ufrag"] # must have ICE
+exclude = ["a=candidate:[0-9a-zA-Z]+ 2 UDP", # must not answer with 2 components
+ "ice-mismatch" # must not mismatch
+ ]
+
+sendto_cfg = sip.SendtoCfg( "caller sends only one component",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/200_ice_success_2.py b/tests/pjsua/scripts-sendto/200_ice_success_2.py
new file mode 100644
index 0000000..cc28f59
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/200_ice_success_2.py
@@ -0,0 +1,36 @@
+# $Id: 200_ice_success_2.py 2084 2008-06-27 23:53:00Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtcp:4382 IN IP4 192.168.0.4
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+a=candidate:YY 2 UDP 1234 192.168.0.4 4382 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-ufrag", # must have ICE
+ "a=candidate:[0-9a-zA-Z]+ 2 UDP" # must have RTCP component
+ ]
+exclude = [
+ "ice-mismatch" # must not mismatch
+ ]
+
+sendto_cfg = sip.SendtoCfg( "caller sends only one component",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude,
+ enable_buffer = True)
+
diff --git a/tests/pjsua/scripts-sendto/200_ice_success_3.py b/tests/pjsua/scripts-sendto/200_ice_success_3.py
new file mode 100644
index 0000000..8fdadd6
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/200_ice_success_3.py
@@ -0,0 +1,35 @@
+# $Id: 200_ice_success_3.py 2376 2008-12-11 17:25:50Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+a=candidate:YY 2 UDP 1234 127.0.0.1 4001 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-ufrag", # must have ICE
+ "a=candidate:[0-9a-zA-Z]+ 2 UDP" # must have RTCP component
+ ]
+exclude = [
+ "ice-mismatch" # must not mismatch
+ ]
+
+sendto_cfg = sip.SendtoCfg( "caller sends two components without a=rtcp line",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude,
+ enable_buffer = True)
+
diff --git a/tests/pjsua/scripts-sendto/200_ice_success_4.py b/tests/pjsua/scripts-sendto/200_ice_success_4.py
new file mode 100644
index 0000000..8da6cad
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/200_ice_success_4.py
@@ -0,0 +1,35 @@
+# $Id: 200_ice_success_4.py 2376 2008-12-11 17:25:50Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtcp:4382 IN IP4 192.168.0.4
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+a=candidate:YY 2 UDP 1234 127.0.0.2 4002 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1 --ice-no-rtcp"
+include = ["a=ice-ufrag"] # must have ICE
+exclude = [
+ "ice-mismatch", # must not mismatch
+ "a=candidate:[0-9a-zA-Z]+ 2 UDP" # must not have RTCP component
+ ]
+
+sendto_cfg = sip.SendtoCfg( "pjsua with --ice-no-rtcp ignores RTCP things in the SDP",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude,
+ enable_buffer = True)
+
diff --git a/tests/pjsua/scripts-sendto/201_ice_mismatch_1.py b/tests/pjsua/scripts-sendto/201_ice_mismatch_1.py
new file mode 100644
index 0000000..c91d8d5
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/201_ice_mismatch_1.py
@@ -0,0 +1,29 @@
+# $Id: 201_ice_mismatch_1.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1 1.1.1.1 2222 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-mismatch"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller sends mismatched offer for comp 1",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/201_ice_mismatch_2.py b/tests/pjsua/scripts-sendto/201_ice_mismatch_2.py
new file mode 100644
index 0000000..69faebe
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/201_ice_mismatch_2.py
@@ -0,0 +1,31 @@
+# $Id: 201_ice_mismatch_2.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtcp:4382 IN IP4 192.168.0.4
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+a=candidate:XX 2 UDP 1234 127.0.0.1 4000 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-mismatch"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller sends mismatched offer for comp 2",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/201_ice_mismatch_3.py b/tests/pjsua/scripts-sendto/201_ice_mismatch_3.py
new file mode 100644
index 0000000..d1ad9a9
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/201_ice_mismatch_3.py
@@ -0,0 +1,30 @@
+# $Id: 201_ice_mismatch_3.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtcp:4382 IN IP4 192.168.0.4
+a=ice-ufrag:1234
+a=ice-pwd:5678
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=candidate:XX 1 UDP 1234 127.0.0.1 4000 typ host
+"""
+
+args = "--null-audio --use-ice --auto-answer 200 --max-calls 1"
+include = ["a=ice-mismatch"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller sends mismatched offer for comp 2",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/251_multipart_ok_simple.py b/tests/pjsua/scripts-sendto/251_multipart_ok_simple.py
new file mode 100644
index 0000000..c98cd4c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/251_multipart_ok_simple.py
@@ -0,0 +1,38 @@
+# $Id: 251_multipart_ok_simple.py 3243 2010-08-01 09:48:51Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+body = \
+"""
+--12345
+Content-Type: application/sdp
+
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+
+--12345
+Content-Type: text/plain
+
+Hi there this is definitely not SDP
+
+--12345--
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1"
+extra_headers = "Content-Type: multipart/mixed; boundary=12345"
+include = ["v=0", "m=audio"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Valid multipart/mixed body containing SDP",
+ pjsua_args=args, sdp="", resp_code=200,
+ extra_headers=extra_headers, body=body,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/252_multipart_ok_clutter.py b/tests/pjsua/scripts-sendto/252_multipart_ok_clutter.py
new file mode 100644
index 0000000..dc9a83b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/252_multipart_ok_clutter.py
@@ -0,0 +1,47 @@
+# $Id: 252_multipart_ok_clutter.py 3243 2010-08-01 09:48:51Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+body = \
+"""
+This is the preamble. It is to be ignored, though it
+is a handy place for composition agents to include an
+explanatory note to non-MIME conformant readers.
+
+--123:45
+Content-Type: text/plain
+
+The first part is definitely not SDP
+
+--123:45
+
+This is implicitly typed plain US-ASCII text.
+It does NOT end with a linebreak.
+--123:45
+Content-Type: application/sdp
+
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+
+--123:45--
+This is the epilogue. It is also to be ignored.
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1"
+extra_headers = "Content-Type: multipart/mixed; boundary=\"123:45\""
+include = ["v=0", "m=audio"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Valid but cluttered multipart/mixed body containing SDP",
+ pjsua_args=args, sdp="", resp_code=200,
+ extra_headers=extra_headers, body=body,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/260_multipart_err_no_sdp.py b/tests/pjsua/scripts-sendto/260_multipart_err_no_sdp.py
new file mode 100644
index 0000000..ed28ca2
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/260_multipart_err_no_sdp.py
@@ -0,0 +1,38 @@
+# $Id: 260_multipart_err_no_sdp.py 3243 2010-08-01 09:48:51Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+body = \
+"""
+--12345
+Content-Type: application/notsdp
+
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=pjmedia
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+
+--12345
+Content-Type: text/plain
+
+Hi there this is definitely not SDP
+
+--12345--
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1"
+extra_headers = "Content-Type: multipart/mixed; boundary=12345"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Multipart/mixed body without SDP",
+ pjsua_args=args, sdp="", resp_code=400,
+ extra_headers=extra_headers, body=body,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/300_srtp_crypto_case_insensitive.py b/tests/pjsua/scripts-sendto/300_srtp_crypto_case_insensitive.py
new file mode 100644
index 0000000..1f609fd
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_crypto_case_insensitive.py
@@ -0,0 +1,27 @@
+# $Id: 300_srtp_crypto_case_insensitive.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AeS_Cm_128_HmAC_shA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 aEs_cM_128_HMaC_ShA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 2 --srtp-secure 0"
+include = ["m=audio \d+ RTP/SAVP", "a=crypto"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used mixed case in crypto attr, callee must process that normally",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_duplicated_crypto_tag.py b/tests/pjsua/scripts-sendto/300_srtp_duplicated_crypto_tag.py
new file mode 100644
index 0000000..29f62c5
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_duplicated_crypto_tag.py
@@ -0,0 +1,27 @@
+# $Id: 300_srtp_duplicated_crypto_tag.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:1 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used invalid crypto tag, callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_invalid_crypto_tag_non_numeric.py b/tests/pjsua/scripts-sendto/300_srtp_invalid_crypto_tag_non_numeric.py
new file mode 100644
index 0000000..8c5d7cc
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_invalid_crypto_tag_non_numeric.py
@@ -0,0 +1,27 @@
+# $Id: 300_srtp_invalid_crypto_tag_non_numeric.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:x AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used invalid crypto tag (non-numeric), callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_receive_crypto_tag_zero.py b/tests/pjsua/scripts-sendto/300_srtp_receive_crypto_tag_zero.py
new file mode 100644
index 0000000..a305fac
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_receive_crypto_tag_zero.py
@@ -0,0 +1,26 @@
+# $Id: 300_srtp_receive_crypto_tag_zero.py 2765 2009-06-17 12:00:47Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:0 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used crypto tag zero, callee must accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_1.py b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_1.py
new file mode 100644
index 0000000..35e712b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_1.py
@@ -0,0 +1,26 @@
+# $Id: 300_srtp_receive_no_key_1.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:0 AES_CM_128_HMAC_SHA1_80
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller send crypto attr without key, callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_2.py b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_2.py
new file mode 100644
index 0000000..51fff9f
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_2.py
@@ -0,0 +1,26 @@
+# $Id: 300_srtp_receive_no_key_2.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:0 AES_CM_128_HMAC_SHA1_80 inline
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller send crypto attr without key, callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_3.py b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_3.py
new file mode 100644
index 0000000..fcf8968
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/300_srtp_receive_no_key_3.py
@@ -0,0 +1,26 @@
+# $Id: 300_srtp_receive_no_key_3.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:0 AES_CM_128_HMAC_SHA1_80 inline:
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller send crypto attr without key, callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/301_srtp0_recv_avp.py b/tests/pjsua/scripts-sendto/301_srtp0_recv_avp.py
new file mode 100644
index 0000000..af68feb
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/301_srtp0_recv_avp.py
@@ -0,0 +1,28 @@
+# $Id: 301_srtp0_recv_avp.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 0 --srtp-secure 0"
+include = []
+exclude = ["a=crypto"]
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP disabled but receive RTP/AVP with crypto, should accept without crypto",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/301_srtp0_recv_savp.py b/tests/pjsua/scripts-sendto/301_srtp0_recv_savp.py
new file mode 100644
index 0000000..1066746
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/301_srtp0_recv_savp.py
@@ -0,0 +1,28 @@
+# $Id: 301_srtp0_recv_savp.py 3713 2011-08-18 18:11:08Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 0 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP disabled but receive RTP/SAVP, should reject the call",
+ pjsua_args=args, sdp=sdp, resp_code=488,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/310_srtp1_no_crypto.py b/tests/pjsua/scripts-sendto/310_srtp1_no_crypto.py
new file mode 100644
index 0000000..044fd66
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/310_srtp1_no_crypto.py
@@ -0,0 +1,26 @@
+# $Id: 310_srtp1_no_crypto.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = ["m=audio \d+ RTP/AVP"]
+exclude = ["a=crypto"]
+
+sendto_cfg = sip.SendtoCfg( "caller has no crypto attr, answer must accept without crypto attr",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/311_srtp1_recv_avp.py b/tests/pjsua/scripts-sendto/311_srtp1_recv_avp.py
new file mode 100644
index 0000000..964222c
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/311_srtp1_recv_avp.py
@@ -0,0 +1,28 @@
+# $Id: 311_srtp1_recv_avp.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = ["m=audio \d+ RTP/AVP", "a=crypto"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP optional and receive RTP/AVP with crypto, should accept with RTP/AVP & crypto",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/312_srtp1_recv_savp.py b/tests/pjsua/scripts-sendto/312_srtp1_recv_savp.py
new file mode 100644
index 0000000..4a0f294
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/312_srtp1_recv_savp.py
@@ -0,0 +1,28 @@
+# $Id: 312_srtp1_recv_savp.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = ["m=audio \d+ RTP/SAVP", "a=crypto"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP optional receive RTP/SAVP, should answer RTP/SAVP too",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/313_srtp1_unsupported_crypto.py b/tests/pjsua/scripts-sendto/313_srtp1_unsupported_crypto.py
new file mode 100644
index 0000000..da5a878
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/313_srtp1_unsupported_crypto.py
@@ -0,0 +1,26 @@
+# $Id: 313_srtp1_unsupported_crypto.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 CRYPTO_X inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 1 --srtp-secure 0"
+include = []
+exclude = ["a=crypto"]
+
+sendto_cfg = sip.SendtoCfg( "caller has used unsupported crypto, callee (SRTP optional) accept the call without crypto",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/320_srtp2_no_crypto.py b/tests/pjsua/scripts-sendto/320_srtp2_no_crypto.py
new file mode 100644
index 0000000..6231964
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/320_srtp2_no_crypto.py
@@ -0,0 +1,26 @@
+# $Id: 320_srtp2_no_crypto.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 2 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has no crypto attr on RTP/SAVP, callee must not accept the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_1.py b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_1.py
new file mode 100644
index 0000000..815b130
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_1.py
@@ -0,0 +1,28 @@
+# $Id: 320_srtp_with_unknown_media_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+m=xapplicationx 4000 RTP/AVP 100
+a=rtpmap:100 myapp/80000
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+a=crypto[\\s\\S]+m=xapplicationx 0 RTP/AVP"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SRTP audio and unknown media", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_2.py b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_2.py
new file mode 100644
index 0000000..5980f20
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_media_2.py
@@ -0,0 +1,28 @@
+# $Id: 320_srtp_with_unknown_media_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=xapplicationx 4000 RTP/AVP 100
+a=rtpmap:100 myapp/80000
+m=audio 5000 RTP/AVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=xapplicationx 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+a=crypto"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Unknown media and SRTP audio", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_1.py b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_1.py
new file mode 100644
index 0000000..c0cf60d
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_1.py
@@ -0,0 +1,27 @@
+# $Id: 320_srtp_with_unknown_transport_1.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/AVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+m=audio 4000 UNKNOWN 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+a=crypto[\\s\\S]+m=audio 0 UNKNOWN"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SRTP audio and unknown media", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_2.py b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_2.py
new file mode 100644
index 0000000..b079471
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/320_srtp_with_unknown_transport_2.py
@@ -0,0 +1,27 @@
+# $Id: 320_srtp_with_unknown_transport_2.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 UNKNOWN 0
+m=audio 5000 RTP/AVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 UNKNOWN[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP[\\s\\S]+a=crypto"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SRTP audio and unknown media", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/321_srtp2_recv_avp.py b/tests/pjsua/scripts-sendto/321_srtp2_recv_avp.py
new file mode 100644
index 0000000..12cd6e2
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/321_srtp2_recv_avp.py
@@ -0,0 +1,28 @@
+# $Id: 321_srtp2_recv_avp.py 3713 2011-08-18 18:11:08Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 2 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP mandatory and receive RTP/AVP with crypto, should reject the call",
+ pjsua_args=args, sdp=sdp, resp_code=488,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/322_srtp2_recv_savp.py b/tests/pjsua/scripts-sendto/322_srtp2_recv_savp.py
new file mode 100644
index 0000000..1e841e8
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/322_srtp2_recv_savp.py
@@ -0,0 +1,28 @@
+# $Id: 322_srtp2_recv_savp.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+a=crypto:2 AES_CM_128_HMAC_SHA1_32 inline:t0r0/apkukU7JjjfR0mY8GEimBq4OiPEm9eKSFOx
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 2 --srtp-secure 0"
+include = ["m=audio \d+ RTP/SAVP", "a=crypto"]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "Callee has SRTP mandatory receive RTP/SAVP, should answer RTP/SAVP too",
+ pjsua_args=args, sdp=sdp, resp_code=200,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/323_srtp2_receive_too_long_key.py b/tests/pjsua/scripts-sendto/323_srtp2_receive_too_long_key.py
new file mode 100644
index 0000000..7536577
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/323_srtp2_receive_too_long_key.py
@@ -0,0 +1,25 @@
+# $Id: 323_srtp2_receive_too_long_key.py 3193 2010-06-03 02:27:41Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Too long key should be rejected
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/SAVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQWnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 2 --srtp-secure 0"
+extra_headers = ""
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("SRTP receive too long key", pjsua_args, sdp, 406,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/323_srtp2_unsupported_crypto.py b/tests/pjsua/scripts-sendto/323_srtp2_unsupported_crypto.py
new file mode 100644
index 0000000..bd322fe
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/323_srtp2_unsupported_crypto.py
@@ -0,0 +1,26 @@
+# $Id: 323_srtp2_unsupported_crypto.py 2036 2008-06-20 17:43:55Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=tester
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/SAVP 0 101
+a=rtpmap:0 PCMU/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+a=crypto:1 CRYPTO_X inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+args = "--null-audio --auto-answer 200 --max-calls 1 --use-srtp 2 --srtp-secure 0"
+include = []
+exclude = []
+
+sendto_cfg = sip.SendtoCfg( "caller has used unsupported crypto, callee (SRTP mandatory) must reject the call",
+ pjsua_args=args, sdp=sdp, resp_code=406,
+ resp_inc=include, resp_exc=exclude)
diff --git a/tests/pjsua/scripts-sendto/330_srtp_prefer_rtp_savp.py b/tests/pjsua/scripts-sendto/330_srtp_prefer_rtp_savp.py
new file mode 100644
index 0000000..ed79593
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/330_srtp_prefer_rtp_savp.py
@@ -0,0 +1,30 @@
+# $Id: 330_srtp_prefer_rtp_savp.py 3251 2010-08-06 01:03:33Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# When SRTP is enabled in pjsua, it should prefer to use
+# RTP/SAVP media line if there are multiple m=audio lines
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 4000 RTP/AVP 0
+a=rtpmap:0 pcmu/8000
+m=audio 4000 RTP/SAVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 1 --srtp-secure 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 RTP/AVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/SAVP[\\s\\S]+a=crypto"
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Prefer RTP/SAVP", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/331_srtp_prefer_rtp_avp.py b/tests/pjsua/scripts-sendto/331_srtp_prefer_rtp_avp.py
new file mode 100644
index 0000000..bd09465
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/331_srtp_prefer_rtp_avp.py
@@ -0,0 +1,29 @@
+# $Id: 331_srtp_prefer_rtp_avp.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# When SRTP is NOT enabled in pjsua, it should prefer to use
+# RTP/AVP media line if there are multiple m=audio lines
+sdp = \
+"""
+v=0
+o=- 0 0 IN IP4 127.0.0.1
+s=-
+c=IN IP4 127.0.0.1
+t=0 0
+m=audio 5000 RTP/SAVP 0
+a=crypto:1 aes_cm_128_hmac_sha1_80 inline:WnD7c1ksDGs+dIefCEo8omPg4uO8DYIinNGL5yxQ
+m=audio 4000 RTP/AVP 0
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --use-srtp 0"
+extra_headers = ""
+include = ["Content-Type: application/sdp", # response must include SDP
+ "m=audio 0 RTP/SAVP[\\s\\S]+m=audio [1-9]+[0-9]* RTP/AVP"
+ ]
+exclude = ["a=crypto"]
+
+sendto_cfg = sip.SendtoCfg("Prefer RTP/SAVP", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/360_non_sip_uri.py b/tests/pjsua/scripts-sendto/360_non_sip_uri.py
new file mode 100644
index 0000000..d838669
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/360_non_sip_uri.py
@@ -0,0 +1,27 @@
+# $Id: 360_non_sip_uri.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Some non-SIP URI's in Contact header
+#
+complete_msg = \
+"""INVITE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 0 INVITE
+Contact: mailto:dontspam@pjsip.org
+Contact: <mailto:dontspam@pjsip.org>
+Contact: http://www.pjsip.org/the%20path.cgi?pname=pvalue
+Contact: <sip:localhost>
+User-Agent: PJSUA v0.9.0-trunk/win32
+Content-Length: 0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Non SIP URI in Contact",
+ "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/361_non_sip_uri.py b/tests/pjsua/scripts-sendto/361_non_sip_uri.py
new file mode 100644
index 0000000..4b2b59b
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/361_non_sip_uri.py
@@ -0,0 +1,26 @@
+# $Id: 361_non_sip_uri.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# No SIP URI in Contact header
+#
+complete_msg = \
+"""INVITE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 0 INVITE
+Contact: mailto:dontspam@pjsip.org
+Contact: <mailto:dontspam@pjsip.org>
+Contact: http://www.pjsip.org/the%20path.cgi?pname=pvalue
+User-Agent: PJSUA v0.9.0-trunk/win32
+Content-Length: 0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "No SIP URI in Contact",
+ "--null-audio --auto-answer 200",
+ "", 500, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/362_non_sip_uri.py b/tests/pjsua/scripts-sendto/362_non_sip_uri.py
new file mode 100644
index 0000000..6065a23
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/362_non_sip_uri.py
@@ -0,0 +1,27 @@
+# $Id: 362_non_sip_uri.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Some non-SIP URI's in Contact header
+#
+complete_msg = \
+"""INVITE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 0 INVITE
+Contact: <sip:localhost>
+Contact: mailto:dontspam@pjsip.org
+Contact: <mailto:dontspam@pjsip.org>
+Contact: http://www.pjsip.org/the%20path.cgi?pname=pvalue
+User-Agent: PJSUA v0.9.0-trunk/win32
+Content-Length: 0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Non SIP URI in Contact",
+ "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/363_non_sip_uri_subscribe.py b/tests/pjsua/scripts-sendto/363_non_sip_uri_subscribe.py
new file mode 100644
index 0000000..8547829
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/363_non_sip_uri_subscribe.py
@@ -0,0 +1,31 @@
+# $Id: 363_non_sip_uri_subscribe.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Some non-SIP URI's in Contact header
+#
+complete_msg = \
+"""SUBSCRIBE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 0 SUBSCRIBE
+Contact: mailto:dontspam@pjsip.org
+Contact: <mailto:dontspam@pjsip.org>
+Contact: http://www.pjsip.org/the%20path.cgi?pname=pvalue
+Contact: <sip:localhost>
+Event: presence
+Expires: 600
+Accept: application/pidf+xml, application/xpidf+xml
+Allow-Events: presence, refer
+User-Agent: PJSUA v0.9.0-trunk/win32
+Content-Length: 0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Non SIP URI in Contact",
+ "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/364_non_sip_uri_subscribe.py b/tests/pjsua/scripts-sendto/364_non_sip_uri_subscribe.py
new file mode 100644
index 0000000..598b8cb
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/364_non_sip_uri_subscribe.py
@@ -0,0 +1,30 @@
+# $Id: 364_non_sip_uri_subscribe.py 2392 2008-12-22 18:54:58Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Some non-SIP URI's in Contact header
+#
+complete_msg = \
+"""SUBSCRIBE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 0 SUBSCRIBE
+Contact: mailto:dontspam@pjsip.org
+Contact: <mailto:dontspam@pjsip.org>
+Contact: http://www.pjsip.org/the%20path.cgi?pname=pvalue
+Event: presence
+Expires: 600
+Accept: application/pidf+xml, application/xpidf+xml
+Allow-Events: presence, refer
+User-Agent: PJSUA v0.9.0-trunk/win32
+Content-Length: 0
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Non SIP URI in Contact",
+ "--null-audio --auto-answer 200",
+ "", 400, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/400_fmtp_g7221_with_bitrate.py b/tests/pjsua/scripts-sendto/400_fmtp_g7221_with_bitrate.py
new file mode 100644
index 0000000..c9a92da
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/400_fmtp_g7221_with_bitrate.py
@@ -0,0 +1,34 @@
+# $Id: 400_fmtp_g7221_with_bitrate.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer for codec G722.1 should contain fmtp bitrate
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 99 100 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:99 G7221/16000
+a=fmtp:99 bitrate=24000
+a=rtpmap:100 G7221/16000
+a=fmtp:100 bitrate=32000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec G7221"
+extra_headers = ""
+include = ["fmtp:[\d]+ bitrate="] # response must include fmtp bitrate
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Answer should contain fmtp bitrate for codec G722.1", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_24000.py b/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_24000.py
new file mode 100644
index 0000000..760a797
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_24000.py
@@ -0,0 +1,35 @@
+# $Id: 401_fmtp_g7221_with_bitrate_24000.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer with codec G722.1 should choose the same bitrate
+# which in this test is 24000
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 100 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:100 G7221/16000
+a=fmtp:100 bitrate=24000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec G7221"
+extra_headers = ""
+include = ["a=rtpmap:[\d]+ G7221/16000", # response must choose G722.1
+ "fmtp:[\d]+ bitrate=24000" # response must choose the same bitrate
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Answer with G722.1 should choose bitrate 24000", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_32000.py b/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_32000.py
new file mode 100644
index 0000000..2a7aa32
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/401_fmtp_g7221_with_bitrate_32000.py
@@ -0,0 +1,35 @@
+# $Id: 401_fmtp_g7221_with_bitrate_32000.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer with codec G722.1 should choose the same bitrate
+# which in this test is 32000
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 100 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:100 G7221/16000
+a=fmtp:100 bitrate=32000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec G7221"
+extra_headers = ""
+include = ["a=rtpmap:[\d]+ G7221/16000", # response must choose G722.1
+ "fmtp:[\d]+ bitrate=32000" # response must choose the same bitrate
+ ]
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("Answer with G722.1 should choose bitrate 32000", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/410_fmtp_amrnb_offer_octet_align.py b/tests/pjsua/scripts-sendto/410_fmtp_amrnb_offer_octet_align.py
new file mode 100644
index 0000000..9b386e3
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/410_fmtp_amrnb_offer_octet_align.py
@@ -0,0 +1,32 @@
+# $Id: 410_fmtp_amrnb_offer_octet_align.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer for codec AMR should contain fmtp octet-align=1
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 99 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:99 AMR/8000
+a=fmtp:99 octet-align=1
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec AMR"
+extra_headers = ""
+include = ["octet-align=1"] # response must include 'octet-align=1'
+exclude = []
+
+sendto_cfg = sip.SendtoCfg("AMR negotiation should response with fmtp 'octet-align=1'", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/411_fmtp_amrnb_offer_band_eff.py b/tests/pjsua/scripts-sendto/411_fmtp_amrnb_offer_band_eff.py
new file mode 100644
index 0000000..9eebff5
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/411_fmtp_amrnb_offer_band_eff.py
@@ -0,0 +1,31 @@
+# $Id: 411_fmtp_amrnb_offer_band_eff.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer for codec AMR should not contain fmtp octet-align=1
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 99 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:99 AMR/8000
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec AMR"
+extra_headers = ""
+include = [""]
+exclude = ["octet-align=1"] # response must not include fmtp 'octet-align=1'
+
+sendto_cfg = sip.SendtoCfg("AMR negotiation should not contain 'octet-align=1'", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/412_fmtp_amrnb_offer_band_eff2.py b/tests/pjsua/scripts-sendto/412_fmtp_amrnb_offer_band_eff2.py
new file mode 100644
index 0000000..d602386
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/412_fmtp_amrnb_offer_band_eff2.py
@@ -0,0 +1,32 @@
+# $Id: 412_fmtp_amrnb_offer_band_eff2.py 3664 2011-07-19 03:42:28Z nanang $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Answer for codec AMR should not contain fmtp octet-align=1
+
+sdp = \
+"""
+v=0
+o=- 3428650655 3428650655 IN IP4 192.168.1.9
+s=pjmedia
+c=IN IP4 192.168.1.9
+t=0 0
+a=X-nat:0
+m=audio 4000 RTP/AVP 99 101
+a=rtcp:4001 IN IP4 192.168.1.9
+a=rtpmap:99 AMR/8000
+a=fmtp:99 octet-align=0
+a=sendrecv
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+"""
+
+pjsua_args = "--null-audio --auto-answer 200 --add-codec AMR"
+extra_headers = ""
+include = [""]
+exclude = ["octet-align=1"] # response must not include fmtp 'octet-align=1'
+
+sendto_cfg = sip.SendtoCfg("AMR negotiation should not contain 'octet-align=1'", pjsua_args, sdp, 200,
+ extra_headers=extra_headers,
+ resp_inc=include, resp_exc=exclude)
+
diff --git a/tests/pjsua/scripts-sendto/500_pres_subscribe_with_bad_event.py b/tests/pjsua/scripts-sendto/500_pres_subscribe_with_bad_event.py
new file mode 100644
index 0000000..99e2aed
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/500_pres_subscribe_with_bad_event.py
@@ -0,0 +1,28 @@
+# $Id: 500_pres_subscribe_with_bad_event.py 2273 2008-09-11 10:25:51Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Ticket http://trac.pjsip.org/repos/ticket/623, based on
+# http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-September/004709.html:
+#
+# Assertion when receiving SUBSCRIBE with non-presence Event.
+complete_msg = \
+"""SUBSCRIBE sip:localhost;transport=UDP SIP/2.0
+Call-ID: f20e8783e764cae325dba17be4b8fe19@10.0.2.15
+CSeq: 1 SUBSCRIBE
+From: <sip:localhost>;tag=1710895
+To: <sip:localhost>
+Via: SIP/2.0/UDP localhost;rport;branch=z9hG4bKd88a.18c427d2.0
+Max-Forwards: 69
+Event: message-summary
+Contact: <sip:localhost>
+Allow: NOTIFY, SUBSCRIBE
+Content-Length: 0
+
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Incoming SUBSCRIBE with non presence",
+ "--null-audio",
+ "", 489, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/999_asterisk_err.py b/tests/pjsua/scripts-sendto/999_asterisk_err.py
new file mode 100644
index 0000000..18aaa06
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/999_asterisk_err.py
@@ -0,0 +1,45 @@
+# $Id: 999_asterisk_err.py 2081 2008-06-27 21:59:15Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# http://lists.pjsip.org/pipermail/pjsip_lists.pjsip.org/2008-June/003426.html:
+#
+# Report in pjsip mailing list on 27/6/2008 that this message will
+# cause pjsip to respond with 500 and then second request will cause
+# segfault.
+complete_msg = \
+"""INVITE sip:5001@192.168.1.200:5060;transport=UDP SIP/2.0
+Via: SIP/2.0/UDP 192.168.1.11:5060;branch=z9hG4bK74a60ee5;rport
+From: \"A user\" <sip:66660000@192.168.1.11>;tag=as2858a32c
+To: <sip:5001@192.168.1.200:5060;transport=UDP>
+Contact: <sip:66660000@192.168.1.11>
+Call-ID: 0bc7612c665e875a4a46411442b930a6@192.168.1.11
+CSeq: 102 INVITE
+User-Agent: Asterisk PBX
+Max-Forwards: 70
+Date: Fri, 27 Jun 2008 08:46:47 GMT
+Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, SUBSCRIBE, NOTIFY
+Supported: replaces
+Content-Type: application/sdp
+Content-Length: 285
+
+v=0
+o=root 4236 4236 IN IP4 192.168.1.11
+s=session
+c=IN IP4 192.168.1.11
+t=0 0
+m=audio 14390 RTP/AVP 0 3 8 101
+a=rtpmap:0 PCMU/8000
+a=rtpmap:3 GSM/8000
+a=rtpmap:8 PCMA/8000
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-16
+a=silenceSupp:off - - - -
+a=ptime:20
+a=sendrecv
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "Asterisk 500", "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sendto/999_message_no_body.py b/tests/pjsua/scripts-sendto/999_message_no_body.py
new file mode 100644
index 0000000..0663a6f
--- /dev/null
+++ b/tests/pjsua/scripts-sendto/999_message_no_body.py
@@ -0,0 +1,24 @@
+# $Id: 999_message_no_body.py 2884 2009-08-17 08:29:47Z bennylp $
+import inc_sip as sip
+import inc_sdp as sdp
+
+# Incoming MESSAGE without body is now accepted
+#
+complete_msg = \
+"""MESSAGE sip:localhost SIP/2.0
+Via: SIP/2.0/UDP 192.168.0.14:5060;rport;branch=z9hG4bKPj9db9
+Max-Forwards: 70
+From: <sip:192.168.0.14>;tag=08cd5bfc2d8a4fddb1f5e59c6961d298
+To: <sip:localhost>
+Call-ID: 3373d9eb32aa458db7e69c7ea51e0bd7
+CSeq: 23809 MESSAGE
+Contact: <sip:192.168.0.14:5060>
+User-Agent: PJSUA v0.8.0-trunk/win32
+Content-Type: text/plain
+Content-Length: 50
+"""
+
+
+sendto_cfg = sip.SendtoCfg( "empty MESSAGE", "--null-audio --auto-answer 200",
+ "", 200, complete_msg=complete_msg)
+
diff --git a/tests/pjsua/scripts-sipp/strict-route.py b/tests/pjsua/scripts-sipp/strict-route.py
new file mode 100644
index 0000000..fbf2b18
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/strict-route.py
@@ -0,0 +1,9 @@
+# $Id: strict-route.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id=sip:pjsua@localhost --username=pjsua --realm=* $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "ACK sip:proxy@.* SIP/2\.0", ""],
+ [0, const.STATE_CONFIRMED, "h"]
+ ]
diff --git a/tests/pjsua/scripts-sipp/strict-route.xml b/tests/pjsua/scripts-sipp/strict-route.xml
new file mode 100644
index 0000000..0ed6935
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/strict-route.xml
@@ -0,0 +1,161 @@
+<?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="Strict route test">
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 407 Proxy Authenticate
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Proxy-Authenticate: DIGEST realm="test", nonce="12345", algorithm=MD5
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 180 Ringing
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 183 progress
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:target@[local_ip]>
+ Record-route: <sip:proxy@[local_ip]:[local_port]>
+ Content-Type: application/sdp
+
+ v=0
+ o=- 3442013205 3442013205 IN IP4 [local_ip]
+ s=pjsip
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 4002 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:target@[local_ip]>
+ Record-route: <sip:proxy@[local_ip]:[local_port];maddr=[local_ip]>
+ Content-Type: application/sdp
+
+ v=0
+ o=- 3442013205 3442013205 IN IP4 [local_ip]
+ s=pjsip
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 4002 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <recv request="BYE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </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="1000"/>
+
+
+ <!-- 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/transfer-attended.py b/tests/pjsua/scripts-sipp/transfer-attended.py
new file mode 100644
index 0000000..2eaf44b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/transfer-attended.py
@@ -0,0 +1,52 @@
+# $Id: transfer-attended.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio", # UA0
+ "--null-audio", # UA1
+ "--null-audio" # UA2
+ ]
+
+PJSUA_EXPECTS = [
+ # A calls B
+ [0, "", "m"],
+ [0, "", "$PJSUA_URI[1]"],
+ [0, const.STATE_CALLING, ""],
+ [1, const.EVENT_INCOMING_CALL, "a"],
+ [1, "", "200"],
+ [0, const.STATE_CONFIRMED, ""],
+ [1, const.STATE_CONFIRMED, ""],
+
+ # B holds A
+ [1, "", "H"],
+ [0, const.MEDIA_HOLD, ""],
+ [1, const.MEDIA_HOLD, ""],
+
+ # B calls C
+ [1, "", "m"],
+ [1, "", "$PJSUA_URI[2]"],
+ [1, const.STATE_CALLING, ""],
+ [2, const.EVENT_INCOMING_CALL, "a"],
+ [2, "", "200"],
+ [1, const.STATE_CONFIRMED, ""],
+ [2, const.STATE_CONFIRMED, ""],
+
+ # B holds C
+ [1, "", "]"],
+ [1, "", "H"],
+ [2, const.MEDIA_HOLD, ""],
+ [1, const.MEDIA_HOLD, ""],
+ [1, "", "]"],
+
+ # B transfer A to C
+ [1, "", "X"],
+ [1, "", "1"],
+ [0, "Call .* is being transfered", ""],
+ [1, "Subscription state .* ACCEPTED", ""],
+ [0, const.STATE_CALLING, ""],
+ [2, "Call .* is being replaced", ""],
+ [1, "call transfered successfully", ""],
+ [0, const.MEDIA_ACTIVE, ""],
+ [2, const.MEDIA_ACTIVE, ""],
+ [1, const.STATE_DISCONNECTED, ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/transfer-attended.xml b/tests/pjsua/scripts-sipp/transfer-attended.xml
new file mode 100644
index 0000000..bd184d2
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/transfer-attended.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="Dummy scenario for call transfer">
+
+ <send retrans="500">
+ <![CDATA[
+
+ OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ Max-Forwards: 70
+ CSeq: 1 OPTIONS
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <pause milliseconds="1000"/>
+
+</scenario>
diff --git a/tests/pjsua/scripts-sipp/transfer-unattended.py b/tests/pjsua/scripts-sipp/transfer-unattended.py
new file mode 100644
index 0000000..14011e1
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/transfer-unattended.py
@@ -0,0 +1,30 @@
+# $Id: transfer-unattended.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio", # UA0
+ "--null-audio", # UA1
+ "--null-audio" # UA2
+ ]
+
+PJSUA_EXPECTS = [
+ # A calls B
+ [0, "", "m"],
+ [0, "", "$PJSUA_URI[1]"],
+ [0, const.STATE_CALLING, ""],
+ [1, const.EVENT_INCOMING_CALL, "a"],
+ [1, "", "200"],
+ [0, const.STATE_CONFIRMED, ""],
+ [1, const.STATE_CONFIRMED, ""],
+
+ # B transfer A to C
+ [1, "", "x"],
+ [1, "", "$PJSUA_URI[2]"],
+ [0, const.STATE_CALLING, ""],
+ [2, const.EVENT_INCOMING_CALL, "a"],
+ [2, "", "200"],
+ [0, const.MEDIA_ACTIVE, ""],
+ [2, const.MEDIA_ACTIVE, ""],
+ [1, "call transfered successfully", ""],
+ [1, const.STATE_DISCONNECTED, ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/transfer-unattended.xml b/tests/pjsua/scripts-sipp/transfer-unattended.xml
new file mode 100644
index 0000000..bd184d2
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/transfer-unattended.xml
@@ -0,0 +1,26 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="Dummy scenario for call transfer">
+
+ <send retrans="500">
+ <![CDATA[
+
+ OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ Max-Forwards: 70
+ CSeq: 1 OPTIONS
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <pause milliseconds="1000"/>
+
+</scenario>
diff --git a/tests/pjsua/scripts-sipp/uac-bad-ack.xml b/tests/pjsua/scripts-sipp/uac-bad-ack.xml
new file mode 100644
index 0000000..d93e30c
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-bad-ack.xml
@@ -0,0 +1,132 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="UAC with bad ACK">
+ <!-- UAC with bad ACK causes assertion with pjsip 1.4 -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <!-- 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 response="200" rtd="true">
+ </recv>
+
+ <!-- Packet lost can be simulated in any send/recv message by -->
+ <!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- This delay can be customized by the -d command-line option -->
+ <!-- or by adding a 'milliseconds = "value"' option here. -->
+ <pause/>
+
+ <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+ <send retrans="500">
+ <![CDATA[
+
+ BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bK-1
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 BYE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" crlf="true">
+ </recv>
+
+ <pause milliseconds="2000"/>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bK-1
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 BYE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- 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/uac-inv-and-ack-without-sdp.xml b/tests/pjsua/scripts-sipp/uac-inv-and-ack-without-sdp.xml
new file mode 100644
index 0000000..a61aba7
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-and-ack-without-sdp.xml
@@ -0,0 +1,91 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="UAC sending initial INVITE and ACK without SDP (#1045)">
+ <!-- UAC with bad ACK causes assertion with pjsip 1.4 -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ ]]>
+ </send>
+
+ <recv response="100" optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv request="BYE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ [last_Contact:]
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <!-- 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/uac-inv-multiple-require.xml b/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml
new file mode 100644
index 0000000..384be82
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-multiple-require.xml
@@ -0,0 +1,67 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="Multiple Require header fields">
+ <!-- UAC with bad ACK causes assertion with pjsip 1.4 -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Require: timer
+ Require: toto
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
+ s=-
+ c=IN IP[media_ip_type] [media_ip]
+ t=0 0
+ m=audio [media_port] RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="420" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <!-- 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/uac-inv-two-media-but-one-disabled-no-rtpmap.py b/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.py
new file mode 100644
index 0000000..fd82347
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.py
@@ -0,0 +1,7 @@
+# $Id: uac-inv-two-media-but-one-disabled-no-rtpmap.py 4177 2012-06-26 02:28:59Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --auto-answer=200"]
+
+PJSUA_EXPECTS = [[0, const.STATE_CONFIRMED, "v"]]
diff --git a/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.xml b/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.xml
new file mode 100644
index 0000000..0770fe9
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-two-media-but-one-disabled-no-rtpmap.xml
@@ -0,0 +1,97 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="Two media with one media disabled and no rtpmap for dynamic PT">
+ <!-- This causes assertion (on r3191 or older) if later pjsua initiates re-INVITE -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 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 4000 RTP/AVP 0
+ m=video 0 RTP/AVP 100
+
+ ]]>
+ </send>
+
+ <recv response="100" optional="true">
+ </recv>
+ <recv response="180" optional="true">
+ </recv>
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- Waiting re-INVITE from pjsua -->
+
+ <recv request="INVITE" crlf="true">
+ </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
+
+ 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 4000 RTP/AVP 0
+ m=video 0 RTP/AVP 100
+
+ ]]>
+ </send>
+
+ <!-- Expecting assertion here -->
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <!-- 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/uac-inv-without-sdp.py b/tests/pjsua/scripts-sipp/uac-inv-without-sdp.py
new file mode 100644
index 0000000..45f9467
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-without-sdp.py
@@ -0,0 +1,11 @@
+# $Id: uac-inv-without-sdp.py 4177 2012-06-26 02:28:59Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1"]
+
+PJSUA_EXPECTS = [[0, const.EVENT_INCOMING_CALL, "a"],
+ [0, "", "200"],
+ [0, const.MEDIA_ACTIVE, ""],
+ [0, const.STATE_CONFIRMED, "h"]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uac-inv-without-sdp.xml b/tests/pjsua/scripts-sipp/uac-inv-without-sdp.xml
new file mode 100644
index 0000000..929c83a
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-inv-without-sdp.xml
@@ -0,0 +1,110 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="UAC sending initial INVITE without SDP (#1526)">
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ ]]>
+ </send>
+
+ <recv response="100" optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+v=0
+o=BroadWorks 1378618 0 IN IP4 192.168.2.25
+s=-
+c=IN IP4 192.168.2.25
+t=0 0
+m=audio 4020 RTP/AVP 0 101
+c=IN IP4 192.168.2.25
+a=rtpmap:101 telephone-event/8000
+a=fmtp:101 0-15
+m=video 4022 RTP/AVP 97
+c=IN IP4 192.168.2.25
+b=TIAS:512000
+a=rtpmap:97 H264/90000
+a=fmtp:97 profile-level-id=42900b
+a=orient:portrait
+a=rtcp-fb:* nack pli
+
+ ]]>
+ </send>
+
+<!-- Assertion occured here before r4175 (see ticket #1526) -->
+
+ <recv request="BYE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ [last_Contact:]
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <!-- 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/uac-message-no-body.xml b/tests/pjsua/scripts-sipp/uac-message-no-body.xml
new file mode 100644
index 0000000..1b7f072
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-message-no-body.xml
@@ -0,0 +1,32 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="MESSAGE request without message body">
+ <send retrans="500">
+ <![CDATA[
+
+ MESSAGE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 MESSAGE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Message without body
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <!-- 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/uac-options.xml b/tests/pjsua/scripts-sipp/uac-options.xml
new file mode 100644
index 0000000..7b14884
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-options.xml
@@ -0,0 +1,54 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="UAC OPTIONS">
+ <!-- UAC with bad ACK causes assertion with pjsip 1.4 -->
+ <send retrans="500">
+ <![CDATA[
+
+ OPTIONS sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 OPTIONS
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: [len]
+
+ ]]>
+ </send>
+
+ <!-- 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 response="200" rtd="true">
+ </recv>
+
+
+ <!-- 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/uac-reinvite-bad-via-branch.xml b/tests/pjsua/scripts-sipp/uac-reinvite-bad-via-branch.xml
new file mode 100644
index 0000000..ed825c9
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-reinvite-bad-via-branch.xml
@@ -0,0 +1,173 @@
+<?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 -->
+<!-- -->
+<!-- -->
+
+<!-- Re-INVITE with bad Via branch (it has the same branch as the
+ previous INVITE (ticket #965) will cause assertion
+-->
+
+
+<scenario name="UAC re-INVITE with bad Via branch">
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bKPj-1
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Tester 234 123 IN IP4 127.0.0.1
+ s=Tester
+ c=IN IP4 127.0.0.1
+ t=0 0
+ m=audio 17424 RTP/AVP 0 101
+ a=rtpmap:101 telephone-event/8000
+ a=sendrecv
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <!-- 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 response="200" rtd="true">
+ </recv>
+
+ <!-- Packet lost can be simulated in any send/recv message by -->
+ <!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bKPj-2
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <!-- Re-INVITE with Via branch value the same as previous INVITE -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bKPj-1
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Tester 234 124 IN IP4 127.0.0.1
+ s=Tester
+ c=IN IP4 127.0.0.1
+ t=0 0
+ m=audio 17424 RTP/AVP 0 101
+ a=rtpmap:101 telephone-event/8000
+
+
+ ]]>
+ </send>
+
+ <!-- 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 response="500" rtd="true">
+ </recv>
+
+ <!-- Packet lost can be simulated in any send/recv message by -->
+ <!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bKPj-1
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000"/>
+
+
+ <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+ <send retrans="500">
+ <![CDATA[
+
+ BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 BYE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" crlf="true">
+ </recv>
+
+
+ <!-- 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/uac-reinvite-port-0-bad-sdp.xml b/tests/pjsua/scripts-sipp/uac-reinvite-port-0-bad-sdp.xml
new file mode 100644
index 0000000..d1cc04f
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-reinvite-port-0-bad-sdp.xml
@@ -0,0 +1,207 @@
+<?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 -->
+<!-- -->
+<!-- -->
+
+<!-- Note:
+ For this test to work, PJSUA-LIB needs to add video line, with
+ this patch:
+
+ pjsua_media.c:1253, after call to pjmedia_endpt_create_sdp():
+
+ if (1) {
+ pjmedia_sdp_media *m = PJ_POOL_ZALLOC_T(pool, pjmedia_sdp_media);
+ m->desc.media = pj_str("video");
+ m->desc.port = 3000;
+ m->desc.transport = pj_str("RTP/AVP");
+ m->desc.fmt_count = 1;
+ m->desc.fmt[0] = pj_str("0");
+ sdp->media[sdp->media_count++] = m;
+ }
+
+-->
+
+
+<scenario name="UAC with bad ACK">
+ <!-- UAC with bad ACK causes assertion with pjsip 1.4 -->
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Tester 234 123 IN IP4 89.208.145.194
+ s=Tester
+ c=IN IP4 89.208.145.194
+ t=0 0
+ m=audio 17424 RTP/AVP 111 0 18 101
+ a=rtpmap:111 SPEEX/16000
+ a=rtpmap:0 PCMU/8000
+ a=rtpmap:18 G729/8000
+ a=rtpmap:101 telephone-event/8000
+ a=sendrecv
+ a=rtcp:17425
+ m=video 11128 RTP/AVP 34 103 104
+ a=rtpmap:34 H263/90000
+ a=rtpmap:103 H263-1998/90000
+ a=rtpmap:104 H264/90000
+ a=sendrecv
+ a=rtcp:11129
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <!-- 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 response="200" rtd="true">
+ </recv>
+
+ <!-- Packet lost can be simulated in any send/recv message by -->
+ <!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 1 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- This delay can be customized by the -d command-line option -->
+ <!-- or by adding a 'milliseconds = "value"' option here. -->
+ <pause milliseconds="2000"/>
+
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Tester 234 124 IN IP4 89.208.145.194
+ s=Tester
+ c=IN IP4 89.208.145.194
+ t=0 0
+ m=audio 17424 RTP/AVP 111 0 18 101
+ a=rtpmap:111 SPEEX/16000
+ a=rtpmap:0 PCMU/8000
+ a=rtpmap:18 G729/8000
+ a=rtpmap:101 telephone-event/8000
+ a=sendrecv
+ a=rtcp:17425
+ m=video 0 RTP/AVP 34 103 104
+ a=sendrecv
+
+
+ ]]>
+ </send>
+
+ <!-- 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 response="200" rtd="true">
+ </recv>
+
+ <!-- Packet lost can be simulated in any send/recv message by -->
+ <!-- by adding the 'lost = "10"'. Value can be [1-100] percent. -->
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 2 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000"/>
+
+
+ <!-- The 'crlf' option inserts a blank line in the statistics report. -->
+ <send retrans="500">
+ <![CDATA[
+
+ BYE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 BYE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" crlf="true">
+ </recv>
+
+
+ <!-- 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/uac-subscribe.xml b/tests/pjsua/scripts-sipp/uac-subscribe.xml
new file mode 100644
index 0000000..c42e951
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-subscribe.xml
@@ -0,0 +1,113 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="UAC presence">
+ <!-- UAC Presence -->
+ <send retrans="500">
+ <![CDATA[
+
+ SUBSCRIBE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 1 SUBSCRIBE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Event: presence
+ Expires: 600
+ Accept: application/pidf+xml, application/xpidf+xml
+ Allow-Events: presence, refer
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <recv request="NOTIFY" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SUBSCRIBE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>
+ Call-ID: [call_id]
+ CSeq: 2 SUBSCRIBE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Event: presence
+ Expires: 0
+ Accept: application/pidf+xml, application/xpidf+xml
+ Allow-Events: presence, refer
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <recv request="NOTIFY" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <!-- 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/uac-ticket-1148.py b/tests/pjsua/scripts-sipp/uac-ticket-1148.py
new file mode 100644
index 0000000..414cb8c
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-ticket-1148.py
@@ -0,0 +1,7 @@
+# $Id: uac-ticket-1148.py 4177 2012-06-26 02:28:59Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --auto-answer=200"]
+
+PJSUA_EXPECTS = [[0, const.STATE_CONFIRMED, "v"]]
diff --git a/tests/pjsua/scripts-sipp/uac-ticket-1148.xml b/tests/pjsua/scripts-sipp/uac-ticket-1148.xml
new file mode 100644
index 0000000..2a2ec8b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uac-ticket-1148.xml
@@ -0,0 +1,98 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+
+<scenario name="Ticket #1148 (assertion when offering SDP media with port zero but answered with port non-zero)">
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 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 4000 RTP/AVP 0
+ m=video 5000 RTP/AVP 100
+ a=rtpmap:100 H261/90000
+
+ ]]>
+ </send>
+
+ <recv response="100" optional="true">
+ </recv>
+ <recv response="180" optional="true">
+ </recv>
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[service]@[remote_ip]:[remote_port] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To: sut <sip:[service]@[remote_ip]:[remote_port]>[peer_tag_param]
+ Call-ID: [call_id]
+ CSeq: 3 ACK
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Subject: Performance Test
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- Waiting re-INVITE from pjsua -->
+
+ <recv request="INVITE" crlf="true">
+ </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
+
+ 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 4000 RTP/AVP 0
+ m=video 5000 RTP/AVP 100
+ a=rtpmap:100 H261/90000
+
+ ]]>
+ </send>
+
+ <!-- Expecting assertion here -->
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <!-- 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-422-then-200-bad-se.xml b/tests/pjsua/scripts-sipp/uas-422-then-200-bad-se.xml
new file mode 100644
index 0000000..9f4df39
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-422-then-200-bad-se.xml
@@ -0,0 +1,118 @@
+<?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="Basic UAS responder">
+ <!-- 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 422 Session Timer too small
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+ Min-SE: 5400
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="true"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Allow: INVITE, OPTIONS, BYE, CANCEL, ACK, PRACK, UPDATE, REFER, SUBSCRIBE, NOTIFY, INFO, REGISTER
+ Allow-Events: telephone-event
+ Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+ Supported: replaces
+ Session-Expires: 3600;refresher=uas
+ Require: timer
+ Content-Type: application/sdp
+ Content-Disposition: session;handling=required
+ Content-Length: [len]
+
+ v=0
+ o=Some-UserAgent 68 210 IN IP4 [local_ip]
+ s=SIP Call
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 17294 RTP/AVP 0 101
+ c=IN IP4 [local_ip]
+ a=rtpmap:0 PCMU/8000
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-16
+ a=ptime:20
+
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+
+ <!-- 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-support-update.xml b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml
new file mode 100644
index 0000000..8016272
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts-support-update.xml
@@ -0,0 +1,168 @@
+<?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>
+
+ <recv response="200">
+ </recv>
+
+ <!-- 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 0000000..5ff1f99
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-180-multiple-fmts.xml
@@ -0,0 +1,171 @@
+<?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>
+
+ <recv response="200">
+ </recv>
+
+
+ <!-- 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-inv-without-sdp.xml b/tests/pjsua/scripts-sipp/uas-answer-200-inv-without-sdp.xml
new file mode 100644
index 0000000..70a3b5f
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-inv-without-sdp.xml
@@ -0,0 +1,80 @@
+<?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 200/INVITE without SDP (#1045)">
+ <!-- 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>
+
+ <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]
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+
+ <recv request="BYE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Content-Length: [len]
+
+ ]]>
+ </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 0000000..8605381
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts-support-update.xml
@@ -0,0 +1,138 @@
+<?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>
+
+ <recv response="200">
+ </recv>
+
+
+ <!-- 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 0000000..9fee67b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-multiple-fmts.xml
@@ -0,0 +1,138 @@
+<?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>
+
+ <recv response="200">
+ </recv>
+
+ <!-- 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-reinvite-without-sdp.py b/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.py
new file mode 100644
index 0000000..5bd516d
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.py
@@ -0,0 +1,7 @@
+# $Id: uas-answer-200-reinvite-without-sdp.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, const.STATE_CONFIRMED, "v"]]
diff --git a/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.xml b/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.xml
new file mode 100644
index 0000000..f51c421
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-reinvite-without-sdp.xml
@@ -0,0 +1,86 @@
+<?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 sending 200/re-INVITE response without SDP (#1045)">
+ <!-- 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>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [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
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Content-Length: [len]
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+
+ <!-- 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-update-without-sdp.py b/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.py
new file mode 100644
index 0000000..adc562a
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.py
@@ -0,0 +1,7 @@
+# $Id: uas-answer-200-update-without-sdp.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, const.STATE_CONFIRMED, "U"]]
diff --git a/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.xml b/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.xml
new file mode 100644
index 0000000..e561db1
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-answer-200-update-without-sdp.xml
@@ -0,0 +1,83 @@
+<?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 sending 200/UPDATE response without SDP answer (#1045)">
+ <!-- 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>
+
+ <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
+
+ ]]>
+ </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:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Content-Length: [len]
+
+ ]]>
+ </send>
+
+
+ <!-- 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-auth.py b/tests/pjsua/scripts-sipp/uas-auth.py
new file mode 100644
index 0000000..fbe422b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-auth.py
@@ -0,0 +1,7 @@
+# $Id: uas-auth.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id=sip:a@localhost --username=a --realm=* --registrar=$SIPP_URI"]
+
+PJSUA_EXPECTS = []
diff --git a/tests/pjsua/scripts-sipp/uas-auth.xml b/tests/pjsua/scripts-sipp/uas-auth.xml
new file mode 100644
index 0000000..96be0b9
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-auth.xml
@@ -0,0 +1,64 @@
+<?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 authorization server">
+ <recv request="REGISTER" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 401 Unauthorized
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ WWW-Authenticate: digest realm="test",stale=true
+ ]]>
+ </send>
+
+
+ <recv request="REGISTER" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Expires: 30
+ ]]>
+ </send>
+
+
+ <!-- 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-cancel-no-final.py b/tests/pjsua/scripts-sipp/uas-cancel-no-final.py
new file mode 100644
index 0000000..bf8f8d7
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-cancel-no-final.py
@@ -0,0 +1,7 @@
+# $Id: uas-cancel-no-final.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, const.STATE_EARLY, "h"]]
diff --git a/tests/pjsua/scripts-sipp/uas-cancel-no-final.xml b/tests/pjsua/scripts-sipp/uas-cancel-no-final.xml
new file mode 100644
index 0000000..e96f2a3
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-cancel-no-final.xml
@@ -0,0 +1,62 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="Basic UAS responder">
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 180 Ringing
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:192.168.0.15>
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <!-- Wait for CANCEL -->
+ <recv request="CANCEL" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <!-- 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-early-bye.xml b/tests/pjsua/scripts-sipp/uas-early-bye.xml
new file mode 100644
index 0000000..216b8b4
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-early-bye.xml
@@ -0,0 +1,68 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<scenario name="Early BYE">
+ <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>
+ <![CDATA[
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <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-Length: 0
+
+ ]]>
+ </send>
+
+ <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>
+
+ <recv response="200">
+ </recv>
+
+
+ <!-- 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-forked-100rel.xml b/tests/pjsua/scripts-sipp/uas-forked-100rel.xml
new file mode 100644
index 0000000..3a1ca22
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-forked-100rel.xml
@@ -0,0 +1,225 @@
+<?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="Forked INVITE, one of them require PRACK">
+ <recv request="INVITE" crlf="true">
+ <action>
+ <ereg regexp="branch=([^;]*)"
+ search_in="hdr"
+ header="Via"
+ assign_to="1,2"/>
+ <assign assign_to="1" variable="2"/>
+ <ereg regexp="CSeq: [ 0-9A-Z]+"
+ search_in="msg"
+ assign_to="4"/>
+ </action>
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [$4]
+ ]]>
+ </send>
+
+ <!-- Call leg 1 sends 180/Ringing -->
+ <send retrans="500">
+ <![CDATA[
+ SIP/2.0 180 Ringing1
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_1
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:UA_1@[local_ip]:[local_port]>
+ Require: 100rel
+ RSeq: 1000
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv request="PRACK" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000" />
+
+ <!-- Call leg 2: 180/Ringing -->
+ <send retrans="500">
+ <![CDATA[
+ SIP/2.0 180 Ringing2
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_2
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:UA_2@[local_ip]:[local_port]>
+ Require: 100rel
+ RSeq: 2000
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv request="PRACK" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000" />
+
+ <!-- Call leg 2: sends Ringing again with correct RSeq -->
+ <send retrans="500">
+ <![CDATA[
+ SIP/2.0 180 Ringing2b
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_2
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:UA_2@[local_ip]:[local_port]>
+ Require: 100rel
+ RSeq: 2001
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv request="PRACK" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000" />
+
+ <!-- Call leg 2: sends Ringing again with WRONG RSeq. There should be no PRACK -->
+ <send>
+ <![CDATA[
+ SIP/2.0 180 Ringing2c
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_2
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:UA_2@[local_ip]:[local_port]>
+ Require: 100rel
+ RSeq: 2004
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <pause milliseconds="2000" />
+
+ <!-- Then Call leg 1 sends 180/Ringing again -->
+ <send retrans="500">
+ <![CDATA[
+ SIP/2.0 180 Ringing1b
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_1
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:UA_1@[local_ip]:[local_port]>
+ Require: 100rel
+ RSeq: 1001
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv request="PRACK" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+
+ <pause milliseconds="2000" />
+
+ <!-- 603/Decline -->
+ <send>
+ <![CDATA[
+ SIP/2.0 603 Decline
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;rport=5080;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_1
+ [last_Call-ID:]
+ [$4]
+ Content-Length: 0
+ ]]>
+ </send>
+
+
+ <!-- Receive ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- 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-forked-200.xml b/tests/pjsua/scripts-sipp/uas-forked-200.xml
new file mode 100644
index 0000000..a67f8ca
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-forked-200.xml
@@ -0,0 +1,128 @@
+<?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="Forked INVITE, one of them require PRACK">
+ <recv request="INVITE" crlf="true">
+ <action>
+ <ereg regexp="branch=([^;]*)"
+ search_in="hdr"
+ header="Via"
+ assign_to="1,2"/>
+ <assign assign_to="1" variable="2"/>
+ </action>
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <!-- Call leg 1: 200/OK -->
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;rport=5080;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_1
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:UA_1@[local_ip]:[local_port]>
+ Content-Type: application/sdp
+
+ v=0
+ o=- 3442013205 3442013205 IN IP4 192.168.0.13
+ s=pjsip
+ c=IN IP4 192.168.0.13
+ t=0 0
+ m=audio 4002 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ ]]>
+ </send>
+
+ <!-- Call leg 2: 200/OK -->
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP 127.0.0.1;received=127.0.0.1;rport=5080;branch=[$2]
+ [last_From:]
+ [last_To:];tag=UA_2
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:UA_2@[local_ip]:[local_port]>
+ Content-Type: application/sdp
+
+ v=0
+ o=- 3442013205 3442013205 IN IP4 192.168.0.13
+ s=pjsip
+ c=IN IP4 192.168.0.13
+ t=0 0
+ m=audio 4002 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ ]]>
+ </send>
+
+ <!-- Receive ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- Receive BYE -->
+ <recv request="BYE" crlf="true">
+ </recv>
+
+ <!-- Send 200/OK to BYE -->
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+
+
+ <!-- Receive ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+
+ <!-- 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-inv-answered-with-srtp.xml b/tests/pjsua/scripts-sipp/uas-inv-answered-with-srtp.xml
new file mode 100644
index 0000000..1f928e7
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-inv-answered-with-srtp.xml
@@ -0,0 +1,77 @@
+<?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="Basic UAS responder">
+ <!-- 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
+
+ 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/SAVP 0 101
+ a=rtpmap:0 PCMU/8000
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-15
+ a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:D4Mf5fIPqxwse/lLrVc2XhLk7NSL6JI0k0Jps4Br
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+
+ <!-- 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-inv_401_retry_after_100.xml b/tests/pjsua/scripts-sipp/uas-inv_401_retry_after_100.xml
new file mode 100644
index 0000000..6debd13
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-inv_401_retry_after_100.xml
@@ -0,0 +1,106 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+<!-- -->
+
+<scenario name="Authorization retry after 1xx response test">
+ <!-- Wait for INVITE request -->
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <!-- Send 100 Trying -->
+ <send>
+ <![CDATA[
+
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <!-- Send 180 Ringing (with tag) -->
+ <send>
+ <![CDATA[
+
+ SIP/2.0 180 Ringing
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <!-- Send 401 Unauthorized -->
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 401 Unauthorized
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ WWW-Authenticate: Digest realm="sipp", nonce="1234"
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <!-- Wait for ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- Wait for INVITE retransmission -->
+ <recv request="INVITE" crlf="true">
+ </recv>
+
+ <!-- Send 500 Test Success to terminate the call -->
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 500 Test Success
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <!-- Wait for ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- 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-mwi-0.py b/tests/pjsua/scripts-sipp/uas-mwi-0.py
new file mode 100644
index 0000000..9c30a49
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-mwi-0.py
@@ -0,0 +1,7 @@
+# $Id: uas-mwi-0.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost:$SIPP_PORT --mwi"]
+
+PJSUA_EXPECTS = []
diff --git a/tests/pjsua/scripts-sipp/uas-mwi-0.xml b/tests/pjsua/scripts-sipp/uas-mwi-0.xml
new file mode 100644
index 0000000..6697c17
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-mwi-0.xml
@@ -0,0 +1,79 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+
+<scenario name="MWI server with immediate final notify">
+ <recv request="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 600
+ ]]>
+ </send>
+
+ <!-- initial notify is final notify -->
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: message-summary
+ Subscription-State: terminated;reason=goinghome
+ Content-Type: application/simple-message-summary
+ Content-Length: [len]
+
+ Messages-Waiting: yes
+ Voice-Message: 4/8 (1/2)
+
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <pause milliseconds="5000"/>
+
+ <!-- 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-mwi.py b/tests/pjsua/scripts-sipp/uas-mwi.py
new file mode 100644
index 0000000..df2e577
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-mwi.py
@@ -0,0 +1,7 @@
+# $Id: uas-mwi.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost:$SIPP_PORT --mwi"]
+
+PJSUA_EXPECTS = []
diff --git a/tests/pjsua/scripts-sipp/uas-mwi.xml b/tests/pjsua/scripts-sipp/uas-mwi.xml
new file mode 100644
index 0000000..ed81195
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-mwi.xml
@@ -0,0 +1,105 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+
+<scenario name="MWI server">
+ <recv request="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 600
+ ]]>
+ </send>
+
+ <!-- initial notify -->
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: message-summary
+ Subscription-State: active;expires=50
+ Content-Type: application/simple-message-summary
+ Content-Length: [len]
+
+ Messages-Waiting: yes
+ Voice-Message: 4/8 (1/2)
+
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <pause milliseconds="2000"/>
+
+
+ <!-- terminate subscription -->
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 2 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: message-summary
+ Subscription-State: terminated;reason=noresource
+ Content-Type: application/simple-message-summary
+ Content-Length: [len]
+
+ Messages-Waiting: yes
+ Voice-Message: 4/8 (1/2)
+
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <!-- 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-prack_fork.xml b/tests/pjsua/scripts-sipp/uas-prack_fork.xml
new file mode 100644
index 0000000..ddae747
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-prack_fork.xml
@@ -0,0 +1,130 @@
+<?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="Forked INVITE, one of them require PRACK">
+ <recv request="INVITE" crlf="true">
+ <action>
+ <ereg regexp="branch=([^;]*)"
+ search_in="hdr"
+ header="Via"
+ assign_to="3"/>
+ <ereg regexp="CSeq: ([0-9a-zA-Z ]*)"
+ search_in="msg"
+ assign_to="4"/>
+ </action>
+ </recv>
+
+ <send>
+ <![CDATA[
+ SIP/2.0 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <!-- Call leg 1: 180/Ringing -->
+ <send>
+ <![CDATA[
+ SIP/2.0 180 Ringing
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=1
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:WRONG_UA@192.168.0.1>
+ ]]>
+ </send>
+
+ <!-- Call leg 2: 180/Ringing with 100rel -->
+ <send retrans="1000">
+ <![CDATA[
+ SIP/2.0 180 Ringing
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=2
+ [last_Call-ID:]
+ [last_CSeq:]
+ Require: 100rel
+ RSeq: 1
+ Contact: <sip:RIGHT_UA@[local_ip]:[local_port]>
+ ]]>
+ </send>
+
+ <!-- Expect PRACK -->
+ <recv request="PRACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- Send 200/OK to PRACK -->
+ <send>
+ <![CDATA[
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <!-- Send 200/OK to INVITE -->
+ <send retrans="500">
+ <![CDATA[
+ SIP/2.0 200 OK
+ Via: SIP/2.0/UDP 127.0.0.1:5080;received=127.0.0.1;rport=5080;[$3]
+ [last_From:]
+ [last_To:];tag=2
+ [last_Call-ID:]
+ [$4]
+ Contact: <sip:RIGHT_UA@[local_ip]:[local_port]>
+ Content-Type: application/sdp
+
+ v=0
+ o=- 3442013205 3442013205 IN IP4 192.168.0.13
+ s=pjsip
+ c=IN IP4 192.168.0.13
+ t=0 0
+ m=audio 4002 RTP/AVP 0
+ a=rtpmap:0 PCMU/8000
+ ]]>
+ </send>
+
+ <!-- Receive ACK -->
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+
+ <!-- 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-reinv-and-ack-same-branch-without-sdp.xml b/tests/pjsua/scripts-sipp/uas-reinv-and-ack-same-branch-without-sdp.xml
new file mode 100644
index 0000000..cab4e53
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-reinv-and-ack-same-branch-without-sdp.xml
@@ -0,0 +1,118 @@
+<?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="Sending re-INVITE and ACK (with same branch) without SDP (#1045)">
+ <!-- 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>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [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
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <pause milliseconds="2000"/>
+
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bK-same-branch
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=z9hG4bK-same-branch
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 ACK
+ 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-reinv-and-ack-without-sdp.xml b/tests/pjsua/scripts-sipp/uas-reinv-and-ack-without-sdp.xml
new file mode 100644
index 0000000..90e1cec
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-reinv-and-ack-without-sdp.xml
@@ -0,0 +1,118 @@
+<?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="Sending re-INVITE and ACK without SDP (#1045)">
+ <!-- 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>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 200 OK
+ [last_Via:]
+ [last_From:]
+ [last_To:]
+ [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
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <pause milliseconds="2000"/>
+
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+ <recv response="100"
+ optional="true">
+ </recv>
+
+ <recv response="180" optional="true">
+ </recv>
+
+ <recv response="200" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 ACK
+ 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-reinv-glare.py b/tests/pjsua/scripts-sipp/uas-reinv-glare.py
new file mode 100644
index 0000000..a6b2d25
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-reinv-glare.py
@@ -0,0 +1,7 @@
+# $Id: uas-reinv-glare.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, const.STATE_CONFIRMED, "U"]]
diff --git a/tests/pjsua/scripts-sipp/uas-reinv-glare.xml b/tests/pjsua/scripts-sipp/uas-reinv-glare.xml
new file mode 100644
index 0000000..60c65f7
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-reinv-glare.xml
@@ -0,0 +1,153 @@
+<?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="Offer answer glare (#1166)">
+ <!-- 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>
+
+ <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=- 1 1 IN IP4 192.168.0.15
+ s=pjmedia
+ c=IN IP4 192.168.0.15
+ t=0 0
+ m=audio 4004 RTP/AVP 0
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <recv request="UPDATE" 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>
+
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=- 2 2 IN IP4 192.168.0.15
+ s=pjmedia
+ c=IN IP4 192.168.0.15
+ t=0 0
+ m=audio 4004 RTP/AVP 0
+
+ ]]>
+ </send>
+
+ <recv response="491" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Length: 0
+
+ ]]>
+ </send>
+
+
+ <send>
+ <![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>
+ <!-- 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-reinv-no-media.xml b/tests/pjsua/scripts-sipp/uas-reinv-no-media.xml
new file mode 100644
index 0000000..1c16fdd
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-reinv-no-media.xml
@@ -0,0 +1,116 @@
+<?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="Offer answer glare (#1166)">
+ <!-- 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>
+
+ <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=- 1 1 IN IP4 192.168.0.15
+ s=pjmedia
+ c=IN IP4 192.168.0.15
+ t=0 0
+ m=audio 4004 RTP/AVP 0
+
+ ]]>
+ </send>
+
+ <recv request="ACK" crlf="true">
+ </recv>
+
+ <send retrans="500">
+ <![CDATA[
+
+ INVITE sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=- 2 2 IN IP4 192.168.0.15
+ s=pjmedia
+ c=IN IP4 192.168.0.15
+ t=0 0
+ m=audio 0 RTP/AVP 0
+
+ ]]>
+ </send>
+
+ <recv response="488" rtd="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ ACK sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
+ From: sipp <sip:sipp@[local_ip]:[local_port]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 INVITE
+ 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-subscribe-late-notify.py b/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.py
new file mode 100644
index 0000000..3734132
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.py
@@ -0,0 +1,11 @@
+# $Id: uas-subscribe-late-notify.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "subscription state is ACTIVE", ""],
+ [0, "subscription state is TERMINATED", ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.xml b/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.xml
new file mode 100644
index 0000000..7bf0664
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-late-notify.xml
@@ -0,0 +1,152 @@
+<?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 -->
+<!-- -->
+<!-- Late NOTIFY scenario: -->
+<!-- - UAC sends SUBSCRIBE, we reply with 200 -->
+<!-- - we send NOTIFY, expect 200 -->
+<!-- - UAC sends SUBSCRIBE, we ignore -->
+<!-- - we send NOTIFY -->
+<!-- See http://trac.pjsip.org/repos/ticket/911 -->
+<!-- -->
+
+<scenario name="Late NOTIFY">
+ <!-- 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="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 60
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=z9hG4bKPj01
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: active;expires=10
+ Content-Type: application/pidf+xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:op="urn:oma:xml:prs:pidf:oma-pres" entity="sip:moto_red@ptt.intra.genaker.net">
+ <tuple id="17415d5738f332a64a2f1d8cfb4ab0a5">
+ <status>
+ <basic>open</basic>
+ </status>
+ <op:willingness>
+ <op:basic>closed</op:basic>
+ </op:willingness>
+ <op:barring-state>active</op:barring-state>
+ <op:service-description>
+ <op:service-id>org.openmobilealliance:PoC-session</op:service-id>
+ <op:version>1.0</op:version>
+ </op:service-description>
+ </tuple>
+ </presence>
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <recv request="SUBSCRIBE" crlf="true">
+ </recv>
+
+ <!-- UAC sends SUBSCRIBE, we do nothing -->
+ <send>
+ <![CDATA[
+
+ SIP/2.0 408 Timeout Bo
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:sipp@[local_ip]:[local_port]>
+ Content-Length: 0
+ Expires: 60
+ ]]>
+ </send>
+
+
+ <!-- <pause milliseconds="32070"/> -->
+
+ <!-- Now send late NOTIFY -->
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=z9hG4bKPj02
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 2 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: terminated;reason=timeout
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv response="481">
+ </recv>
+
+
+ <!-- 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-subscribe-multipart-notify.py b/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.py
new file mode 100644
index 0000000..6316c81
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.py
@@ -0,0 +1,11 @@
+# $Id: uas-subscribe-multipart-notify.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "status is Online", ""],
+ [0, "subscription state is TERMINATED", ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.xml b/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.xml
new file mode 100644
index 0000000..e2e1f9b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-multipart-notify.xml
@@ -0,0 +1,119 @@
+<?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 -->
+<!-- -->
+<!-- See https://trac.pjsip.org/repos/ticket/1146 -->
+<!-- -->
+
+<scenario name="SUBSCRIBE tests">
+ <!-- Establish subscription -->
+ <recv request="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 60
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=z9hG4bKPj01
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: active;expires=10
+ Content-Type: multipart/mixed;boundary=abcd
+
+ --abcd
+ Content-Type: text/plain
+
+ Hi there, please don't read this part.
+ --abcd
+ Content-Type: application/pidf+xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:op="urn:oma:xml:prs:pidf:oma-pres" entity="sip:test@pjsip.org">
+ <tuple id="17415d5738f332a64a2f1d8cfb4ab0a5">
+ <status>
+ <basic>open</basic>
+ </status>
+ </tuple>
+ </presence>
+ --abcd--
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <!-- Subscription has been established at this point -->
+
+
+ <!-- *******
+
+ Wait for subscription refresh, reply with 481
+
+ -->
+
+ <recv request="SUBSCRIBE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 481 You should resubscribe mow
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:sipp@[local_ip]:[local_port]>
+ Content-Length: 0
+ ]]>
+ </send>
+
+
+
+
+ <!-- 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-subscribe-notify-terminate.py b/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.py
new file mode 100644
index 0000000..ed64feb
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.py
@@ -0,0 +1,10 @@
+# $Id: uas-subscribe-notify-terminate.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "subscription state is TERMINATED", ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.xml b/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.xml
new file mode 100644
index 0000000..1171a56
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-notify-terminate.xml
@@ -0,0 +1,108 @@
+<?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 -->
+<!-- -->
+<!-- NOTIFY with instant termination: -->
+<!-- - UAC sends SUBSCRIBE, we reply with 200 and Expires=0 -->
+<!-- - we send NOTIFY with state=terminated -->
+<!-- -->
+
+<scenario name="NOTIFY with instant termination">
+ <!-- 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="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 0
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=z9hG4bKPj01
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: terminated;reason=timeout
+ Content-Type: application/pidf+xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:op="urn:oma:xml:prs:pidf:oma-pres" entity="sip:moto_red@ptt.intra.genaker.net">
+ <tuple id="17415d5738f332a64a2f1d8cfb4ab0a5">
+ <status>
+ <basic>open</basic>
+ </status>
+ <op:willingness>
+ <op:basic>closed</op:basic>
+ </op:willingness>
+ <op:barring-state>active</op:barring-state>
+ <op:service-description>
+ <op:service-id>org.openmobilealliance:PoC-session</op:service-id>
+ <op:version>1.0</op:version>
+ </op:service-description>
+ </tuple>
+ </presence>
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <pause milliseconds="32000"/>
+
+ <!-- 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-subscribe-refresh-481.py b/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.py
new file mode 100644
index 0000000..549e98f
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.py
@@ -0,0 +1,11 @@
+# $Id: uas-subscribe-refresh-481.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "status is Online", ""],
+ [0, "subscription state is TERMINATED", ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.xml b/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.xml
new file mode 100644
index 0000000..0cb2682
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-refresh-481.xml
@@ -0,0 +1,109 @@
+<?xml version="1.0" encoding="ISO-8859-1" ?>
+<!DOCTYPE scenario SYSTEM "sipp.dtd">
+
+<!-- This program is free software; you can redistribute it and/or -->
+<!-- modify it under the terms of the GNU General Public License as -->
+<!-- published by the Free Software Foundation; either version 2 of the -->
+<!-- License, or (at your option) any later version. -->
+<!-- -->
+<!-- This program is distributed in the hope that it will be useful, -->
+<!-- but WITHOUT ANY WARRANTY; without even the implied warranty of -->
+<!-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -->
+<!-- GNU General Public License for more details. -->
+<!-- -->
+<!-- You should have received a copy of the GNU General Public License -->
+<!-- along with this program; if not, write to the -->
+<!-- Free Software Foundation, Inc., -->
+<!-- 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -->
+<!-- -->
+
+<scenario name="SUBSCRIBE tests">
+ <!-- Establish subscription -->
+ <recv request="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 60
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=z9hG4bKPj01
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: active;expires=10
+ Content-Type: application/pidf+xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:op="urn:oma:xml:prs:pidf:oma-pres" entity="sip:moto_red@ptt.intra.genaker.net">
+ <tuple id="17415d5738f332a64a2f1d8cfb4ab0a5">
+ <status>
+ <basic>open</basic>
+ </status>
+ </tuple>
+ </presence>
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <!-- Subscription has been established at this point -->
+
+
+ <!-- *******
+
+ Wait for subscription refresh, reply with 481
+
+ -->
+
+ <recv request="SUBSCRIBE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 481 You should resubscribe mow
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:sipp@[local_ip]:[local_port]>
+ Content-Length: 0
+ ]]>
+ </send>
+
+
+
+
+ <!-- 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-subscribe-terminated-retry.py b/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.py
new file mode 100644
index 0000000..4a79d44
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.py
@@ -0,0 +1,11 @@
+# $Id: uas-subscribe-terminated-retry.py 4188 2012-06-29 09:01:17Z nanang $
+#
+import inc_const as const
+
+PJSUA = ["--null-audio --max-calls=1 --id sip:pjsua@localhost --add-buddy $SIPP_URI"]
+
+PJSUA_EXPECTS = [[0, "", "s"],
+ [0, "Subscribe presence of:", "1"],
+ [0, "Presence subscription .* is TERMINATED", ""],
+ [0, "Resubscribing .* in 5000 ms", ""]
+ ]
diff --git a/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.xml b/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.xml
new file mode 100644
index 0000000..4843cc3
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-subscribe-terminated-retry.xml
@@ -0,0 +1,120 @@
+<?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 -->
+<!-- -->
+<!-- Late NOTIFY scenario: -->
+<!-- - UAC sends SUBSCRIBE, we reply with 200 -->
+<!-- - we send NOTIFY, expect 200 -->
+<!-- - UAC sends SUBSCRIBE, we ignore -->
+<!-- - we send NOTIFY -->
+<!-- See http://trac.pjsip.org/repos/ticket/911 -->
+<!-- -->
+
+<scenario name="NOTIFY with terminated status with some reason code should cause UAC to retry">
+ <!-- Establish subscription -->
+ <recv request="SUBSCRIBE" 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>
+ <![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-Length: 0
+ Expires: 60
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 1 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: active;expires=50
+ Content-Type: application/pidf+xml
+
+ <?xml version="1.0" encoding="UTF-8"?>
+ <presence xmlns="urn:ietf:params:xml:ns:pidf" xmlns:op="urn:oma:xml:prs:pidf:oma-pres" entity="sip:moto_red@ptt.intra.genaker.net">
+ <tuple id="17415d5738f332a64a2f1d8cfb4ab0a5">
+ <status>
+ <basic>open</basic>
+ </status>
+ </tuple>
+ </presence>
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+ <!-- Subscription has been established at this point -->
+
+
+ <pause milliseconds="4000"/>
+
+ <!-- *******
+
+ Send NOTIFY termination
+
+ -->
+ <send retrans="500">
+ <![CDATA[
+ NOTIFY sip:[$5] SIP/2.0
+ Via: SIP/2.0/[transport] [local_ip]:[local_port];rport;branch=[branch]
+ From: sipp <sip:sipp@[local_ip]>;tag=[call_number]
+ To[$3]
+ Call-ID: [call_id]
+ Cseq: 3 NOTIFY
+ Contact: sip:sipp@[local_ip]:[local_port]
+ Max-Forwards: 70
+ Event: presence
+ Subscription-State: terminated;reason=probation;retry-after=5
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv response="200">
+ </recv>
+
+
+
+
+
+ <!-- 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-template.xml b/tests/pjsua/scripts-sipp/uas-template.xml
new file mode 100644
index 0000000..d51f89c
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-template.xml
@@ -0,0 +1,84 @@
+<?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="Basic UAS responder">
+ <!-- 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 100 Trying
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ ]]>
+ </send>
+
+ <send retrans="500">
+ <![CDATA[
+
+ SIP/2.0 301 Redirection
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:target@192.168.254.254>
+ Content-Length: 0
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="false"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <!-- 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-timer-reinvite.xml b/tests/pjsua/scripts-sipp/uas-timer-reinvite.xml
new file mode 100644
index 0000000..fe5169b
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-timer-reinvite.xml
@@ -0,0 +1,108 @@
+<?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 -->
+
+
+<!-- -->
+<!-- Session timer where UAS doesn't indicate support for UPDATE. -->
+<!-- In this case, UAC MUST use re-INVITE with SDP. -->
+
+<scenario name="Basic UAS responder">
+ <recv request="INVITE" crlf="true">
+ </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:[local_ip]:[local_port];transport=[transport]>
+ Require: timer
+ Session-Expires: 90;refresher=uac
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Some-UserAgent 68 210 IN IP4 [local_ip]
+ s=SIP Call
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 17294 RTP/AVP 0 101
+ c=IN IP4 [local_ip]
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-16
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="true"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <recv request="INVITE" crlf="true">
+ </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:[local_ip]:[local_port];transport=[transport]>
+ Require: timer
+ Session-Expires: 90;refresher=uac
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Some-UserAgent 68 210 IN IP4 [local_ip]
+ s=SIP Call
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 17294 RTP/AVP 0 101
+ c=IN IP4 [local_ip]
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-16
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+
+ <!-- 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-timer-update.xml b/tests/pjsua/scripts-sipp/uas-timer-update.xml
new file mode 100644
index 0000000..11a5973
--- /dev/null
+++ b/tests/pjsua/scripts-sipp/uas-timer-update.xml
@@ -0,0 +1,126 @@
+<?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 -->
+
+
+<!-- -->
+<!-- Session timer where UAS incidates support for UPDATE. -->
+<!-- In this case, UAC will first use empty UPDATE, which we -->
+<!-- will reply with 400. UAC MUST retry sending UPDATE with SDP. -->
+
+<scenario name="Basic UAS responder">
+ <recv request="INVITE" crlf="true">
+ </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:[local_ip]:[local_port];transport=[transport]>
+ Allow: UPDATE, INVITE
+ Require: timer
+ Session-Expires: 90;refresher=uac
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Some-UserAgent 68 210 IN IP4 [local_ip]
+ s=SIP Call
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 17294 RTP/AVP 0 101
+ c=IN IP4 [local_ip]
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-16
+ ]]>
+ </send>
+
+ <recv request="ACK"
+ optional="true"
+ rtd="true"
+ crlf="true">
+ </recv>
+
+ <recv request="UPDATE" crlf="true">
+ </recv>
+
+ <send>
+ <![CDATA[
+
+ SIP/2.0 400 Want SDP Body
+ [last_Via:]
+ [last_From:]
+ [last_To:];tag=[call_number]
+ [last_Call-ID:]
+ [last_CSeq:]
+ Contact: <sip:[local_ip]:[local_port];transport=[transport]>
+ Allow: INVITE
+ Require: timer
+ Session-Expires: 90;refresher=uac
+ Content-Length: 0
+ ]]>
+ </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:[local_ip]:[local_port];transport=[transport]>
+ Allow: INVITE
+ Require: timer
+ Session-Expires: 90;refresher=uac
+ Content-Type: application/sdp
+ Content-Length: [len]
+
+ v=0
+ o=Some-UserAgent 68 210 IN IP4 [local_ip]
+ s=SIP Call
+ c=IN IP4 [local_ip]
+ t=0 0
+ m=audio 17294 RTP/AVP 0 101
+ c=IN IP4 [local_ip]
+ a=rtpmap:101 telephone-event/8000
+ a=fmtp:101 0-16
+ ]]>
+ </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/tools/Makefile b/tests/pjsua/tools/Makefile
new file mode 100644
index 0000000..189eb00
--- /dev/null
+++ b/tests/pjsua/tools/Makefile
@@ -0,0 +1,21 @@
+#Modify this to point to the PJSIP location.
+PJBASE=~/Desktop/project/pjproject
+
+include $(PJBASE)/build.mak
+
+CC = $(APP_CC)
+LDFLAGS = $(APP_LDFLAGS)
+LDLIBS = $(APP_LDLIBS)
+CFLAGS = $(APP_CFLAGS)
+CPPFLAGS= ${CFLAGS}
+
+# If your application is in a file named myapp.cpp or myapp.c
+# # this is the line you will need to build the binary.
+# all: myapp
+#
+cmp_wav: cmp_wav.c
+ $(CC) -o $@ $< $(CPPFLAGS) $(LDFLAGS) $(LDLIBS)
+
+clean:
+ rm -f cmp_wav.o cmp_wav
+
diff --git a/tests/pjsua/tools/cmp_wav.c b/tests/pjsua/tools/cmp_wav.c
new file mode 100644
index 0000000..e3c864c
--- /dev/null
+++ b/tests/pjsua/tools/cmp_wav.c
@@ -0,0 +1,262 @@
+/* $Id: cmp_wav.c 3553 2011-05-05 06:14:19Z nanang $ */
+/*
+ * Copyright (C) 2008-2011 Teluu Inc. (http://www.teluu.com)
+ * Copyright (C) 2003-2008 Benny Prijono <benny@prijono.org>
+ *
+ * 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
+ */
+#include <pjmedia.h>
+#include <pjlib-util.h>
+#include <pjlib.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define app_perror(a,b,c) printf("%s: %s (%d)", a, b, c)
+
+
+/* For logging purpose. */
+#define THIS_FILE "cmp_wav.c"
+#define BYTES_PER_FRAME 512
+
+static const char *desc =
+" FILE \n"
+" \n"
+" cmp_wav.c \n"
+" \n"
+" PURPOSE \n"
+" \n"
+" Compare two WAV files. \n"
+" \n"
+" USAGE \n"
+" \n"
+" cmp_wav ORIGINAL_WAV DEGRADED_WAV [TIME] [DETAIL] \n"
+" \n"
+" ORIGINAL_WAV The original WAV file as reference. \n"
+" DEGRADED_WAV The degraded WAV file. \n"
+" TIME Compare only some part of the files \n"
+" (in ms, since the beginning). \n"
+" Specify 0 (default) to compare the whole time. \n"
+" DETAIL Show detail result, 1 or 0 (default=0, means no)\n"
+" \n"
+" Both files must have same clock rate and must contain \n"
+" uncompressed (i.e. 16bit) PCM. \n";
+
+
+/* Sum of multiplication of corresponding samples in buf1 & buf2 */
+double sum_mult_sig(pj_int16_t *buf1, pj_int16_t *buf2, unsigned nsamples)
+{
+ double mag = 0;
+
+ while (nsamples--)
+ mag += (double)*buf1++ * (double)*buf2++;
+
+ return mag;
+}
+
+
+/*
+ * main()
+ */
+int main(int argc, char *argv[])
+{
+ pj_caching_pool cp;
+ pjmedia_endpt *med_endpt;
+ pj_pool_t *pool;
+ pjmedia_port *file_ori_port;
+ pjmedia_port *file_deg_port;
+ pj_status_t status;
+ unsigned first_nsamples = 0;
+ unsigned samples_compared = 0;
+
+ char buf1[BYTES_PER_FRAME];
+ char buf2[BYTES_PER_FRAME];
+
+ double ref_mag = 0;
+ double deg_mag = 0;
+ double mix_mag = 0;
+
+ int detail = 0;
+ int res_deg, res_mix, res_overall;
+
+ if (argc < 3) {
+ puts("Error: original & degraded filename required");
+ puts(desc);
+ return 1;
+ }
+
+ /* Set log level. */
+ pj_log_set_level(3);
+
+ /* Must init PJLIB first: */
+ status = pj_init();
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Must create a pool factory before we can allocate any memory. */
+ pj_caching_pool_init(&cp, &pj_pool_factory_default_policy, 0);
+
+ /*
+ * Initialize media endpoint.
+ * This will implicitly initialize PJMEDIA too.
+ */
+ status = pjmedia_endpt_create(&cp.factory, NULL, 1, &med_endpt);
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Create memory pool for our file player */
+ pool = pj_pool_create( &cp.factory, /* pool factory */
+ "wav", /* pool name. */
+ 4000, /* init size */
+ 4000, /* increment size */
+ NULL /* callback on error */
+ );
+
+ /* Create file media port from the original WAV file */
+ status = pjmedia_wav_player_port_create( pool, /* memory pool */
+ argv[1], /* file to play */
+ 40, /* ptime. */
+ PJMEDIA_FILE_NO_LOOP, /* flags */
+ 0, /* default buffer */
+ &file_ori_port/* returned port */
+ );
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to use WAV file", status);
+ return 1;
+ }
+
+ /* Create file media port from the degraded WAV file */
+ status = pjmedia_wav_player_port_create( pool, /* memory pool */
+ argv[2], /* file to play */
+ 40, /* ptime. */
+ PJMEDIA_FILE_NO_LOOP, /* flags */
+ 0, /* default buffer */
+ &file_deg_port/* returned port */
+ );
+ if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Unable to use WAV file", status);
+ return 1;
+ }
+
+ if (file_ori_port->info.clock_rate != file_deg_port->info.clock_rate) {
+ app_perror(THIS_FILE, "Clock rates must be same.", PJ_EINVAL);
+ return 1;
+ }
+
+ if (argc > 3)
+ first_nsamples = atoi(argv[3]) * file_ori_port->info.clock_rate / 1000;
+
+ if (argc > 4)
+ detail = atoi(argv[4]);
+
+ while (1) {
+ pjmedia_frame f1, f2;
+
+ f1.buf = buf1;
+ f1.size = BYTES_PER_FRAME;
+ f2.buf = buf2;
+ f2.size = BYTES_PER_FRAME;
+
+ status = pjmedia_port_get_frame(file_ori_port, &f1);
+ if (status == PJ_EEOF) {
+ break;
+ } else if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Error occured while reading file", status);
+ break;
+ }
+ status = pjmedia_port_get_frame(file_deg_port, &f2);
+ if (status == PJ_EEOF) {
+ break;
+ } else if (status != PJ_SUCCESS) {
+ app_perror(THIS_FILE, "Error occured while reading file", status);
+ break;
+ }
+
+ /* Calculate magnitudes */
+ ref_mag += sum_mult_sig(f1.buf, f1.buf, BYTES_PER_FRAME >> 1);
+ deg_mag += sum_mult_sig(f2.buf, f2.buf, BYTES_PER_FRAME >> 1);
+ mix_mag += sum_mult_sig(f1.buf, f2.buf, BYTES_PER_FRAME >> 1);
+
+ samples_compared += BYTES_PER_FRAME >> 1;
+ if (first_nsamples && samples_compared >= first_nsamples)
+ break;
+ }
+
+ /* Degraded magnitude compared to reference magnitude
+ */
+ res_deg = (int) (deg_mag / ref_mag * 100.0);
+ if (res_deg < 0)
+ res_deg = -1;
+ else if (res_deg >= 81)
+ res_deg = 9;
+ else
+ res_deg = pj_isqrt(res_deg);
+
+ /* Mixed magnitude (don't know what this is actually :D) compared to
+ * reference magnitude
+ */
+ res_mix = (int) (mix_mag / ref_mag * 100.0);
+ if (res_mix < 0)
+ res_mix = -1;
+ else if (res_mix >= 81)
+ res_mix = 9;
+ else
+ res_mix = pj_isqrt(res_mix);
+
+ /* Overall score.
+ * If mixed score is -1, then overall score should be -1 as well.
+ * Apply no weighting (1:1) for now.
+ */
+ if (res_mix == -1)
+ res_overall = -1;
+ else
+ res_overall = (res_mix*1 + res_deg*1) / 2;
+
+ if (detail) {
+ printf("Reference = %.0f\n", ref_mag);
+ printf("Degraded = %.0f\n", deg_mag);
+ printf("Mixed = %.0f\n", mix_mag);
+
+ printf("\n");
+
+ printf("Score 1 = %d\n", res_deg);
+ printf("Score 2 = %d\n", res_mix);
+
+ printf("\n");
+ }
+
+ printf("Overall = %d\n", res_overall);
+
+ /* Destroy file port */
+ status = pjmedia_port_destroy( file_ori_port );
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ status = pjmedia_port_destroy( file_deg_port );
+ PJ_ASSERT_RETURN(status == PJ_SUCCESS, 1);
+
+ /* Release application pool */
+ pj_pool_release( pool );
+
+ /* Destroy media endpoint. */
+ pjmedia_endpt_destroy( med_endpt );
+
+ /* Destroy pool factory */
+ pj_caching_pool_destroy( &cp );
+
+ /* Shutdown PJLIB */
+ pj_shutdown();
+
+
+ /* Done. */
+ return 0;
+}
+
diff --git a/tests/pjsua/wavs/.keep b/tests/pjsua/wavs/.keep
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/tests/pjsua/wavs/.keep