diff --git a/Freeswitch.2017.sln b/Freeswitch.2017.sln index be107fde3e..d6b9e27875 100644 --- a/Freeswitch.2017.sln +++ b/Freeswitch.2017.sln @@ -564,8 +564,6 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cidlookup", "src\mod\ap EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_cdr_mongodb", "src\mod\event_handlers\mod_cdr_mongodb\mod_cdr_mongodb.2017.vcxproj", "{4DFF29B4-2976-447D-A8B3-43476451517C}" EndProject -Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ffmpeg", "libs\win32\ffmpeg\ffmpeg.2017.vcxproj", "{BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}" -EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{9388C266-C3FC-468A-92EF-0CBC35941412}" EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "test_mod_av", "src\mod\applications\mod_av\test\test_mod_av.2017.vcxproj", "{7926CB0D-62CE-4A09-AE94-1DA2BC92D625}" @@ -578,6 +576,10 @@ Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "48khz music", "libs\win32\S EndProject Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "mod_signalwire", "src\mod\applications\mod_signalwire\mod_signalwire.2017.vcxproj", "{B19AE6FC-BFFF-428D-B483-3BBEAECCC618}" EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "ffmpeg", "libs\win32\ffmpeg\ffmpeg.2017.vcxproj", "{BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}" +EndProject +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Setup.CA.DownloadOpenH264", "w32\Setup\CustomActions\Setup.CA.DownloadOpenH264\Setup.CA.DownloadOpenH264.csproj", "{EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}" +EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution All|Win32 = All|Win32 @@ -2353,14 +2355,16 @@ Global {841C345F-FCC7-4F64-8F54-0281CEABEB01}.Debug|x64.ActiveCfg = Debug|x64 {841C345F-FCC7-4F64-8F54-0281CEABEB01}.Release|Win32.ActiveCfg = Release|Win32 {841C345F-FCC7-4F64-8F54-0281CEABEB01}.Release|x64.ActiveCfg = Release|x64 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|Win32.ActiveCfg = Release|Win32 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|Win32.Build.0 = Release|Win32 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|x64.ActiveCfg = Release|x64 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|x64.Build.0 = Release|x64 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.Debug|Win32.ActiveCfg = Debug|Win32 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.Debug|x64.ActiveCfg = Debug|x64 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.Release|Win32.ActiveCfg = Release|Win32 - {7AEE504B-23B6-4B05-829E-7CD34855F146}.Release|x64.ActiveCfg = Release|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|Win32.ActiveCfg = Release-x264|Win32 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|Win32.Build.0 = Release-x264|Win32 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|x64.ActiveCfg = Release-x264|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.All|x64.Build.0 = Release-x264|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Debug|Win32.ActiveCfg = Debug-x264|Win32 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Debug|x64.ActiveCfg = Debug-openh264|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Debug|x64.Build.0 = Debug-openh264|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Release|Win32.ActiveCfg = Release-x264|Win32 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Release|x64.ActiveCfg = Release-openh264|x64 + {7AEE504B-23B6-4B05-829E-7CD34855F146}.Release|x64.Build.0 = Release-openh264|x64 {20179127-853B-4FE9-B7C0-9E817E6A3A72}.All|Win32.ActiveCfg = Release|Win32 {20179127-853B-4FE9-B7C0-9E817E6A3A72}.All|Win32.Build.0 = Release|Win32 {20179127-853B-4FE9-B7C0-9E817E6A3A72}.All|x64.ActiveCfg = Release|x64 @@ -2585,14 +2589,6 @@ Global {4DFF29B4-2976-447D-A8B3-43476451517C}.Release|Win32.Build.0 = Release|Win32 {4DFF29B4-2976-447D-A8B3-43476451517C}.Release|x64.ActiveCfg = Release|x64 {4DFF29B4-2976-447D-A8B3-43476451517C}.Release|x64.Build.0 = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|Win32.ActiveCfg = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|Win32.Build.0 = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|x64.ActiveCfg = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|x64.Build.0 = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Debug|Win32.ActiveCfg = Debug|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Debug|x64.ActiveCfg = Debug|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Release|Win32.ActiveCfg = Release|x64 - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Release|x64.ActiveCfg = Release|x64 {7926CB0D-62CE-4A09-AE94-1DA2BC92D625}.All|Win32.ActiveCfg = Release|Win32 {7926CB0D-62CE-4A09-AE94-1DA2BC92D625}.All|Win32.Build.0 = Release|Win32 {7926CB0D-62CE-4A09-AE94-1DA2BC92D625}.All|x64.ActiveCfg = Release|x64 @@ -2641,6 +2637,28 @@ Global {B19AE6FC-BFFF-428D-B483-3BBEAECCC618}.Release|Win32.Build.0 = Release|Win32 {B19AE6FC-BFFF-428D-B483-3BBEAECCC618}.Release|x64.ActiveCfg = Release|x64 {B19AE6FC-BFFF-428D-B483-3BBEAECCC618}.Release|x64.Build.0 = Release|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|Win32.ActiveCfg = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|Win32.Build.0 = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|x64.ActiveCfg = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.All|x64.Build.0 = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Debug|Win32.ActiveCfg = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Debug|x64.ActiveCfg = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Debug|x64.Build.0 = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Release|Win32.ActiveCfg = Debug-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Release|x64.ActiveCfg = Release-openh264|x64 + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED}.Release|x64.Build.0 = Release-openh264|x64 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.All|Win32.ActiveCfg = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.All|Win32.Build.0 = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.All|x64.ActiveCfg = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.All|x64.Build.0 = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Debug|Win32.ActiveCfg = Debug|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Debug|Win32.Build.0 = Debug|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Debug|x64.ActiveCfg = Debug|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Debug|x64.Build.0 = Debug|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Release|Win32.ActiveCfg = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Release|Win32.Build.0 = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Release|x64.ActiveCfg = Release|x86 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042}.Release|x64.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE @@ -2845,12 +2863,12 @@ Global {40C4E2A2-B49B-496C-96D6-C04B890F7F88} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {0A130A8B-3076-4619-BADF-9E86F621AEEC} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} {4DFF29B4-2976-447D-A8B3-43476451517C} = {9ADF1E48-2F5C-4ED7-A893-596259FABFE0} - {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} {7926CB0D-62CE-4A09-AE94-1DA2BC92D625} = {9388C266-C3FC-468A-92EF-0CBC35941412} {EF62B845-A0CE-44FD-B8E6-475FE87D06C3} = {9388C266-C3FC-468A-92EF-0CBC35941412} {8154C82D-58EE-4145-9DEC-A445A5AA3D6B} = {4F227C26-768F-46A3-8684-1D08A46FB374} {EBD0B6B4-C5CA-46B0-BBC7-DBA71DF05D31} = {4F227C26-768F-46A3-8684-1D08A46FB374} {B19AE6FC-BFFF-428D-B483-3BBEAECCC618} = {E72B5BCB-6462-4D23-B419-3AF1A4AC3D78} + {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED} = {EB910B0D-F27D-4B62-B67B-DE834C99AC5B} EndGlobalSection GlobalSection(ExtensibilityGlobals) = postSolution SolutionGuid = {09840DE7-9208-45AA-9667-1A71EE93BD1E} diff --git a/build/config/erlang.m4 b/build/config/erlang.m4 index 7e4dc35b9b..83a089c8cd 100644 --- a/build/config/erlang.m4 +++ b/build/config/erlang.m4 @@ -75,10 +75,15 @@ then [AC_MSG_ERROR([ei.h is unusable - are the erlang development headers installed?])] ) else + ERLANG_MAJOR="`echo "$ERLANG_VER" | sed 's/\([[^.]][[^.]]*\).*/\1/'`" + ERLANG_MINOR="`echo "$ERLANG_VER" | sed 's/[[^.]][[^.]]*.\([[^.]][[^.]]*\).*/\1/'`" ERLANG_LDFLAGS="$ERLANG_LDFLAGS -lei" AC_MSG_NOTICE([Your erlang seems OK, do not forget to enable mod_erlang_event in modules.conf]) AC_SUBST([ERLANG_CFLAGS], [$ERLANG_CFLAGS]) AC_SUBST([ERLANG_LDFLAGS], [$ERLANG_LDFLAGS]) + AC_SUBST([ERLANG_VERSION], [$ERLANG_VER]) + AC_SUBST([ERLANG_MAJOR], [$ERLANG_MAJOR]) + AC_SUBST([ERLANG_MINOR], [$ERLANG_MINOR]) AM_CONDITIONAL([HAVE_ERLANG],[true]) fi diff --git a/build/modules.conf.in b/build/modules.conf.in index a3297e744c..98f4b7d7fc 100644 --- a/build/modules.conf.in +++ b/build/modules.conf.in @@ -125,6 +125,7 @@ formats/mod_sndfile #formats/mod_ssml formats/mod_tone_stream #formats/mod_vlc +#formats/mod_opusfile #languages/mod_basic #languages/mod_java languages/mod_lua diff --git a/conf/testing/autoload_configs/modules.conf.xml b/conf/testing/autoload_configs/modules.conf.xml index 9849ce2d94..7c65886a9e 100644 --- a/conf/testing/autoload_configs/modules.conf.xml +++ b/conf/testing/autoload_configs/modules.conf.xml @@ -26,6 +26,7 @@ + diff --git a/conf/vanilla/autoload_configs/avmd.conf.xml b/conf/vanilla/autoload_configs/avmd.conf.xml index f40c0a0cda..86b2500bad 100644 --- a/conf/vanilla/autoload_configs/avmd.conf.xml +++ b/conf/vanilla/autoload_configs/avmd.conf.xml @@ -62,6 +62,12 @@ + + + + + + diff --git a/conf/vanilla/autoload_configs/conference.conf.xml b/conf/vanilla/autoload_configs/conference.conf.xml index d683c41227..b927d9b883 100644 --- a/conf/vanilla/autoload_configs/conference.conf.xml +++ b/conf/vanilla/autoload_configs/conference.conf.xml @@ -250,17 +250,123 @@ - + + - - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/vanilla/autoload_configs/modules.conf.xml b/conf/vanilla/autoload_configs/modules.conf.xml index 0b336a168d..8eff5fe263 100644 --- a/conf/vanilla/autoload_configs/modules.conf.xml +++ b/conf/vanilla/autoload_configs/modules.conf.xml @@ -102,9 +102,10 @@ - + + diff --git a/conf/vanilla/autoload_configs/verto.conf.xml b/conf/vanilla/autoload_configs/verto.conf.xml index 7714053083..899aaeb6c2 100644 --- a/conf/vanilla/autoload_configs/verto.conf.xml +++ b/conf/vanilla/autoload_configs/verto.conf.xml @@ -23,10 +23,10 @@ - + - - + + @@ -47,8 +47,8 @@ - - + + diff --git a/conf/vanilla/dialplan/default.xml b/conf/vanilla/dialplan/default.xml index 08552ef229..7f7ff6fa35 100644 --- a/conf/vanilla/dialplan/default.xml +++ b/conf/vanilla/dialplan/default.xml @@ -387,7 +387,7 @@ - + @@ -410,7 +410,28 @@ - + + + + + + + + + + + + + + + + + + + + + + diff --git a/conf/vanilla/dialplan/public.xml b/conf/vanilla/dialplan/public.xml index e44006e33b..020bb62c80 100644 --- a/conf/vanilla/dialplan/public.xml +++ b/conf/vanilla/dialplan/public.xml @@ -42,6 +42,12 @@ + + + + + + - - + + diff --git a/conf/vanilla/sip_profiles/internal.xml b/conf/vanilla/sip_profiles/internal.xml index 5bee06dbfd..3205e179b9 100644 --- a/conf/vanilla/sip_profiles/internal.xml +++ b/conf/vanilla/sip_profiles/internal.xml @@ -281,8 +281,8 @@ auto - Use guessed ip. auto-nat - Use ip learned from NAT-PMP or UPNP --> - - + + diff --git a/conf/vanilla/vars.xml b/conf/vanilla/vars.xml index b45267751f..387592c978 100644 --- a/conf/vanilla/vars.xml +++ b/conf/vanilla/vars.xml @@ -256,8 +256,8 @@ 127 - BV32 --> - - + + - + - + - - + + diff --git a/configure.ac b/configure.ac index 3ccf8560eb..fcc3d60a5c 100644 --- a/configure.ac +++ b/configure.ac @@ -449,19 +449,6 @@ elif test "x${ax_cv_c_compiler_vendor}" = "xgnu" ; then fi fi -# Enable clang address sanitizer bit build -AC_ARG_ENABLE(address_sanitizer, - [AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])], - [enable_address_sanitizer="$enable_address_sanitizer"], - [enable_address_sanitizer="no"]) - -if test "${enable_address_sanitizer}" = "yes"; then - APR_ADDTO(CFLAGS, -fsanitize=address -fno-omit-frame-pointer) - APR_ADDTO(CXXFLAGS, -fsanitize=address -fno-omit-frame-pointer) - APR_ADDTO(LDFLAGS, -fsanitize=address) -fi - - case "${ax_cv_c_compiler_vendor}" in sun) VISIBILITY_FLAG=-xldscope=hidden @@ -1389,6 +1376,14 @@ PKG_CHECK_MODULES([OPENCV], [opencv >= 2.4.5],[ AM_CONDITIONAL([HAVE_OPENCV],[true])],[ AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_OPENCV],[false])]) +PKG_CHECK_MODULES([OPUSFILE_DECODE], [opusfile >= 0.5],[ + AM_CONDITIONAL([HAVE_OPUSFILE_DECODE],[true])],[ + AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_OPUSFILE_DECODE],[false])]) +PKG_CHECK_MODULES([OPUSFILE_ENCODE], [libopusenc >= 0.1],[ + AM_CONDITIONAL([HAVE_OPUSFILE_ENCODE],[true])],[ + AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_OPUSFILE_ENCODE],[false])]) + + PKG_CHECK_MODULES([MAGICK], [ImageMagick >= 6.0.0],[ AM_CONDITIONAL([HAVE_MAGICK],[true])],[ AC_MSG_RESULT([no]); AM_CONDITIONAL([HAVE_MAGICK],[false])]) @@ -1599,6 +1594,7 @@ if test x$HAVE_OPENSSL = x1; then APR_ADDTO(SWITCH_AM_CFLAGS, -DHAVE_OPENSSL) AC_CHECK_LIB(ssl, SSL_CTX_set_tlsext_use_srtp, AC_DEFINE_UNQUOTED(HAVE_OPENSSL_DTLS_SRTP, 1, HAVE_OPENSSL_DTLS_SRTP), AC_MSG_ERROR([OpenSSL >= 1.0.1e and associated developement headers required])) AC_CHECK_LIB(ssl, DTLSv1_method, AC_DEFINE_UNQUOTED(HAVE_OPENSSL_DTLS, 1, HAVE_OPENSSL_DTLS), AC_MSG_ERROR([OpenSSL >= 1.0.1e and associaed developement headers required])) + AC_CHECK_LIB(ssl, DTLSv1_2_method, AC_DEFINE_UNQUOTED(HAVE_OPENSSL_DTLSv1_2_method, 1, [DTLS version 1.2 is available])) else AC_MSG_ERROR([OpenSSL >= 1.0.1e and associated developement headers required]) fi @@ -1810,6 +1806,18 @@ AC_SUBST(SNMP_LIBS) CHECK_ERLANG +# Enable clang address sanitizer bit build +AC_ARG_ENABLE(address_sanitizer, + [AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])], + [enable_address_sanitizer="$enable_address_sanitizer"], + [enable_address_sanitizer="no"]) + +if test "${enable_address_sanitizer}" = "yes"; then + APR_ADDTO(CFLAGS, -fsanitize=address -fno-omit-frame-pointer) + APR_ADDTO(CXXFLAGS, -fsanitize=address -fno-omit-frame-pointer) + APR_ADDTO(LDFLAGS, -fsanitize=address) +fi + # we never use this, and hard setting it will make cross compile work better ac_cv_file_dbd_apr_dbd_mysql_c=no @@ -1946,6 +1954,7 @@ AC_CONFIG_FILES([Makefile src/mod/formats/mod_imagick/Makefile src/mod/formats/mod_local_stream/Makefile src/mod/formats/mod_native_file/Makefile + src/mod/formats/mod_opusfile/Makefile src/mod/formats/mod_shell_stream/Makefile src/mod/formats/mod_shout/Makefile src/mod/formats/mod_sndfile/Makefile diff --git a/debian/control-modules b/debian/control-modules index d27ebbbc37..ba9dda7806 100644 --- a/debian/control-modules +++ b/debian/control-modules @@ -621,6 +621,11 @@ Module: formats/mod_webm Description: Adds mod_webm Adds mod_webm. +Module: formats/mod_opusfile +Description: mod_opusfile + Adds mod_opusfile. +Build-Depends: libopusfile-dev + ## mod/languages Module: languages/mod_basic diff --git a/debian/freeswitch-systemd.freeswitch.service b/debian/freeswitch-systemd.freeswitch.service index c283f1df39..71f168696a 100644 --- a/debian/freeswitch-systemd.freeswitch.service +++ b/debian/freeswitch-systemd.freeswitch.service @@ -3,22 +3,24 @@ [Unit] Description=freeswitch Wants=network-online.target -Requires=syslog.socket network.target local-fs.target -After=syslog.socket network.target network-online.target local-fs.target +Requires=network.target local-fs.target +After=network.target network-online.target local-fs.target [Service] ; service Type=forking PIDFile=/run/freeswitch/freeswitch.pid Environment="DAEMON_OPTS=-nonat" +Environment="USER=freeswitch" +Environment="GROUP=freeswitch" EnvironmentFile=-/etc/default/freeswitch -ExecStartPre=/bin/chown -R freeswitch:freeswitch /var/lib/freeswitch /var/log/freeswitch /etc/freeswitch /usr/share/freeswitch /var/run/freeswitch -ExecStart=/usr/bin/freeswitch -u freeswitch -g freeswitch -ncwait $DAEMON_OPTS +ExecStartPre=/bin/chown -R ${USER}:${GROUP} /var/lib/freeswitch /var/log/freeswitch /etc/freeswitch /usr/share/freeswitch /var/run/freeswitch +ExecStart=/usr/bin/freeswitch -u ${USER} -g ${GROUP} -ncwait ${DAEMON_OPTS} TimeoutSec=45s Restart=always ; exec -User=root -Group=daemon +;User=${USER} +;Group=${GROUP} LimitCORE=infinity LimitNOFILE=100000 LimitNPROC=60000 diff --git a/docs/COPYING b/docs/COPYING index 1bf2b1279d..cb7209a8e3 100644 --- a/docs/COPYING +++ b/docs/COPYING @@ -469,3 +469,62 @@ EXHIBIT A -Mozilla Public License. Original Code Source Code for Your Modifications.] +------------------------------------------------------- +About The Cisco-Provided Binary of OpenH264 Video Codec +------------------------------------------------------- + +Cisco provides this program under the terms of the BSD license. + +Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. + +As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. + +For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary + +A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org + +----------- +BSD License +----------- + +Copyright © 2014 Cisco Systems, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------- +AVC/H.264 Patent Portfolio License Notice +----------------------------------------- + +The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: + +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM + +Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla + +--------------------------------------------- +AVC/H.264 Patent Portfolio License Conditions +--------------------------------------------- + +In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met: + +1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device; + +2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary; + +3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text: + + "OpenH264 Video Codec provided by Cisco Systems, Inc." + +4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. + + + + v1.0 \ No newline at end of file diff --git a/docs/COPYING.rtf b/docs/COPYING.rtf index be24606746..51970cc222 100644 --- a/docs/COPYING.rtf +++ b/docs/COPYING.rtf @@ -1,689 +1,537 @@ -{\rtf1\adeflang1025\ansi\ansicpg1251\uc1\adeff31507\deff0\stshfdbch31505\stshfloch31506\stshfhich31506\stshfbi31507\deflang1049\deflangfe1049\themelang1049\themelangfe0\themelangcs0{\fonttbl{\f0\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f1\fbidi \fswiss\fcharset204\fprq2{\*\panose 020b0604020202020204}Arial;} -{\f34\fbidi \froman\fcharset204\fprq2{\*\panose 02040503050406030204}Cambria Math;}{\flomajor\f31500\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbmajor\f31501\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhimajor\f31502\fbidi \fswiss\fcharset204\fprq2{\*\panose 020f0302020204030204}Calibri Light;} -{\fbimajor\f31503\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\flominor\f31504\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;} -{\fdbminor\f31505\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\fhiminor\f31506\fbidi \fswiss\fcharset204\fprq2{\*\panose 020f0502020204030204}Calibri;} -{\fbiminor\f31507\fbidi \froman\fcharset204\fprq2{\*\panose 02020603050405020304}Times New Roman;}{\f394\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\f392\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\f395\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\f396\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\f397\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\f398\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\f399\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\f400\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\f404\fbidi \fswiss\fcharset0\fprq2 Arial;}{\f402\fbidi \fswiss\fcharset238\fprq2 Arial CE;} -{\f405\fbidi \fswiss\fcharset161\fprq2 Arial Greek;}{\f406\fbidi \fswiss\fcharset162\fprq2 Arial Tur;}{\f407\fbidi \fswiss\fcharset177\fprq2 Arial (Hebrew);}{\f408\fbidi \fswiss\fcharset178\fprq2 Arial (Arabic);} -{\f409\fbidi \fswiss\fcharset186\fprq2 Arial Baltic;}{\f410\fbidi \fswiss\fcharset163\fprq2 Arial (Vietnamese);}{\f734\fbidi \froman\fcharset0\fprq2 Cambria Math;}{\f732\fbidi \froman\fcharset238\fprq2 Cambria Math CE;} -{\f735\fbidi \froman\fcharset161\fprq2 Cambria Math Greek;}{\f736\fbidi \froman\fcharset162\fprq2 Cambria Math Tur;}{\f739\fbidi \froman\fcharset186\fprq2 Cambria Math Baltic;}{\f740\fbidi \froman\fcharset163\fprq2 Cambria Math (Vietnamese);} -{\flomajor\f31510\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flomajor\f31508\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flomajor\f31511\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} -{\flomajor\f31512\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flomajor\f31513\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flomajor\f31514\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\flomajor\f31515\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flomajor\f31516\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbmajor\f31520\fbidi \froman\fcharset0\fprq2 Times New Roman;} -{\fdbmajor\f31518\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbmajor\f31521\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbmajor\f31522\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\fdbmajor\f31523\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbmajor\f31524\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbmajor\f31525\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\fdbmajor\f31526\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhimajor\f31530\fbidi \fswiss\fcharset0\fprq2 Calibri Light;}{\fhimajor\f31528\fbidi \fswiss\fcharset238\fprq2 Calibri Light CE;} -{\fhimajor\f31531\fbidi \fswiss\fcharset161\fprq2 Calibri Light Greek;}{\fhimajor\f31532\fbidi \fswiss\fcharset162\fprq2 Calibri Light Tur;}{\fhimajor\f31535\fbidi \fswiss\fcharset186\fprq2 Calibri Light Baltic;} -{\fhimajor\f31536\fbidi \fswiss\fcharset163\fprq2 Calibri Light (Vietnamese);}{\fbimajor\f31540\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fbimajor\f31538\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\fbimajor\f31541\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbimajor\f31542\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbimajor\f31543\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fbimajor\f31544\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbimajor\f31545\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbimajor\f31546\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);} -{\flominor\f31550\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\flominor\f31548\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\flominor\f31551\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;} -{\flominor\f31552\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\flominor\f31553\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\flominor\f31554\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);} -{\flominor\f31555\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\flominor\f31556\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fdbminor\f31560\fbidi \froman\fcharset0\fprq2 Times New Roman;} -{\fdbminor\f31558\fbidi \froman\fcharset238\fprq2 Times New Roman CE;}{\fdbminor\f31561\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fdbminor\f31562\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;} -{\fdbminor\f31563\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);}{\fdbminor\f31564\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fdbminor\f31565\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;} -{\fdbminor\f31566\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}{\fhiminor\f31570\fbidi \fswiss\fcharset0\fprq2 Calibri;}{\fhiminor\f31568\fbidi \fswiss\fcharset238\fprq2 Calibri CE;} -{\fhiminor\f31571\fbidi \fswiss\fcharset161\fprq2 Calibri Greek;}{\fhiminor\f31572\fbidi \fswiss\fcharset162\fprq2 Calibri Tur;}{\fhiminor\f31575\fbidi \fswiss\fcharset186\fprq2 Calibri Baltic;} -{\fhiminor\f31576\fbidi \fswiss\fcharset163\fprq2 Calibri (Vietnamese);}{\fbiminor\f31580\fbidi \froman\fcharset0\fprq2 Times New Roman;}{\fbiminor\f31578\fbidi \froman\fcharset238\fprq2 Times New Roman CE;} -{\fbiminor\f31581\fbidi \froman\fcharset161\fprq2 Times New Roman Greek;}{\fbiminor\f31582\fbidi \froman\fcharset162\fprq2 Times New Roman Tur;}{\fbiminor\f31583\fbidi \froman\fcharset177\fprq2 Times New Roman (Hebrew);} -{\fbiminor\f31584\fbidi \froman\fcharset178\fprq2 Times New Roman (Arabic);}{\fbiminor\f31585\fbidi \froman\fcharset186\fprq2 Times New Roman Baltic;}{\fbiminor\f31586\fbidi \froman\fcharset163\fprq2 Times New Roman (Vietnamese);}} -{\colortbl;\red0\green0\blue0;\red0\green0\blue255;\red0\green255\blue255;\red0\green255\blue0;\red255\green0\blue255;\red255\green0\blue0;\red255\green255\blue0;\red255\green255\blue255;\red0\green0\blue128;\red0\green128\blue128;\red0\green128\blue0; -\red128\green0\blue128;\red128\green0\blue0;\red128\green128\blue0;\red128\green128\blue128;\red192\green192\blue192;}{\*\defchp \fs22\loch\af31506\hich\af31506\dbch\af31505 }{\*\defpap \ql \li0\ri0\sa160\sl259\slmult1 -\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 }\noqfpromote {\stylesheet{\ql \li0\ri0\sa160\sl259\slmult1\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 -\ltrch\fcs0 \fs22\lang1049\langfe1049\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1049\langfenp1049 \snext0 \sqformat \spriority0 Normal;}{\*\cs10 \additive \ssemihidden \sunhideused \spriority1 Default Paragraph Font;}{\* -\ts11\tsrowd\trftsWidthB3\trpaddl108\trpaddr108\trpaddfl3\trpaddft3\trpaddfb3\trpaddfr3\trcbpat1\trcfpat1\tblind0\tblindtype3\tsvertalt\tsbrdrt\tsbrdrl\tsbrdrb\tsbrdrr\tsbrdrdgl\tsbrdrdgr\tsbrdrh\tsbrdrv \ql \li0\ri0\sa160\sl259\slmult1 -\widctlpar\wrapdefault\aspalpha\aspnum\faauto\adjustright\rin0\lin0\itap0 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 \fs22\lang1049\langfe1049\loch\f31506\hich\af31506\dbch\af31505\cgrid\langnp1049\langfenp1049 \snext11 \ssemihidden \sunhideused -Normal Table;}}{\*\rsidtbl \rsid269322\rsid9123021}{\mmathPr\mmathFont34\mbrkBin0\mbrkBinSub0\msmallFrac0\mdispDef1\mlMargin0\mrMargin0\mdefJc1\mwrapIndent1440\mintLim0\mnaryLim1}{\info{\operator Andrey}{\creatim\yr2018\mo4\dy22\hr2\min42} -{\revtim\yr2018\mo4\dy22\hr2\min44}{\version2}{\edmins2}{\nofpages8}{\nofwords3831}{\nofchars21838}{\nofcharsws25618}{\vern93}}{\*\xmlnstbl {\xmlns1 http://schemas.microsoft.com/office/word/2003/wordml}} -\paperw12240\paperh15840\margl1701\margr850\margt1134\margb1134\gutter0\ltrsect -\widowctrl\ftnbj\aenddoc\trackmoves0\trackformatting1\donotembedsysfont0\relyonvml0\donotembedlingdata1\grfdocevents0\validatexml0\showplaceholdtext0\ignoremixedcontent0\saveinvalidxml0\showxmlerrors0\horzdoc\dghspace120\dgvspace120\dghorigin1701 -\dgvorigin1984\dghshow0\dgvshow3\jcompress\viewkind1\viewscale100\rsidroot269322 \fet0{\*\wgrffmtfilter 2450}\ilfomacatclnup0\ltrpar \sectd \ltrsect\linex0\sectdefaultcl\sftnbj {\*\pnseclvl1\pnucrm\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl2 -\pnucltr\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl3\pndec\pnstart1\pnindent720\pnhang {\pntxta .}}{\*\pnseclvl4\pnlcltr\pnstart1\pnindent720\pnhang {\pntxta )}}{\*\pnseclvl5\pndec\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl6 -\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl7\pnlcrm\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl8\pnlcltr\pnstart1\pnindent720\pnhang {\pntxtb (}{\pntxta )}}{\*\pnseclvl9\pnlcrm\pnstart1\pnindent720\pnhang -{\pntxtb (}{\pntxta )}}\pard\plain \ltrpar\ql \li0\ri0\nowidctlpar\wrapdefault\faauto\rin0\lin0\itap0\pararsid269322 \rtlch\fcs1 \af31507\afs22\alang1025 \ltrch\fcs0 -\fs22\lang1049\langfe1049\loch\af31506\hich\af31506\dbch\af31505\cgrid\langnp1049\langfenp1049 {\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\lang1033\langfe1049\langnp1033\insrsid9123021\charrsid269322 \hich\af1\dbch\af31505\loch\f1 MOZILLA PUBLIC LICENSE - -\par \hich\af1\dbch\af31505\loch\f1 Version 1.1 -\par -\par --------------- -\par -\par \hich\af1\dbch\af31505\loch\f1 1. Definitions. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.0.1. "Commercial Use" means distribution or otherwise making the -\par \hich\af1\dbch\af31505\loch\f1 Covered Code available to a third party. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.1. "Contributor" means each entity that creates or contributes to -\par \hich\af1\dbch\af31505\loch\f1 the creation of Modifications. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.2. "Contributor Version" means the combination of the Original -\par \hich\af1\dbch\af31505\loch\f1 Code, prior Modification\hich\af1\dbch\af31505\loch\f1 s used by a Contributor, and the Modifications -\par \hich\af1\dbch\af31505\loch\f1 made by that particular Contributor. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.3. "Covered Code" means the Original Code or Modifications or the -\par \hich\af1\dbch\af31505\loch\f1 combination of the Original Code and Modifications, in each case -\par \hich\af1\dbch\af31505\loch\f1 including portions\hich\af1\dbch\af31505\loch\f1 thereof. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.4. "Electronic Distribution Mechanism" means a mechanism generally -\par \hich\af1\dbch\af31505\loch\f1 accepted in the software development community for the electronic -\par \hich\af1\dbch\af31505\loch\f1 transfer of data. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.5. "Executable" means Covered Code in any form other than Source -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 Code. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.6. "Initial Developer" means the individual or entity identified -\par \hich\af1\dbch\af31505\loch\f1 as the Initial Developer in the Source Code notice required by Exhibit -\par \hich\af1\dbch\af31505\loch\f1 A. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.7. "Larger Work" means a work which combines Covered Code or -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 portions thereof with code not governed by the terms of this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.8. "License" means this document. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.8.1. "Licensable" means having the right to grant, to the maximum -\par \hich\af1\dbch\af31505\loch\f1 extent possible, whether at the time of the initial grant or -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 subsequently acquired, any and all of the rights conveyed herein. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.9. "Modifications" means any addition to or deletion from the -\par \hich\af1\dbch\af31505\loch\f1 substance or structure of either the Original Code or any previous -\par \hich\af1\dbch\af31505\loch\f1 Modifications. When Covered Code is relea\hich\af1\dbch\af31505\loch\f1 sed as a series of files, a -\par \hich\af1\dbch\af31505\loch\f1 Modification is: -\par \hich\af1\dbch\af31505\loch\f1 A. Any addition to or deletion from the contents of a file -\par \hich\af1\dbch\af31505\loch\f1 containing Original Code or previous Modifications. -\par -\par \hich\af1\dbch\af31505\loch\f1 B. Any new file that contains any part of the Original Code or -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 previous Modifications. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.10. "Original Code" means Source Code of computer software code -\par \hich\af1\dbch\af31505\loch\f1 which is described in the Source Code notice required by Exhibit A as -\par \hich\af1\dbch\af31505\loch\f1 Original Code, and which, at the time of its release under this -\par \hich\af1\dbch\af31505\loch\f1 Li\hich\af1\dbch\af31505\loch\f1 cense is not already Covered Code governed by this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.10.1. "Patent Claims" means any patent claim(s), now owned or -\par \hich\af1\dbch\af31505\loch\f1 hereafter acquired, including without limitation, method, process, -\par \hich\af1\dbch\af31505\loch\f1 and apparatus claims, in any patent Licensable by grantor. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.11. "Source Code" means the preferred form of the Covered Code for -\par \hich\af1\dbch\af31505\loch\f1 making modifications to it, including all modules it contains, plus -\par \hich\af1\dbch\af31505\loch\f1 any associated interface definition fil\hich\af1\dbch\af31505\loch\f1 es, scripts used to control -\par \hich\af1\dbch\af31505\loch\f1 compilation and installation of an Executable, or source code -\par \hich\af1\dbch\af31505\loch\f1 differential comparisons against either the Original Code or another -\par \hich\af1\dbch\af31505\loch\f1 well known, available Covered Code of the Contributor's choice. The -\par \hich\af1\dbch\af31505\loch\f1 Source Co\hich\af1\dbch\af31505\loch\f1 de can be in a compressed or archival form, provided the -\par \hich\af1\dbch\af31505\loch\f1 appropriate decompression or de-archiving software is widely available -\par \hich\af1\dbch\af31505\loch\f1 for no charge. -\par -\par \hich\af1\dbch\af31505\loch\f1 1.12. "You" (or "Your") means an individual or a legal entity -\par \hich\af1\dbch\af31505\loch\f1 exercising rights under, and \hich\af1\dbch\af31505\loch\f1 complying with all of the terms of, this -\par \hich\af1\dbch\af31505\loch\f1 License or a future version of this License issued under Section 6.1. -\par \hich\af1\dbch\af31505\loch\f1 For legal entities, "You" includes any entity which controls, is -\par \hich\af1\dbch\af31505\loch\f1 controlled by, or is under common control with You. For purposes \hich\af1\dbch\af31505\loch\f1 of -\par \hich\af1\dbch\af31505\loch\f1 this definition, "control" means (a) the power, direct or indirect, -\par \hich\af1\dbch\af31505\loch\f1 to cause the direction or management of such entity, whether by -\par \hich\af1\dbch\af31505\loch\f1 contract or otherwise, or (b) ownership of more than fifty percent -\par \hich\af1\dbch\af31505\loch\f1 (50%) of the outstanding shares or\hich\af1\dbch\af31505\loch\f1 beneficial ownership of such -\par \hich\af1\dbch\af31505\loch\f1 entity. -\par -\par \hich\af1\dbch\af31505\loch\f1 2. Source Code License. -\par -\par \hich\af1\dbch\af31505\loch\f1 2.1. The Initial Developer Grant. -\par \hich\af1\dbch\af31505\loch\f1 The Initial Developer hereby grants You a world-wide, royalty-free, -\par \hich\af1\dbch\af31505\loch\f1 non-exclusive license, subject to third party intellectual property -\par \hich\af1\dbch\af31505\loch\f1 claims: -\par \hich\af1\dbch\af31505\loch\f1 (a) under intellectual property rights (other than patent or -\par \hich\af1\dbch\af31505\loch\f1 trademark) Licensable by Initial Developer to use, reproduce, -\par \hich\af1\dbch\af31505\loch\f1 modify, display, perform, sublicense and distribute the Original -\par \hich\af1\dbch\af31505\loch\f1 Code (or porti\hich\af1\dbch\af31505\loch\f1 ons thereof) with or without Modifications, and/or -\par \hich\af1\dbch\af31505\loch\f1 as part of a Larger Work; and -\par -\par \hich\af1\dbch\af31505\loch\f1 (b) under Patents Claims infringed by the making, using or -\par \hich\af1\dbch\af31505\loch\f1 selling of Original Code, to make, have made, use, practice, -\par \hich\af1\dbch\af31505\loch\f1 sell, and offe\hich\af1\dbch\af31505\loch\f1 r for sale, and/or otherwise dispose of the -\par \hich\af1\dbch\af31505\loch\f1 Original Code (or portions thereof). -\par -\par \hich\af1\dbch\af31505\loch\f1 (c) the licenses granted in this Section 2.1(a) and (b) are -\par \hich\af1\dbch\af31505\loch\f1 effective on the date Initial Developer first distributes -\par \hich\af1\dbch\af31505\loch\f1 Original Code un\hich\af1\dbch\af31505\loch\f1 der the terms of this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 (d) Notwithstanding Section 2.1(b) above, no patent license is -\par \hich\af1\dbch\af31505\loch\f1 granted: 1) for code that You delete from the Original Code; 2) -\par \hich\af1\dbch\af31505\loch\f1 separate from the Original Code; or 3) for infringements caused -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 by: i) the modification of the Original Code or ii) the -\par \hich\af1\dbch\af31505\loch\f1 combination of the Original Code with other software or devices. -\par -\par \hich\af1\dbch\af31505\loch\f1 2.2. Contributor Grant. -\par \hich\af1\dbch\af31505\loch\f1 Subject to third party intellectual property claims, each Contributor -\par \hich\af1\dbch\af31505\loch\f1 hereby \hich\af1\dbch\af31505\loch\f1 grants You a world-wide, royalty-free, non-exclusive license -\par -\par \hich\af1\dbch\af31505\loch\f1 (a) under intellectual property rights (other than patent or -\par \hich\af1\dbch\af31505\loch\f1 trademark) Licensable by Contributor, to use, reproduce, modify, -\par \hich\af1\dbch\af31505\loch\f1 display, perform, sublicense and distribute the Modifications -\par \hich\af1\dbch\af31505\loch\f1 created by such Contributor (or portions thereof) either on an -\par \hich\af1\dbch\af31505\loch\f1 unmodified basis, with other Modifications, as Covered Code -\par \hich\af1\dbch\af31505\loch\f1 and/or as part of a Larger Work\hich\af1\dbch\af31505\loch\f1 ; and -\par -\par \hich\af1\dbch\af31505\loch\f1 (b) under Patent Claims infringed by the making, using, or -\par \hich\af1\dbch\af31505\loch\f1 selling of Modifications made by that Contributor either alone -\par \hich\af1\dbch\af31505\loch\f1 and/or in combination with its Contributor Version (or portions -\par \hich\af1\dbch\af31505\loch\f1 of such combination), \hich\af1\dbch\af31505\loch\f1 to make, use, sell, offer for sale, have -\par \hich\af1\dbch\af31505\loch\f1 made, and/or otherwise dispose of: 1) Modifications made by that -\par \hich\af1\dbch\af31505\loch\f1 Contributor (or portions thereof); and 2) the combination of -\par \hich\af1\dbch\af31505\loch\f1 Modifications made by that Contributor with its Contributor -\par \hich\af1\dbch\af31505\loch\f1 Version (or portions of such combination). -\par -\par \hich\af1\dbch\af31505\loch\f1 (c) the licenses granted in Sections 2.2(a) and 2.2(b) are -\par \hich\af1\dbch\af31505\loch\f1 effective on the date Contributor first makes Commercial Use of -\par \hich\af1\dbch\af31505\loch\f1 the Covered Code. -\par -\par \hich\af1\dbch\af31505\loch\f1 (d) Notwithstand\hich\af1\dbch\af31505\loch\f1 ing Section 2.2(b) above, no patent license is -\par \hich\af1\dbch\af31505\loch\f1 granted: 1) for any code that Contributor has deleted from the -\par \hich\af1\dbch\af31505\loch\f1 Contributor Version; 2) separate from the Contributor Version; -\par \hich\af1\dbch\af31505\loch\f1 3) for infringements caused by: i) third party modi\hich\af1\dbch\af31505\loch\f1 fications of -\par \hich\af1\dbch\af31505\loch\f1 Contributor Version or ii) the combination of Modifications made -\par \hich\af1\dbch\af31505\loch\f1 by that Contributor with other software (except as part of the -\par \hich\af1\dbch\af31505\loch\f1 Contributor Version) or other devices; or 4) under Patent Claims -\par \hich\af1\dbch\af31505\loch\f1 infringe\hich\af1\dbch\af31505\loch\f1 d by Covered Code in the absence of Modifications made by -\par \hich\af1\dbch\af31505\loch\f1 that Contributor. -\par -\par \hich\af1\dbch\af31505\loch\f1 3. Distribution Obligations. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.1. Application of License. -\par \hich\af1\dbch\af31505\loch\f1 The Modifications which You create or to which You contribute are -\par \hich\af1\dbch\af31505\loch\f1 governed by the terms of this License, including without limitation -\par \hich\af1\dbch\af31505\loch\f1 Section 2.2. The Source Code version of Covered Code may be -\par \hich\af1\dbch\af31505\loch\f1 distributed only under the terms of this License or a future version -\par \hich\af1\dbch\af31505\loch\f1 of this License released under Section \hich\af1\dbch\af31505\loch\f1 6.1, and You must include a -\par \hich\af1\dbch\af31505\loch\f1 copy of this License with every copy of the Source Code You -\par \hich\af1\dbch\af31505\loch\f1 distribute. You may not offer or impose any terms on any Source Code -\par \hich\af1\dbch\af31505\loch\f1 version that alters or restricts the applicable version of this -\par \hich\af1\dbch\af31505\loch\f1 License or the \hich\af1\dbch\af31505\loch\f1 recipients' rights hereunder. However, You may include -\par \hich\af1\dbch\af31505\loch\f1 an additional document offering the additional rights described in -\par \hich\af1\dbch\af31505\loch\f1 Section 3.5. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.2. Availability of Source Code. -\par \hich\af1\dbch\af31505\loch\f1 Any Modification which You create or to which You contribute must \hich\af1\dbch\af31505\loch\f1 be -\par \hich\af1\dbch\af31505\loch\f1 made available in Source Code form under the terms of this License -\par \hich\af1\dbch\af31505\loch\f1 either on the same media as an Executable version or via an accepted -\par \hich\af1\dbch\af31505\loch\f1 Electronic Distribution Mechanism to anyone to whom you made an -\par \hich\af1\dbch\af31505\loch\f1 Executable version available; and\hich\af1\dbch\af31505\loch\f1 if made available via Electronic -\par \hich\af1\dbch\af31505\loch\f1 Distribution Mechanism, must remain available for at least twelve (12) -\par \hich\af1\dbch\af31505\loch\f1 months after the date it initially became available, or at least six -\par \hich\af1\dbch\af31505\loch\f1 (6) months after a subsequent version of that particular Modificati\hich\af1\dbch\af31505\loch\f1 on -\par \hich\af1\dbch\af31505\loch\f1 has been made available to such recipients. You are responsible for -\par \hich\af1\dbch\af31505\loch\f1 ensuring that the Source Code version remains available even if the -\par \hich\af1\dbch\af31505\loch\f1 Electronic Distribution Mechanism is maintained by a third party. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.3. Description of Modifications. -\par \hich\af1\dbch\af31505\loch\f1 You must cause all Covered Code to which You contribute to contain a -\par \hich\af1\dbch\af31505\loch\f1 file documenting the changes You made to create that Covered Code and -\par \hich\af1\dbch\af31505\loch\f1 the date of any change. You must include a prominent statement\hich\af1\dbch\af31505\loch\f1 that -\par \hich\af1\dbch\af31505\loch\f1 the Modification is derived, directly or indirectly, from Original -\par \hich\af1\dbch\af31505\loch\f1 Code provided by the Initial Developer and including the name of the -\par \hich\af1\dbch\af31505\loch\f1 Initial Developer in (a) the Source Code, and (b) in any notice in an -\par \hich\af1\dbch\af31505\loch\f1 Executable version or re\hich\af1\dbch\af31505\loch\f1 lated documentation in which You describe the -\par \hich\af1\dbch\af31505\loch\f1 origin or ownership of the Covered Code. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.4. Intellectual Property Matters -\par \hich\af1\dbch\af31505\loch\f1 (a) Third Party Claims. -\par \hich\af1\dbch\af31505\loch\f1 If Contributor has knowledge that a license under a third party's -\par \hich\af1\dbch\af31505\loch\f1 int\hich\af1\dbch\af31505\loch\f1 ellectual property rights is required to exercise the rights -\par \hich\af1\dbch\af31505\loch\f1 granted by such Contributor under Sections 2.1 or 2.2, -\par \hich\af1\dbch\af31505\loch\f1 Contributor must include a text file with the Source Code -\par \hich\af1\dbch\af31505\loch\f1 distribution titled "LEGAL" which describes the clai\hich\af1\dbch\af31505\loch\f1 m and the -\par \hich\af1\dbch\af31505\loch\f1 party making the claim in sufficient detail that a recipient will -\par \hich\af1\dbch\af31505\loch\f1 know whom to contact. If Contributor obtains such knowledge after -\par \hich\af1\dbch\af31505\loch\f1 the Modification is made available as described in Section 3.2, -\par \hich\af1\dbch\af31505\loch\f1 Contributo\hich\af1\dbch\af31505\loch\f1 r shall promptly modify the LEGAL file in all copies -\par \hich\af1\dbch\af31505\loch\f1 Contributor makes available thereafter and shall take other steps -\par \hich\af1\dbch\af31505\loch\f1 (such as notifying appropriate mailing lists or newsgroups) -\par \hich\af1\dbch\af31505\loch\f1 reasonably calculated to inform those who recei\hich\af1\dbch\af31505\loch\f1 ved the Covered -\par \hich\af1\dbch\af31505\loch\f1 Code that new knowledge has been obtained. -\par -\par \hich\af1\dbch\af31505\loch\f1 (b) Contributor APIs. -\par \hich\af1\dbch\af31505\loch\f1 If Contributor's Modifications include an application programming -\par \hich\af1\dbch\af31505\loch\f1 interface and Contributor has knowledge of patent licenses which -\par \hich\af1\dbch\af31505\loch\f1 are reasonably necessary to implement that API, Contributor must -\par \hich\af1\dbch\af31505\loch\f1 also include this information in the LEGAL file. -\par -\par \hich\af1\dbch\af31505\loch\f1 (c) Representations. -\par \hich\af1\dbch\af31505\loch\f1 Contributor represents that, except as disclosed pursuant to -\par \hich\af1\dbch\af31505\loch\f1 S\hich\af1\dbch\af31505\loch\f1 ection 3.4(a) above, Contributor believes that Contributor's -\par \hich\af1\dbch\af31505\loch\f1 Modifications are Contributor's original creation(s) and/or -\par \hich\af1\dbch\af31505\loch\f1 Contributor has sufficient rights to grant the rights conveyed by -\par \hich\af1\dbch\af31505\loch\f1 this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.5. Required Notic\hich\af1\dbch\af31505\loch\f1 es. -\par \hich\af1\dbch\af31505\loch\f1 You must duplicate the notice in Exhibit A in each file of the Source -\par \hich\af1\dbch\af31505\loch\f1 Code. If it is not possible to put such notice in a particular Source -\par \hich\af1\dbch\af31505\loch\f1 Code file due to its structure, then You must include such notice in a -\par \hich\af1\dbch\af31505\loch\f1 location (such as a \hich\af1\dbch\af31505\loch\f1 relevant directory) where a user would be likely -\par \hich\af1\dbch\af31505\loch\f1 to look for such a notice. If You created one or more Modification(s) -\par \hich\af1\dbch\af31505\loch\f1 You may add your name as a Contributor to the notice described in -\par \hich\af1\dbch\af31505\loch\f1 Exhibit A. You must also duplicate this License in any\hich\af1\dbch\af31505\loch\f1 documentation -\par \hich\af1\dbch\af31505\loch\f1 for the Source Code where You describe recipients' rights or ownership -\par \hich\af1\dbch\af31505\loch\f1 rights relating to Covered Code. You may choose to offer, and to -\par \hich\af1\dbch\af31505\loch\f1 charge a fee for, warranty, support, indemnity or liability -\par \hich\af1\dbch\af31505\loch\f1 obligations to one or mo\hich\af1\dbch\af31505\loch\f1 re recipients of Covered Code. However, You -\par \hich\af1\dbch\af31505\loch\f1 may do so only on Your own behalf, and not on behalf of the Initial -\par \hich\af1\dbch\af31505\loch\f1 Developer or any Contributor. You must make it absolutely clear than -\par \hich\af1\dbch\af31505\loch\f1 any such warranty, support, indemnity or liability obligatio\hich\af1\dbch\af31505\loch\f1 n is -\par \hich\af1\dbch\af31505\loch\f1 offered by You alone, and You hereby agree to indemnify the Initial -\par \hich\af1\dbch\af31505\loch\f1 Developer and every Contributor for any liability incurred by the -\par \hich\af1\dbch\af31505\loch\f1 Initial Developer or such Contributor as a result of warranty, -\par \hich\af1\dbch\af31505\loch\f1 support, indemnity or liability terms You offer. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.6. Distribution of Executable Versions. -\par \hich\af1\dbch\af31505\loch\f1 You may distribute Covered Code in Executable form only if the -\par \hich\af1\dbch\af31505\loch\f1 requirements of Section 3.1-3.5 have been met for that Covered Code, -\par \hich\af1\dbch\af31505\loch\f1 and if \hich\af1\dbch\af31505\loch\f1 You include a notice stating that the Source Code version of -\par \hich\af1\dbch\af31505\loch\f1 the Covered Code is available under the terms of this License, -\par \hich\af1\dbch\af31505\loch\f1 including a description of how and where You have fulfilled the -\par \hich\af1\dbch\af31505\loch\f1 obligations of Section 3.2. The notice must be conspi\hich\af1\dbch\af31505\loch\f1 cuously included -\par \hich\af1\dbch\af31505\loch\f1 in any notice in an Executable version, related documentation or -\par \hich\af1\dbch\af31505\loch\f1 collateral in which You describe recipients' rights relating to the -\par \hich\af1\dbch\af31505\loch\f1 Covered Code. You may distribute the Executable version of Covered -\par \hich\af1\dbch\af31505\loch\f1 Code or ownership r\hich\af1\dbch\af31505\loch\f1 ights under a license of Your choice, which may -\par \hich\af1\dbch\af31505\loch\f1 contain terms different from this License, provided that You are in -\par \hich\af1\dbch\af31505\loch\f1 compliance with the terms of this License and that the license for the -\par \hich\af1\dbch\af31505\loch\f1 Executable version does not attempt to limit or alter \hich\af1\dbch\af31505\loch\f1 the recipient's -\par \hich\af1\dbch\af31505\loch\f1 rights in the Source Code version from the rights set forth in this -\par \hich\af1\dbch\af31505\loch\f1 License. If You distribute the Executable version under a different -\par \hich\af1\dbch\af31505\loch\f1 license You must make it absolutely clear that any terms which differ -\par \hich\af1\dbch\af31505\loch\f1 from this Lice\hich\af1\dbch\af31505\loch\f1 nse are offered by You alone, not by the Initial -\par \hich\af1\dbch\af31505\loch\f1 Developer or any Contributor. You hereby agree to indemnify the -\par \hich\af1\dbch\af31505\loch\f1 Initial Developer and every Contributor for any liability incurred by -\par \hich\af1\dbch\af31505\loch\f1 the Initial Developer or such Contributor as a result of a\hich\af1\dbch\af31505\loch\f1 ny such -\par \hich\af1\dbch\af31505\loch\f1 terms You offer. -\par -\par \hich\af1\dbch\af31505\loch\f1 3.7. Larger Works. -\par \hich\af1\dbch\af31505\loch\f1 You may create a Larger Work by combining Covered Code with other code -\par \hich\af1\dbch\af31505\loch\f1 not governed by the terms of this License and distribute the Larger -\par \hich\af1\dbch\af31505\loch\f1 Work as a single product. In such a case, You must make sure the -\par \hich\af1\dbch\af31505\loch\f1 requirements of this License are fulfilled for the Covered Code. -\par -\par \hich\af1\dbch\af31505\loch\f1 4. Inability to Comply Due to Statute or Regulation. -\par -\par \hich\af1\dbch\af31505\loch\f1 If it is impossible for You to comply with any of the te\hich\af1\dbch\af31505\loch\f1 rms of this -\par \hich\af1\dbch\af31505\loch\f1 License with respect to some or all of the Covered Code due to -\par \hich\af1\dbch\af31505\loch\f1 statute, judicial order, or regulation then You must: (a) comply with -\par \hich\af1\dbch\af31505\loch\f1 the terms of this License to the maximum extent possible; and (b) -\par \hich\af1\dbch\af31505\loch\f1 describe the limitations \hich\af1\dbch\af31505\loch\f1 and the code they affect. Such description -\par \hich\af1\dbch\af31505\loch\f1 must be included in the LEGAL file described in Section 3.4 and must -\par \hich\af1\dbch\af31505\loch\f1 be included with all distributions of the Source Code. Except to the -\par \hich\af1\dbch\af31505\loch\f1 extent prohibited by statute or regulation, such description\hich\af1\dbch\af31505\loch\f1 must be -\par \hich\af1\dbch\af31505\loch\f1 sufficiently detailed for a recipient of ordinary skill to be able to -\par \hich\af1\dbch\af31505\loch\f1 understand it. -\par -\par \hich\af1\dbch\af31505\loch\f1 5. Application of this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 This License applies to code to which the Initial Developer has -\par \hich\af1\dbch\af31505\loch\f1 attached the notice in Exhibit A and to rela\hich\af1\dbch\af31505\loch\f1 ted Covered Code. -\par -\par \hich\af1\dbch\af31505\loch\f1 6. Versions of the License. -\par -\par \hich\af1\dbch\af31505\loch\f1 6.1. New Versions. -\par \hich\af1\dbch\af31505\loch\f1 Netscape Communications Corporation ("Netscape") may publish revised -\par \hich\af1\dbch\af31505\loch\f1 and/or new versions of the License from time to time. Each version -\par \hich\af1\dbch\af31505\loch\f1 will be given a distinguishing version number. -\par -\par \hich\af1\dbch\af31505\loch\f1 6.2. Effect of New Versions. -\par \hich\af1\dbch\af31505\loch\f1 Once Covered Code has been published under a particular version of the -\par \hich\af1\dbch\af31505\loch\f1 License, You may always continue to use it under the terms of that -\par \hich\af1\dbch\af31505\loch\f1 version. You may\hich\af1\dbch\af31505\loch\f1 also choose to use such Covered Code under the terms -\par \hich\af1\dbch\af31505\loch\f1 of any subsequent version of the License published by Netscape. No one -\par \hich\af1\dbch\af31505\loch\f1 other than Netscape has the right to modify the terms applicable to -\par \hich\af1\dbch\af31505\loch\f1 Covered Code created under this License. -\par -\par \hich\af1\dbch\af31505\loch\f1 6\hich\af1\dbch\af31505\loch\f1 .3. Derivative Works. -\par \hich\af1\dbch\af31505\loch\f1 If You create or use a modified version of this License (which you may -\par \hich\af1\dbch\af31505\loch\f1 only do in order to apply it to code which is not already Covered Code -\par \hich\af1\dbch\af31505\loch\f1 governed by this License), You must (a) rename Your license so that -\par \hich\af1\dbch\af31505\loch\f1 the \hich\af1\dbch\af31505\loch\f1 phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape", -\par \hich\af1\dbch\af31505\loch\f1 "MPL", "NPL" or any confusingly similar phrase do not appear in your -\par \hich\af1\dbch\af31505\loch\f1 license (except to note that your license differs from this License) -\par \hich\af1\dbch\af31505\loch\f1 and (b) otherwise make it clear that Your version \hich\af1\dbch\af31505\loch\f1 of the license -\par \hich\af1\dbch\af31505\loch\f1 contains terms which differ from the Mozilla Public License and -\par \hich\af1\dbch\af31505\loch\f1 Netscape Public License. (Filling in the name of the Initial -\par \hich\af1\dbch\af31505\loch\f1 Developer, Original Code or Contributor in the notice described in -\par \hich\af1\dbch\af31505\loch\f1 Exhibit A shall not of themse\hich\af1\dbch\af31505\loch\f1 lves be deemed to be modifications of -\par \hich\af1\dbch\af31505\loch\f1 this License.) -\par -\par \hich\af1\dbch\af31505\loch\f1 7. DISCLAIMER OF WARRANTY. -\par -\par \hich\af1\dbch\af31505\loch\f1 COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS, -\par \hich\af1\dbch\af31505\loch\f1 WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, -\par \hich\af1\dbch\af31505\loch\f1 WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF -\par \hich\af1\dbch\af31505\loch\f1 DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING. -\par \hich\af1\dbch\af31505\loch\f1 THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE -\par \hich\af1\dbch\af31505\loch\f1 IS WITH YOU. SHOULD ANY COVERED\hich\af1\dbch\af31505\loch\f1 CODE PROVE DEFECTIVE IN ANY RESPECT, -\par \hich\af1\dbch\af31505\loch\f1 YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE -\par \hich\af1\dbch\af31505\loch\f1 COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER -\par \hich\af1\dbch\af31505\loch\f1 OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO US\hich\af1\dbch\af31505\loch\f1 E OF -\par \hich\af1\dbch\af31505\loch\f1 ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER. -\par -\par \hich\af1\dbch\af31505\loch\f1 8. TERMINATION. -\par -\par \hich\af1\dbch\af31505\loch\f1 8.1. This License and the rights granted hereunder will terminate -\par \hich\af1\dbch\af31505\loch\f1 automatically if You fail to comply with terms herein and fail to cure -\par \hich\af1\dbch\af31505\loch\f1 such\hich\af1\dbch\af31505\loch\f1 breach within 30 days of becoming aware of the breach. All -\par \hich\af1\dbch\af31505\loch\f1 sublicenses to the Covered Code which are properly granted shall -\par \hich\af1\dbch\af31505\loch\f1 survive any termination of this License. Provisions which, by their -\par \hich\af1\dbch\af31505\loch\f1 nature, must remain in effect beyond the termina\hich\af1\dbch\af31505\loch\f1 tion of this License -\par \hich\af1\dbch\af31505\loch\f1 shall survive. -\par -\par \hich\af1\dbch\af31505\loch\f1 8.2. If You initiate litigation by asserting a patent infringement -\par \hich\af1\dbch\af31505\loch\f1 claim (excluding declatory judgment actions) against Initial Developer -\par \hich\af1\dbch\af31505\loch\f1 or a Contributor (the Initial Developer or Contributor again\hich\af1\dbch\af31505\loch\f1 st whom -\par \hich\af1\dbch\af31505\loch\f1 You file such action is referred to as "Participant") alleging that: -\par -\par \hich\af1\dbch\af31505\loch\f1 (a) such Participant's Contributor Version directly or indirectly -\par \hich\af1\dbch\af31505\loch\f1 infringes any patent, then any and all rights granted by such -\par \hich\af1\dbch\af31505\loch\f1 Participant to You under Sec\hich\af1\dbch\af31505\loch\f1 tions 2.1 and/or 2.2 of this License -\par \hich\af1\dbch\af31505\loch\f1 shall, upon 60 days notice from Participant terminate prospectively, -\par \hich\af1\dbch\af31505\loch\f1 unless if within 60 days after receipt of notice You either: (i) -\par \hich\af1\dbch\af31505\loch\f1 agree in writing to pay Participant a mutually agreeable reasonable -\par \hich\af1\dbch\af31505\loch\f1 royalty for Your past and future use of Modifications made by such -\par \hich\af1\dbch\af31505\loch\f1 Participant, or (ii) withdraw Your litigation claim with respect to -\par \hich\af1\dbch\af31505\loch\f1 the Contributor Version against such Participant. If within 60 days -\par \hich\af1\dbch\af31505\loch\f1 of notice, a reasonable royalty \hich\af1\dbch\af31505\loch\f1 and payment arrangement are not -\par \hich\af1\dbch\af31505\loch\f1 mutually agreed upon in writing by the parties or the litigation claim -\par \hich\af1\dbch\af31505\loch\f1 is not withdrawn, the rights granted by Participant to You under -\par \hich\af1\dbch\af31505\loch\f1 Sections 2.1 and/or 2.2 automatically terminate at the expiration of -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 the 60 day notice period specified above. -\par -\par \hich\af1\dbch\af31505\loch\f1 (b) any software, hardware, or device, other than such Participant's -\par \hich\af1\dbch\af31505\loch\f1 Contributor Version, directly or indirectly infringes any patent, then -\par \hich\af1\dbch\af31505\loch\f1 any rights granted to You by such Participant under Sect\hich\af1\dbch\af31505\loch\f1 ions 2.1(b) -\par \hich\af1\dbch\af31505\loch\f1 and 2.2(b) are revoked effective as of the date You first made, used, -\par \hich\af1\dbch\af31505\loch\f1 sold, distributed, or had made, Modifications made by that -\par \hich\af1\dbch\af31505\loch\f1 Participant. -\par -\par \hich\af1\dbch\af31505\loch\f1 8.3. If You assert a patent infringement claim against Participant -\par \hich\af1\dbch\af31505\loch\f1 alleging\hich\af1\dbch\af31505\loch\f1 that such Participant's Contributor Version directly or -\par \hich\af1\dbch\af31505\loch\f1 indirectly infringes any patent where such claim is resolved (such as -\par \hich\af1\dbch\af31505\loch\f1 by license or settlement) prior to the initiation of patent -\par \hich\af1\dbch\af31505\loch\f1 infringement litigation, then the reasonable value of \hich\af1\dbch\af31505\loch\f1 the licenses -\par \hich\af1\dbch\af31505\loch\f1 granted by such Participant under Sections 2.1 or 2.2 shall be taken -\par \hich\af1\dbch\af31505\loch\f1 into account in determining the amount or value of any payment or -\par \hich\af1\dbch\af31505\loch\f1 license. -\par -\par \hich\af1\dbch\af31505\loch\f1 8.4. In the event of termination under Sections 8.1 or 8.2 above, -\par \hich\af1\dbch\af31505\loch\f1 all end user license agreements (excluding distributors and resellers) -\par \hich\af1\dbch\af31505\loch\f1 which have been validly granted by You or any distributor hereunder -\par \hich\af1\dbch\af31505\loch\f1 prior to termination shall survive termination. -\par -\par \hich\af1\dbch\af31505\loch\f1 9. LIMITATION OF LIABILITY. -\par -\par \hich\af1\dbch\af31505\loch\f1 UNDER NO CIRCUMSTAN\hich\af1\dbch\af31505\loch\f1 CES AND UNDER NO LEGAL THEORY, WHETHER TORT -\par \hich\af1\dbch\af31505\loch\f1 (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL -\par \hich\af1\dbch\af31505\loch\f1 DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE, -\par \hich\af1\dbch\af31505\loch\f1 OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY\hich\af1\dbch\af31505\loch\f1 PERSON FOR -\par \hich\af1\dbch\af31505\loch\f1 ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY -\par \hich\af1\dbch\af31505\loch\f1 CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL, -\par \hich\af1\dbch\af31505\loch\f1 WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER -\par \hich\af1\dbch\af31505\loch\f1 COMMERCIAL DAMAGE\hich\af1\dbch\af31505\loch\f1 S OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN -\par \hich\af1\dbch\af31505\loch\f1 INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF -\par \hich\af1\dbch\af31505\loch\f1 LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY -\par \hich\af1\dbch\af31505\loch\f1 RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICAB\hich\af1\dbch\af31505\loch\f1 LE LAW -\par \hich\af1\dbch\af31505\loch\f1 PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE -\par \hich\af1\dbch\af31505\loch\f1 EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO -\par \hich\af1\dbch\af31505\loch\f1 THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU. -\par -\par \hich\af1\dbch\af31505\loch\f1 10. U.S. GOVERNMENT END USERS. -\par -\par \hich\af1\dbch\af31505\loch\f1 The Covered Co\hich\af1\dbch\af31505\loch\f1 de is a "commercial item," as that term is defined in -\par \hich\af1\dbch\af31505\loch\f1 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer -\par \hich\af1\dbch\af31505\loch\f1 software" and "commercial computer software documentation," as such -\par \hich\af1\dbch\af31505\loch\f1 terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consis\hich\af1\dbch\af31505\loch\f1 tent with 48 -\par \hich\af1\dbch\af31505\loch\f1 C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995), -\par \hich\af1\dbch\af31505\loch\f1 all U.S. Government End Users acquire Covered Code with only those -\par \hich\af1\dbch\af31505\loch\f1 rights set forth herein. -\par -\par \hich\af1\dbch\af31505\loch\f1 11. MISCELLANEOUS. -\par -\par \hich\af1\dbch\af31505\loch\f1 This License represents the complete agreement concerning subject -\par \hich\af1\dbch\af31505\loch\f1 matter hereof. If any provision of this License is held to be -\par \hich\af1\dbch\af31505\loch\f1 unenforceable, such provision shall be reformed only to the extent -\par \hich\af1\dbch\af31505\loch\f1 necessary to make it enforceable. This Li\hich\af1\dbch\af31505\loch\f1 cense shall be governed by -\par \hich\af1\dbch\af31505\loch\f1 California law provisions (except to the extent applicable law, if -\par \hich\af1\dbch\af31505\loch\f1 any, provides otherwise), excluding its conflict-of-law provisions. -\par \hich\af1\dbch\af31505\loch\f1 With respect to disputes in which at least one party is a citizen of, -\par \hich\af1\dbch\af31505\loch\f1 or a\hich\af1\dbch\af31505\loch\f1 n entity chartered or registered to do business in the United -\par \hich\af1\dbch\af31505\loch\f1 States of America, any litigation relating to this License shall be -\par \hich\af1\dbch\af31505\loch\f1 subject to the jurisdiction of the Federal Courts of the Northern -\par \hich\af1\dbch\af31505\loch\f1 District of California, with venue lying in S\hich\af1\dbch\af31505\loch\f1 anta Clara County, -\par \hich\af1\dbch\af31505\loch\f1 California, with the losing party responsible for costs, including -\par \hich\af1\dbch\af31505\loch\f1 without limitation, court costs and reasonable attorneys' fees and -\par \hich\af1\dbch\af31505\loch\f1 expenses. The application of the United Nations Convention on -\par \hich\af1\dbch\af31505\loch\f1 Contracts for the Int\hich\af1\dbch\af31505\loch\f1 ernational Sale of Goods is expressly excluded. -\par \hich\af1\dbch\af31505\loch\f1 Any law or regulation which provides that the language of a contract -\par \hich\af1\dbch\af31505\loch\f1 shall be construed against the drafter shall not apply to this -\par \hich\af1\dbch\af31505\loch\f1 License. -\par -\par \hich\af1\dbch\af31505\loch\f1 12. RESPONSIBILITY FOR CLAIMS. -\par -\par \hich\af1\dbch\af31505\loch\f1 As between Ini\hich\af1\dbch\af31505\loch\f1 tial Developer and the Contributors, each party is -\par \hich\af1\dbch\af31505\loch\f1 responsible for claims and damages arising, directly or indirectly, -\par \hich\af1\dbch\af31505\loch\f1 out of its utilization of rights under this License and You agree to -\par \hich\af1\dbch\af31505\loch\f1 work with Initial Developer \hich\af1\dbch\af31505\loch\f1 and Contributors to distribute such -\par \hich\af1\dbch\af31505\loch\f1 responsibility on an equitable basis. Nothing herein is intended or -\par \hich\af1\dbch\af31505\loch\f1 shall be deemed to constitute any admission of liability. -\par -\par \hich\af1\dbch\af31505\loch\f1 13. MULTIPLE-LICENSED CODE. -\par -\par \hich\af1\dbch\af31505\loch\f1 Initial Developer may designate portions of the C\hich\af1\dbch\af31505\loch\f1 overed Code as -\par \hich\af1\dbch\af31505\loch\f1 "Multiple-Licensed". "Multiple-Licensed" means that the Initial -\par \hich\af1\dbch\af31505\loch\f1 Developer permits you to utilize portions of the Covered Code under -\par \hich\af1\dbch\af31505\loch\f1 Your choice of the NPL or the alternative licenses, if any, specified -\par \hich\af1\dbch\af31505\loch\f1 by the Initial Dev\hich\af1\dbch\af31505\loch\f1 eloper in the file described in Exhibit A. -\par -\par \hich\af1\dbch\af31505\loch\f1 EXHIBIT A -Mozilla Public License. -\par -\par \hich\af1\dbch\af31505\loch\f1 ``The contents of this file are subject to the Mozilla Public License -\par \hich\af1\dbch\af31505\loch\f1 Version 1.1 (the "License"); you may not use this file except in -\par \hich\af1\dbch\af31505\loch\f1 compliance with the Licens\hich\af1\dbch\af31505\loch\f1 e. You may obtain a copy of the License at -\par \hich\af1\dbch\af31505\loch\f1 http://www.mozilla.org/MPL/ -\par -\par \hich\af1\dbch\af31505\loch\f1 Software distributed under the License is distributed on an "AS IS" -\par \hich\af1\dbch\af31505\loch\f1 basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the -\par \hich\af1\dbch\af31505\loch\f1 License for the specific\hich\af1\dbch\af31505\loch\f1 language governing rights and limitations -\par \hich\af1\dbch\af31505\loch\f1 under the License. -\par -\par \hich\af1\dbch\af31505\loch\f1 The Original Code is ______________________________________. -\par -\par \hich\af1\dbch\af31505\loch\f1 The Initial Developer of the Original Code is ________________________. -\par \hich\af1\dbch\af31505\loch\f1 Portions created by ______________________ are Copyright (C) ______ -\par \hich\af1\dbch\af31505\loch\f1 _______________________. All Rights Reserved. -\par -\par \hich\af1\dbch\af31505\loch\f1 Contributor(s): ______________________________________. -\par -\par \hich\af1\dbch\af31505\loch\f1 Alternatively, the contents of this file may be used under the t\hich\af1\dbch\af31505\loch\f1 erms -\par \hich\af1\dbch\af31505\loch\f1 of the _____ license (the "[___] License"), in which case the -\par \hich\af1\dbch\af31505\loch\f1 provisions of [______] License are applicable instead of those -\par \hich\af1\dbch\af31505\loch\f1 above. If you wish to allow use of your version of this file only -\par \hich\af1\dbch\af31505\loch\f1 under the terms of the [____] License \hich\af1\dbch\af31505\loch\f1 and not to allow others to use -\par \hich\af1\dbch\af31505\loch\f1 your version of this file under the MPL, indicate your decision by -\par \hich\af1\dbch\af31505\loch\f1 deleting the provisions above and replace them with the notice and -\par \hich\af1\dbch\af31505\loch\f1 other provisions required by the [___] License. If you do not delete -\par \hich\af1\dbch\af31505\loch\f1 \hich\af1\dbch\af31505\loch\f1 the provisions above, a recipient may use your version of this file -\par \hich\af1\dbch\af31505\loch\f1 under either the MPL or the [___] License." -\par -\par \hich\af1\dbch\af31505\loch\f1 [NOTE: The text of this Exhibit A may differ slightly from the text of -\par \hich\af1\dbch\af31505\loch\f1 the notices in the Source Code files of the Original Cod\hich\af1\dbch\af31505\loch\f1 e. You should -\par \hich\af1\dbch\af31505\loch\f1 use the text of this Exhibit A rather than the text found in the -\par \hich\af1\dbch\af31505\loch\f1 Original Code Source Code for Your Modifications.] -\par -\par -\par }{\rtlch\fcs1 \af1\afs20 \ltrch\fcs0 \f1\fs20\lang1033\langfe1049\langnp1033\insrsid9123021\charrsid269322 -\par }{\*\themedata 504b030414000600080000002100e9de0fbfff0000001c020000130000005b436f6e74656e745f54797065735d2e786d6cac91cb4ec3301045f748fc83e52d4a -9cb2400825e982c78ec7a27cc0c8992416c9d8b2a755fbf74cd25442a820166c2cd933f79e3be372bd1f07b5c3989ca74aaff2422b24eb1b475da5df374fd9ad -5689811a183c61a50f98f4babebc2837878049899a52a57be670674cb23d8e90721f90a4d2fa3802cb35762680fd800ecd7551dc18eb899138e3c943d7e503b6 -b01d583deee5f99824e290b4ba3f364eac4a430883b3c092d4eca8f946c916422ecab927f52ea42b89a1cd59c254f919b0e85e6535d135a8de20f20b8c12c3b0 -0c895fcf6720192de6bf3b9e89ecdbd6596cbcdd8eb28e7c365ecc4ec1ff1460f53fe813d3cc7f5b7f020000ffff0300504b030414000600080000002100a5d6 -a7e7c0000000360100000b0000005f72656c732f2e72656c73848fcf6ac3300c87ef85bd83d17d51d2c31825762fa590432fa37d00e1287f68221bdb1bebdb4f -c7060abb0884a4eff7a93dfeae8bf9e194e720169aaa06c3e2433fcb68e1763dbf7f82c985a4a725085b787086a37bdbb55fbc50d1a33ccd311ba548b6309512 -0f88d94fbc52ae4264d1c910d24a45db3462247fa791715fd71f989e19e0364cd3f51652d73760ae8fa8c9ffb3c330cc9e4fc17faf2ce545046e37944c69e462 -a1a82fe353bd90a865aad41ed0b5b8f9d6fd010000ffff0300504b0304140006000800000021006b799616830000008a0000001c0000007468656d652f746865 -6d652f7468656d654d616e616765722e786d6c0ccc4d0ac3201040e17da17790d93763bb284562b2cbaebbf600439c1a41c7a0d29fdbd7e5e38337cedf14d59b -4b0d592c9c070d8a65cd2e88b7f07c2ca71ba8da481cc52c6ce1c715e6e97818c9b48d13df49c873517d23d59085adb5dd20d6b52bd521ef2cdd5eb9246a3d8b -4757e8d3f729e245eb2b260a0238fd010000ffff0300504b03041400060008000000210054b663bbf5060000c21a0000160000007468656d652f7468656d652f -7468656d65312e786d6cec59dd8e133714beafd47718cd7dc8df4c7e5604944c126861019140c5a5377132663de368ecec1221240457bd69558956bd2852db9b -5e5455572a555155d457589e0109d4d287e8b16732b1132f2c2b2aa18a5d6977e27ce7f8f33967bee3199f3e7b2ba2ce1e4e386171cb2d9f2ab90e8e476c4ce2 -69cbbd36ec171aaec3058ac788b218b7dc05e6eed9331f7e701a6d891047d801fb986fa1961b0a31db2a16f90886113fc5663886ef262c8990808fc9b4384ed0 -3ef88d68b1522ad58a1122b1ebc42802b787df1ffe7af8c7e1817379322123ec9e59faef519824165c0e8c683290def1d2e8bba7f70e0f0e9f1c3e3a3c787a17 -ae9fc0ffcf95ed78b72c2df882073471f6106db930f598ed0ff12de13a1471015fb4dc92fa718b674e17d1566644c511b69a5d5ffd647699c178b7a2e64ca63b -f9a49ee77bb576ee5f01a8d8c4f5eabd5aaf96fb5300341ac1ca532eba4fbfd3ec74fd0cab81d24b8bef6ebd5b2d1b78cd7f758373db97bf065e8152ffde06be -df0f208a065e8152bcbf81f7bc7a25f00cbc02a5f8da06be5e6a77bdba8157a090927877035df26bd560b9da1c3261f4bc15def4bd7ebd92395fa1a01af26a93 -534c582c8e5b7b11bac9923e1848438a04891db198e1091a41a10788929d843817c93484429ca19871182e554afd5215feca5f4f5da908a12d8c346bc91398f1 -8d21c9cfe1a384cc44cbfd18bcba1ae4f9e3c7cfee3d7a76efb767f7ef3fbbf77336b77265d89d47f154b77bf9c317ff3cbcebfcfdcbb72f1f7c994ebd8ee73a -fec54f9fbef8fdcf57b98715af42f1fcab83178f0e9e7ffdd95f3f3eb0786f276847870f4984b97309ef3b5759040bb4f0c73bc99b590c4344748b763ce52846 -72168bff9e080df4a505a2c882eb60338ed713901e1bf0dcfca64178102673412c1e2f849101dc668c7658628dc205399716e6e13c9eda274fe63aee2a427bb6 -b903141b59eecd67a0c1c4e63208b141f30a45b140531c63e1c8efd82ec696d5dd20c488eb3619258cb389706e10a78388352443b26354d3cae83c89202f0b1b -41c8b7119bedeb4e8751dbaabb78cf44c2bd81a885fc1053238ce7d05ca0c8e6728822aa07fc2212a18de460918c745c8f0bc8f41453e6f4c698739bcde504d6 -ab25fd02c88c3deddb741199c844905d9bcf8b88311dd965bb4188a2990d3b2071a8633fe2bb50a2c8b9c2840dbecdcc3b447e863ca0f8c8745f27d848f7ebd5 -e01a28ac4e695520f29b7962c9e539cc8cfa1d2ce804612535d0100c5d8f48fc5a915f9377ffbf937710d1e7df3cb4ace8ed48baddb1918f3714f37642ac77d3 -f935093f0ab72edc014bc6e4ddd7ed2e9ac75730dc2a9bcdebbd6cbf976df77f2fdb47ddcf6f5fac57fa0cd22db7ade9f65d6de6a363efe52784d28158507c91 -abed3c872e35eec3a0f4a31e7571feac370be152ded930a1819b2648d93809139f10110e4234833d7fd9954ea63c733de5ce8c71781450c356df124fe7d1361b -a78fb4e5b27c7c4dc58423b11a2ff9f9383c7e88145dabaf1ed372f78aed543d5e2f0948db3721a14d6692a85a48d497833248ea611e826621a156f65658342d -2c1ad2fd32551b2c805a9e15d84639b0f96ab9be072660044f5988e2b1cc539aea65765532df66a68f0aa65101b0a75856c02ad34dc9f5c8e5c9d5a5a5768c4c -1b24b4723349a8c8a89ec64334c65975cad1e3d078d35c37572935e8c950a8f9a0b45634ea8d57b13869aec16e5d1b68ac2b058d9dfd965babfa503223346bb9 -1378150097d10c6a87cbed2fa25378e53612497ac39f44596609175dc4c334e04a7452358888c0894349d472e5f2f334d0586988e256ae8020bcb3e49a202bef -1a3948ba99643c99e091d0d3ae8dc848a71f41e153adb07eabcc4f0e96966c0ee91e84e37d6787ce93ab084accaf976500c784c31ba1721acd3181579eb990ad -ea6fad3165b2abbf735435948e233a0b51d65174314fe14aca733aea531e03ed53b66608a81692ac11ee4c6583d5836a74d3bc6ba41c8eecbaaf379291d34473 -d5330d55915dd3ae62c60ccb36b016cb9335798dd532c4a0697a874fa57b5d729b4bad5bdb27e45d02029ec7cfd2758fd110346aabc90c6a92f1a60c4bcdce46 -cddeb15ce06ba81da74968aa5f5bba5d8b5bde23acd3c1e0893a3fd8ad572d0c4d96fb4c1569755ca21f67b09d9b201e5d78313ca782ab54c2e1448260433450 -7b925436e016b925b25b03ae9c79425aeeed92dff6828a1f144a0dbf57f0aa5ea9d0f0dbd542dbf7abe59e5f2e753b953bd058441895fdf4a8a60fafa5e8223b -b051e31b8736d1f2cddba9118b8a4c9dc5141571756853ae188736e9598d33944732ae4340746ed72afd66b5d9a9159ad576bfe0753b8d4233a8750add5a50ef -f6bb81df68f6efb8ce9e027bed6ae0d57a8d42ad1c0405af5692f41bcd42ddab54da5ebddde879ed3bd93606569eca47160b08afe275e65f000000ffff030050 -4b0304140006000800000021000dd1909fb60000001b010000270000007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e -72656c73848f4d0ac2301484f78277086f6fd3ba109126dd88d0add40384e4350d363f2451eced0dae2c082e8761be9969bb979dc9136332de3168aa1a083ae9 -95719ac16db8ec8e4052164e89d93b64b060828e6f37ed1567914b284d262452282e3198720e274a939cd08a54f980ae38a38f56e422a3a641c8bbd048f7757d -a0f19b017cc524bd62107bd5001996509affb3fd381a89672f1f165dfe514173d9850528a2c6cce0239baa4c04ca5bbabac4df000000ffff0300504b01022d00 -14000600080000002100e9de0fbfff0000001c0200001300000000000000000000000000000000005b436f6e74656e745f54797065735d2e786d6c504b01022d -0014000600080000002100a5d6a7e7c0000000360100000b00000000000000000000000000300100005f72656c732f2e72656c73504b01022d00140006000800 -000021006b799616830000008a0000001c00000000000000000000000000190200007468656d652f7468656d652f7468656d654d616e616765722e786d6c504b -01022d001400060008000000210054b663bbf5060000c21a00001600000000000000000000000000d60200007468656d652f7468656d652f7468656d65312e78 -6d6c504b01022d00140006000800000021000dd1909fb60000001b0100002700000000000000000000000000ff0900007468656d652f7468656d652f5f72656c732f7468656d654d616e616765722e786d6c2e72656c73504b050600000000050005005d010000fa0a00000000} -{\*\colorschememapping 3c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d22796573223f3e0d0a3c613a636c724d -617020786d6c6e733a613d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f64726177696e676d6c2f323030362f6d6169 -6e22206267313d226c743122207478313d22646b3122206267323d226c743222207478323d22646b322220616363656e74313d22616363656e74312220616363 -656e74323d22616363656e74322220616363656e74333d22616363656e74332220616363656e74343d22616363656e74342220616363656e74353d22616363656e74352220616363656e74363d22616363656e74362220686c696e6b3d22686c696e6b2220666f6c486c696e6b3d22666f6c486c696e6b222f3e} -{\*\latentstyles\lsdstimax371\lsdlockeddef0\lsdsemihiddendef0\lsdunhideuseddef0\lsdqformatdef0\lsdprioritydef99{\lsdlockedexcept \lsdqformat1 \lsdpriority0 \lsdlocked0 Normal;\lsdqformat1 \lsdpriority9 \lsdlocked0 heading 1; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 2;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 3;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 4; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 5;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 6;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 7; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 8;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority9 \lsdlocked0 heading 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 1; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 5; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 6;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index 9; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 1;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 2;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 3; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 4;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 5;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 6; -\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 7;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 8;\lsdsemihidden1 \lsdunhideused1 \lsdpriority39 \lsdlocked0 toc 9;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Indent; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 header;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footer; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 index heading;\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority35 \lsdlocked0 caption;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of figures; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 envelope return;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 footnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation reference; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 line number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 page number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote reference;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 endnote text; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 table of authorities;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 macro;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 toa heading;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Bullet 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Number 5;\lsdqformat1 \lsdpriority10 \lsdlocked0 Title;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Closing; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Signature;\lsdsemihidden1 \lsdunhideused1 \lsdpriority1 \lsdlocked0 Default Paragraph Font;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 4; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 List Continue 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Message Header;\lsdqformat1 \lsdpriority11 \lsdlocked0 Subtitle;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Salutation; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Date;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text First Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Note Heading; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Body Text Indent 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Block Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Hyperlink;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 FollowedHyperlink;\lsdqformat1 \lsdpriority22 \lsdlocked0 Strong; -\lsdqformat1 \lsdpriority20 \lsdlocked0 Emphasis;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Document Map;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Plain Text;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 E-mail Signature; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Top of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Bottom of Form;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal (Web);\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Acronym; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Address;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Cite;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Code;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Definition; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Keyboard;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Preformatted;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Sample;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Typewriter; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 HTML Variable;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Normal Table;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 annotation subject;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 No List; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Outline List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 1; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Simple 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Classic 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Colorful 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 3; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Columns 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 6; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Grid 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 4;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 5;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 6; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 7;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table List 8;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table 3D effects 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Contemporary;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Elegant;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Professional; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Subtle 2;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 1;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 2; -\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Web 3;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Balloon Text;\lsdpriority39 \lsdlocked0 Table Grid;\lsdsemihidden1 \lsdunhideused1 \lsdlocked0 Table Theme;\lsdsemihidden1 \lsdlocked0 Placeholder Text; -\lsdqformat1 \lsdpriority1 \lsdlocked0 No Spacing;\lsdpriority60 \lsdlocked0 Light Shading;\lsdpriority61 \lsdlocked0 Light List;\lsdpriority62 \lsdlocked0 Light Grid;\lsdpriority63 \lsdlocked0 Medium Shading 1;\lsdpriority64 \lsdlocked0 Medium Shading 2; -\lsdpriority65 \lsdlocked0 Medium List 1;\lsdpriority66 \lsdlocked0 Medium List 2;\lsdpriority67 \lsdlocked0 Medium Grid 1;\lsdpriority68 \lsdlocked0 Medium Grid 2;\lsdpriority69 \lsdlocked0 Medium Grid 3;\lsdpriority70 \lsdlocked0 Dark List; -\lsdpriority71 \lsdlocked0 Colorful Shading;\lsdpriority72 \lsdlocked0 Colorful List;\lsdpriority73 \lsdlocked0 Colorful Grid;\lsdpriority60 \lsdlocked0 Light Shading Accent 1;\lsdpriority61 \lsdlocked0 Light List Accent 1; -\lsdpriority62 \lsdlocked0 Light Grid Accent 1;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 1;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 1;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 1;\lsdsemihidden1 \lsdlocked0 Revision; -\lsdqformat1 \lsdpriority34 \lsdlocked0 List Paragraph;\lsdqformat1 \lsdpriority29 \lsdlocked0 Quote;\lsdqformat1 \lsdpriority30 \lsdlocked0 Intense Quote;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 1;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 1; -\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 1;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 1;\lsdpriority70 \lsdlocked0 Dark List Accent 1;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 1;\lsdpriority72 \lsdlocked0 Colorful List Accent 1; -\lsdpriority73 \lsdlocked0 Colorful Grid Accent 1;\lsdpriority60 \lsdlocked0 Light Shading Accent 2;\lsdpriority61 \lsdlocked0 Light List Accent 2;\lsdpriority62 \lsdlocked0 Light Grid Accent 2;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 2; -\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 2;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 2;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 2;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 2;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 2; -\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 2;\lsdpriority70 \lsdlocked0 Dark List Accent 2;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 2;\lsdpriority72 \lsdlocked0 Colorful List Accent 2;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 2; -\lsdpriority60 \lsdlocked0 Light Shading Accent 3;\lsdpriority61 \lsdlocked0 Light List Accent 3;\lsdpriority62 \lsdlocked0 Light Grid Accent 3;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 3;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 3; -\lsdpriority65 \lsdlocked0 Medium List 1 Accent 3;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 3;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 3;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 3;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 3; -\lsdpriority70 \lsdlocked0 Dark List Accent 3;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 3;\lsdpriority72 \lsdlocked0 Colorful List Accent 3;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 3;\lsdpriority60 \lsdlocked0 Light Shading Accent 4; -\lsdpriority61 \lsdlocked0 Light List Accent 4;\lsdpriority62 \lsdlocked0 Light Grid Accent 4;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 4;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 4;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 4; -\lsdpriority66 \lsdlocked0 Medium List 2 Accent 4;\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 4;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 4;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 4;\lsdpriority70 \lsdlocked0 Dark List Accent 4; -\lsdpriority71 \lsdlocked0 Colorful Shading Accent 4;\lsdpriority72 \lsdlocked0 Colorful List Accent 4;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 4;\lsdpriority60 \lsdlocked0 Light Shading Accent 5;\lsdpriority61 \lsdlocked0 Light List Accent 5; -\lsdpriority62 \lsdlocked0 Light Grid Accent 5;\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 5;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 5;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 5;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 5; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 5;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 5;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 5;\lsdpriority70 \lsdlocked0 Dark List Accent 5;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 5; -\lsdpriority72 \lsdlocked0 Colorful List Accent 5;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 5;\lsdpriority60 \lsdlocked0 Light Shading Accent 6;\lsdpriority61 \lsdlocked0 Light List Accent 6;\lsdpriority62 \lsdlocked0 Light Grid Accent 6; -\lsdpriority63 \lsdlocked0 Medium Shading 1 Accent 6;\lsdpriority64 \lsdlocked0 Medium Shading 2 Accent 6;\lsdpriority65 \lsdlocked0 Medium List 1 Accent 6;\lsdpriority66 \lsdlocked0 Medium List 2 Accent 6; -\lsdpriority67 \lsdlocked0 Medium Grid 1 Accent 6;\lsdpriority68 \lsdlocked0 Medium Grid 2 Accent 6;\lsdpriority69 \lsdlocked0 Medium Grid 3 Accent 6;\lsdpriority70 \lsdlocked0 Dark List Accent 6;\lsdpriority71 \lsdlocked0 Colorful Shading Accent 6; -\lsdpriority72 \lsdlocked0 Colorful List Accent 6;\lsdpriority73 \lsdlocked0 Colorful Grid Accent 6;\lsdqformat1 \lsdpriority19 \lsdlocked0 Subtle Emphasis;\lsdqformat1 \lsdpriority21 \lsdlocked0 Intense Emphasis; -\lsdqformat1 \lsdpriority31 \lsdlocked0 Subtle Reference;\lsdqformat1 \lsdpriority32 \lsdlocked0 Intense Reference;\lsdqformat1 \lsdpriority33 \lsdlocked0 Book Title;\lsdsemihidden1 \lsdunhideused1 \lsdpriority37 \lsdlocked0 Bibliography; -\lsdsemihidden1 \lsdunhideused1 \lsdqformat1 \lsdpriority39 \lsdlocked0 TOC Heading;\lsdpriority41 \lsdlocked0 Plain Table 1;\lsdpriority42 \lsdlocked0 Plain Table 2;\lsdpriority43 \lsdlocked0 Plain Table 3;\lsdpriority44 \lsdlocked0 Plain Table 4; -\lsdpriority45 \lsdlocked0 Plain Table 5;\lsdpriority40 \lsdlocked0 Grid Table Light;\lsdpriority46 \lsdlocked0 Grid Table 1 Light;\lsdpriority47 \lsdlocked0 Grid Table 2;\lsdpriority48 \lsdlocked0 Grid Table 3;\lsdpriority49 \lsdlocked0 Grid Table 4; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 1; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 1;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 1;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 1; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 1;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 2;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 2; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 2;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 2; -\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 3;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 3;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 3;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 3; -\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 3;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 4; -\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 4;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 4;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 4;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 4; -\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 4;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 5; -\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 5;\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 5;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 5; -\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 5;\lsdpriority46 \lsdlocked0 Grid Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 Grid Table 2 Accent 6;\lsdpriority48 \lsdlocked0 Grid Table 3 Accent 6; -\lsdpriority49 \lsdlocked0 Grid Table 4 Accent 6;\lsdpriority50 \lsdlocked0 Grid Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 Grid Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 Grid Table 7 Colorful Accent 6; -\lsdpriority46 \lsdlocked0 List Table 1 Light;\lsdpriority47 \lsdlocked0 List Table 2;\lsdpriority48 \lsdlocked0 List Table 3;\lsdpriority49 \lsdlocked0 List Table 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful;\lsdpriority52 \lsdlocked0 List Table 7 Colorful;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 1;\lsdpriority47 \lsdlocked0 List Table 2 Accent 1;\lsdpriority48 \lsdlocked0 List Table 3 Accent 1; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 1;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 1;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 1;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 1; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 2;\lsdpriority47 \lsdlocked0 List Table 2 Accent 2;\lsdpriority48 \lsdlocked0 List Table 3 Accent 2;\lsdpriority49 \lsdlocked0 List Table 4 Accent 2; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 2;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 2;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 2;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 3; -\lsdpriority47 \lsdlocked0 List Table 2 Accent 3;\lsdpriority48 \lsdlocked0 List Table 3 Accent 3;\lsdpriority49 \lsdlocked0 List Table 4 Accent 3;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 3; -\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 3;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 3;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 4;\lsdpriority47 \lsdlocked0 List Table 2 Accent 4; -\lsdpriority48 \lsdlocked0 List Table 3 Accent 4;\lsdpriority49 \lsdlocked0 List Table 4 Accent 4;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 4;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 4; -\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 4;\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 5;\lsdpriority47 \lsdlocked0 List Table 2 Accent 5;\lsdpriority48 \lsdlocked0 List Table 3 Accent 5; -\lsdpriority49 \lsdlocked0 List Table 4 Accent 5;\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 5;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 5;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 5; -\lsdpriority46 \lsdlocked0 List Table 1 Light Accent 6;\lsdpriority47 \lsdlocked0 List Table 2 Accent 6;\lsdpriority48 \lsdlocked0 List Table 3 Accent 6;\lsdpriority49 \lsdlocked0 List Table 4 Accent 6; -\lsdpriority50 \lsdlocked0 List Table 5 Dark Accent 6;\lsdpriority51 \lsdlocked0 List Table 6 Colorful Accent 6;\lsdpriority52 \lsdlocked0 List Table 7 Colorful Accent 6;}}{\*\datastore 010500000200000018000000 -4d73786d6c322e534158584d4c5265616465722e362e30000000000000000000000e0000 -d0cf11e0a1b11ae1000000000000000000000000000000003e000300feff0900060000000000000000000000010000000100000000000000001000000200000001000000feffffff0000000000000000ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -fffffffffffffffffdffffff04000000feffffff05000000fefffffffeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffff52006f006f007400200045006e00740072007900000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000500ffffffffffffffff010000000c6ad98892f1d411a65f0040963251e50000000000000000000000006073 -1aa2cad9d3010300000080020000000000004d0073006f004400610074006100530074006f0072006500000000000000000000000000000000000000000000000000000000000000000000000000000000001a000101ffffffffffffffff02000000000000000000000000000000000000000000000060731aa2cad9d301 -60731aa2cad9d301000000000000000000000000ca003500d9005100cc004600cd00cc00c300d4003400de00d4005300c800dd00d500de005a005300d30051003d003d000000000000000000000000000000000032000101ffffffffffffffff03000000000000000000000000000000000000000000000060731aa2cad9 -d30160731aa2cad9d3010000000000000000000000004900740065006d0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000a000201ffffffff04000000ffffffff000000000000000000000000000000000000000000000000 -00000000000000000000000000000000f100000000000000010000000200000003000000feffffff0500000006000000070000000800000009000000feffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff -ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3c623a536f757263657320786d6c6e733a623d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f6772617068792220786d6c6e733d -22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222053656c65637465645374796c653d225c415041536978746845646974696f6e4f66666963654f6e6c696e652e78736c22205374796c654e616d -653d22415041222056657273696f6e3d2236222f3e0000000000000000000000000000003c3f786d6c2076657273696f6e3d22312e302220656e636f64696e673d225554462d3822207374616e64616c6f6e653d226e6f223f3e0d0a3c64733a6461746173746f72654974656d2064733a6974656d49443d227b42303530 -464541392d364335422d343738462d424544312d3241334444374536353243447d2220786d6c6e733a64733d22687474703a2f2f736368656d61732e6f70656e786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f637573746f6d586d6c223e3c64733a736368656d61526566733e3c -64733a736368656d615265662064733a7572693d22687474703a2f2f736368656d61732e6f70656e500072006f007000650072007400690065007300000000000000000000000000000000000000000000000000000000000000000000000000000000000000000016000200ffffffffffffffffffffffff000000000000 -0000000000000000000000000000000000000000000000000000000000000400000055010000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff00000000 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff0000 -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000ffffffffffffffffffffffff -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000786d6c666f726d6174732e6f72672f6f6666696365446f63756d656e742f323030362f6269626c696f677261706879222f3e3c2f64733a736368656d61526566733e3c2f64733a6461746173746f -72654974656d3e0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 -00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000105000000000000}} +{\rtf1\ansi\ansicpg1251\deff0\nouicompat\deflang1049\deflangfe1049{\fonttbl{\f0\fswiss\fprq2\fcharset204 Arial;}{\f1\fswiss\fprq2\fcharset0 Arial;}} +{\colortbl ;\red0\green0\blue255;} +{\*\generator Riched20 10.0.17763}{\*\mmathPr\mnaryLim0\mdispDef1\mwrapIndent1440 }\viewkind4\uc1 +\pard\nowidctlpar\f0\fs20 MOZILLA PUBLIC LICENSE\par +Version 1.1\par +\par +---------------\par +\par +1. Definitions.\par +\par + 1.0.1. "Commercial Use" means distribution or otherwise making the\par + Covered Code available to a third party.\par +\par + 1.1. "Contributor" means each entity that creates or contributes to\par + the creation of Modifications.\par +\par + 1.2. "Contributor Version" means the combination of the Original\par + Code, prior Modifications used by a Contributor, and the Modifications\par + made by that particular Contributor.\par +\par + 1.3. "Covered Code" means the Original Code or Modifications or the\par + combination of the Original Code and Modifications, in each case\par + including portions thereof.\par +\par + 1.4. "Electronic Distribution Mechanism" means a mechanism generally\par + accepted in the software development community for the electronic\par + transfer of data.\par +\par + 1.5. "Executable" means Covered Code in any form other than Source\par + Code.\par +\par + 1.6. "Initial Developer" means the individual or entity identified\par + as the Initial Developer in the Source Code notice required by Exhibit\par + A.\par +\par + 1.7. "Larger Work" means a work which combines Covered Code or\par + portions thereof with code not governed by the terms of this License.\par +\par + 1.8. "License" means this document.\par +\par + 1.8.1. "Licensable" means having the right to grant, to the maximum\par + extent possible, whether at the time of the initial grant or\par + subsequently acquired, any and all of the rights conveyed herein.\par +\par + 1.9. "Modifications" means any addition to or deletion from the\par + substance or structure of either the Original Code or any previous\par + Modifications. When Covered Code is released as a series of files, a\par + Modification is:\par + A. Any addition to or deletion from the contents of a file\par + containing Original Code or previous Modifications.\par +\par + B. Any new file that contains any part of the Original Code or\par + previous Modifications.\par +\par + 1.10. "Original Code" means Source Code of computer software code\par + which is described in the Source Code notice required by Exhibit A as\par + Original Code, and which, at the time of its release under this\par + License is not already Covered Code governed by this License.\par +\par + 1.10.1. "Patent Claims" means any patent claim(s), now owned or\par + hereafter acquired, including without limitation, method, process,\par + and apparatus claims, in any patent Licensable by grantor.\par +\par + 1.11. "Source Code" means the preferred form of the Covered Code for\par + making modifications to it, including all modules it contains, plus\par + any associated interface definition files, scripts used to control\par + compilation and installation of an Executable, or source code\par + differential comparisons against either the Original Code or another\par + well known, available Covered Code of the Contributor's choice. The\par + Source Code can be in a compressed or archival form, provided the\par + appropriate decompression or de-archiving software is widely available\par + for no charge.\par +\par + 1.12. "You" (or "Your") means an individual or a legal entity\par + exercising rights under, and complying with all of the terms of, this\par + License or a future version of this License issued under Section 6.1.\par + For legal entities, "You" includes any entity which controls, is\par + controlled by, or is under common control with You. For purposes of\par + this definition, "control" means (a) the power, direct or indirect,\par + to cause the direction or management of such entity, whether by\par + contract or otherwise, or (b) ownership of more than fifty percent\par + (50%) of the outstanding shares or beneficial ownership of such\par + entity.\par +\par +2. Source Code License.\par +\par + 2.1. The Initial Developer Grant.\par + The Initial Developer hereby grants You a world-wide, royalty-free,\par + non-exclusive license, subject to third party intellectual property\par + claims:\par + (a) under intellectual property rights (other than patent or\par + trademark) Licensable by Initial Developer to use, reproduce,\par + modify, display, perform, sublicense and distribute the Original\par + Code (or portions thereof) with or without Modifications, and/or\par + as part of a Larger Work; and\par +\par + (b) under Patents Claims infringed by the making, using or\par + selling of Original Code, to make, have made, use, practice,\par + sell, and offer for sale, and/or otherwise dispose of the\par + Original Code (or portions thereof).\par +\par + (c) the licenses granted in this Section 2.1(a) and (b) are\par + effective on the date Initial Developer first distributes\par + Original Code under the terms of this License.\par +\par + (d) Notwithstanding Section 2.1(b) above, no patent license is\par + granted: 1) for code that You delete from the Original Code; 2)\par + separate from the Original Code; or 3) for infringements caused\par + by: i) the modification of the Original Code or ii) the\par + combination of the Original Code with other software or devices.\par +\par + 2.2. Contributor Grant.\par + Subject to third party intellectual property claims, each Contributor\par + hereby grants You a world-wide, royalty-free, non-exclusive license\par +\par + (a) under intellectual property rights (other than patent or\par + trademark) Licensable by Contributor, to use, reproduce, modify,\par + display, perform, sublicense and distribute the Modifications\par + created by such Contributor (or portions thereof) either on an\par + unmodified basis, with other Modifications, as Covered Code\par + and/or as part of a Larger Work; and\par +\par + (b) under Patent Claims infringed by the making, using, or\par + selling of Modifications made by that Contributor either alone\par + and/or in combination with its Contributor Version (or portions\par + of such combination), to make, use, sell, offer for sale, have\par + made, and/or otherwise dispose of: 1) Modifications made by that\par + Contributor (or portions thereof); and 2) the combination of\par + Modifications made by that Contributor with its Contributor\par + Version (or portions of such combination).\par +\par + (c) the licenses granted in Sections 2.2(a) and 2.2(b) are\par + effective on the date Contributor first makes Commercial Use of\par + the Covered Code.\par +\par + (d) Notwithstanding Section 2.2(b) above, no patent license is\par + granted: 1) for any code that Contributor has deleted from the\par + Contributor Version; 2) separate from the Contributor Version;\par + 3) for infringements caused by: i) third party modifications of\par + Contributor Version or ii) the combination of Modifications made\par + by that Contributor with other software (except as part of the\par + Contributor Version) or other devices; or 4) under Patent Claims\par + infringed by Covered Code in the absence of Modifications made by\par + that Contributor.\par +\par +3. Distribution Obligations.\par +\par + 3.1. Application of License.\par + The Modifications which You create or to which You contribute are\par + governed by the terms of this License, including without limitation\par + Section 2.2. The Source Code version of Covered Code may be\par + distributed only under the terms of this License or a future version\par + of this License released under Section 6.1, and You must include a\par + copy of this License with every copy of the Source Code You\par + distribute. You may not offer or impose any terms on any Source Code\par + version that alters or restricts the applicable version of this\par + License or the recipients' rights hereunder. However, You may include\par + an additional document offering the additional rights described in\par + Section 3.5.\par +\par + 3.2. Availability of Source Code.\par + Any Modification which You create or to which You contribute must be\par + made available in Source Code form under the terms of this License\par + either on the same media as an Executable version or via an accepted\par + Electronic Distribution Mechanism to anyone to whom you made an\par + Executable version available; and if made available via Electronic\par + Distribution Mechanism, must remain available for at least twelve (12)\par + months after the date it initially became available, or at least six\par + (6) months after a subsequent version of that particular Modification\par + has been made available to such recipients. You are responsible for\par + ensuring that the Source Code version remains available even if the\par + Electronic Distribution Mechanism is maintained by a third party.\par +\par + 3.3. Description of Modifications.\par + You must cause all Covered Code to which You contribute to contain a\par + file documenting the changes You made to create that Covered Code and\par + the date of any change. You must include a prominent statement that\par + the Modification is derived, directly or indirectly, from Original\par + Code provided by the Initial Developer and including the name of the\par + Initial Developer in (a) the Source Code, and (b) in any notice in an\par + Executable version or related documentation in which You describe the\par + origin or ownership of the Covered Code.\par +\par + 3.4. Intellectual Property Matters\par + (a) Third Party Claims.\par + If Contributor has knowledge that a license under a third party's\par + intellectual property rights is required to exercise the rights\par + granted by such Contributor under Sections 2.1 or 2.2,\par + Contributor must include a text file with the Source Code\par + distribution titled "LEGAL" which describes the claim and the\par + party making the claim in sufficient detail that a recipient will\par + know whom to contact. If Contributor obtains such knowledge after\par + the Modification is made available as described in Section 3.2,\par + Contributor shall promptly modify the LEGAL file in all copies\par + Contributor makes available thereafter and shall take other steps\par + (such as notifying appropriate mailing lists or newsgroups)\par + reasonably calculated to inform those who received the Covered\par + Code that new knowledge has been obtained.\par +\par + (b) Contributor APIs.\par + If Contributor's Modifications include an application programming\par + interface and Contributor has knowledge of patent licenses which\par + are reasonably necessary to implement that API, Contributor must\par + also include this information in the LEGAL file.\par +\par + (c) Representations.\par + Contributor represents that, except as disclosed pursuant to\par + Section 3.4(a) above, Contributor believes that Contributor's\par + Modifications are Contributor's original creation(s) and/or\par + Contributor has sufficient rights to grant the rights conveyed by\par + this License.\par +\par + 3.5. Required Notices.\par + You must duplicate the notice in Exhibit A in each file of the Source\par + Code. If it is not possible to put such notice in a particular Source\par + Code file due to its structure, then You must include such notice in a\par + location (such as a relevant directory) where a user would be likely\par + to look for such a notice. If You created one or more Modification(s)\par + You may add your name as a Contributor to the notice described in\par + Exhibit A. You must also duplicate this License in any documentation\par + for the Source Code where You describe recipients' rights or ownership\par + rights relating to Covered Code. You may choose to offer, and to\par + charge a fee for, warranty, support, indemnity or liability\par + obligations to one or more recipients of Covered Code. However, You\par + may do so only on Your own behalf, and not on behalf of the Initial\par + Developer or any Contributor. You must make it absolutely clear than\par + any such warranty, support, indemnity or liability obligation is\par + offered by You alone, and You hereby agree to indemnify the Initial\par + Developer and every Contributor for any liability incurred by the\par + Initial Developer or such Contributor as a result of warranty,\par + support, indemnity or liability terms You offer.\par +\par + 3.6. Distribution of Executable Versions.\par + You may distribute Covered Code in Executable form only if the\par + requirements of Section 3.1-3.5 have been met for that Covered Code,\par + and if You include a notice stating that the Source Code version of\par + the Covered Code is available under the terms of this License,\par + including a description of how and where You have fulfilled the\par + obligations of Section 3.2. The notice must be conspicuously included\par + in any notice in an Executable version, related documentation or\par + collateral in which You describe recipients' rights relating to the\par + Covered Code. You may distribute the Executable version of Covered\par + Code or ownership rights under a license of Your choice, which may\par + contain terms different from this License, provided that You are in\par + compliance with the terms of this License and that the license for the\par + Executable version does not attempt to limit or alter the recipient's\par + rights in the Source Code version from the rights set forth in this\par + License. If You distribute the Executable version under a different\par + license You must make it absolutely clear that any terms which differ\par + from this License are offered by You alone, not by the Initial\par + Developer or any Contributor. You hereby agree to indemnify the\par + Initial Developer and every Contributor for any liability incurred by\par + the Initial Developer or such Contributor as a result of any such\par + terms You offer.\par +\par + 3.7. Larger Works.\par + You may create a Larger Work by combining Covered Code with other code\par + not governed by the terms of this License and distribute the Larger\par + Work as a single product. In such a case, You must make sure the\par + requirements of this License are fulfilled for the Covered Code.\par +\par +4. Inability to Comply Due to Statute or Regulation.\par +\par + If it is impossible for You to comply with any of the terms of this\par + License with respect to some or all of the Covered Code due to\par + statute, judicial order, or regulation then You must: (a) comply with\par + the terms of this License to the maximum extent possible; and (b)\par + describe the limitations and the code they affect. Such description\par + must be included in the LEGAL file described in Section 3.4 and must\par + be included with all distributions of the Source Code. Except to the\par + extent prohibited by statute or regulation, such description must be\par + sufficiently detailed for a recipient of ordinary skill to be able to\par + understand it.\par +\par +5. Application of this License.\par +\par + This License applies to code to which the Initial Developer has\par + attached the notice in Exhibit A and to related Covered Code.\par +\par +6. Versions of the License.\par +\par + 6.1. New Versions.\par + Netscape Communications Corporation ("Netscape") may publish revised\par + and/or new versions of the License from time to time. Each version\par + will be given a distinguishing version number.\par +\par + 6.2. Effect of New Versions.\par + Once Covered Code has been published under a particular version of the\par + License, You may always continue to use it under the terms of that\par + version. You may also choose to use such Covered Code under the terms\par + of any subsequent version of the License published by Netscape. No one\par + other than Netscape has the right to modify the terms applicable to\par + Covered Code created under this License.\par +\par + 6.3. Derivative Works.\par + If You create or use a modified version of this License (which you may\par + only do in order to apply it to code which is not already Covered Code\par + governed by this License), You must (a) rename Your license so that\par + the phrases "Mozilla", "MOZILLAPL", "MOZPL", "Netscape",\par + "MPL", "NPL" or any confusingly similar phrase do not appear in your\par + license (except to note that your license differs from this License)\par + and (b) otherwise make it clear that Your version of the license\par + contains terms which differ from the Mozilla Public License and\par + Netscape Public License. (Filling in the name of the Initial\par + Developer, Original Code or Contributor in the notice described in\par + Exhibit A shall not of themselves be deemed to be modifications of\par + this License.)\par +\par +7. DISCLAIMER OF WARRANTY.\par +\par + COVERED CODE IS PROVIDED UNDER THIS LICENSE ON AN "AS IS" BASIS,\par + WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,\par + WITHOUT LIMITATION, WARRANTIES THAT THE COVERED CODE IS FREE OF\par + DEFECTS, MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE OR NON-INFRINGING.\par + THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE COVERED CODE\par + IS WITH YOU. SHOULD ANY COVERED CODE PROVE DEFECTIVE IN ANY RESPECT,\par + YOU (NOT THE INITIAL DEVELOPER OR ANY OTHER CONTRIBUTOR) ASSUME THE\par + COST OF ANY NECESSARY SERVICING, REPAIR OR CORRECTION. THIS DISCLAIMER\par + OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE. NO USE OF\par + ANY COVERED CODE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.\par +\par +8. TERMINATION.\par +\par + 8.1. This License and the rights granted hereunder will terminate\par + automatically if You fail to comply with terms herein and fail to cure\par + such breach within 30 days of becoming aware of the breach. All\par + sublicenses to the Covered Code which are properly granted shall\par + survive any termination of this License. Provisions which, by their\par + nature, must remain in effect beyond the termination of this License\par + shall survive.\par +\par + 8.2. If You initiate litigation by asserting a patent infringement\par + claim (excluding declatory judgment actions) against Initial Developer\par + or a Contributor (the Initial Developer or Contributor against whom\par + You file such action is referred to as "Participant") alleging that:\par +\par + (a) such Participant's Contributor Version directly or indirectly\par + infringes any patent, then any and all rights granted by such\par + Participant to You under Sections 2.1 and/or 2.2 of this License\par + shall, upon 60 days notice from Participant terminate prospectively,\par + unless if within 60 days after receipt of notice You either: (i)\par + agree in writing to pay Participant a mutually agreeable reasonable\par + royalty for Your past and future use of Modifications made by such\par + Participant, or (ii) withdraw Your litigation claim with respect to\par + the Contributor Version against such Participant. If within 60 days\par + of notice, a reasonable royalty and payment arrangement are not\par + mutually agreed upon in writing by the parties or the litigation claim\par + is not withdrawn, the rights granted by Participant to You under\par + Sections 2.1 and/or 2.2 automatically terminate at the expiration of\par + the 60 day notice period specified above.\par +\par + (b) any software, hardware, or device, other than such Participant's\par + Contributor Version, directly or indirectly infringes any patent, then\par + any rights granted to You by such Participant under Sections 2.1(b)\par + and 2.2(b) are revoked effective as of the date You first made, used,\par + sold, distributed, or had made, Modifications made by that\par + Participant.\par +\par + 8.3. If You assert a patent infringement claim against Participant\par + alleging that such Participant's Contributor Version directly or\par + indirectly infringes any patent where such claim is resolved (such as\par + by license or settlement) prior to the initiation of patent\par + infringement litigation, then the reasonable value of the licenses\par + granted by such Participant under Sections 2.1 or 2.2 shall be taken\par + into account in determining the amount or value of any payment or\par + license.\par +\par + 8.4. In the event of termination under Sections 8.1 or 8.2 above,\par + all end user license agreements (excluding distributors and resellers)\par + which have been validly granted by You or any distributor hereunder\par + prior to termination shall survive termination.\par +\par +9. LIMITATION OF LIABILITY.\par +\par + UNDER NO CIRCUMSTANCES AND UNDER NO LEGAL THEORY, WHETHER TORT\par + (INCLUDING NEGLIGENCE), CONTRACT, OR OTHERWISE, SHALL YOU, THE INITIAL\par + DEVELOPER, ANY OTHER CONTRIBUTOR, OR ANY DISTRIBUTOR OF COVERED CODE,\par + OR ANY SUPPLIER OF ANY OF SUCH PARTIES, BE LIABLE TO ANY PERSON FOR\par + ANY INDIRECT, SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES OF ANY\par + CHARACTER INCLUDING, WITHOUT LIMITATION, DAMAGES FOR LOSS OF GOODWILL,\par + WORK STOPPAGE, COMPUTER FAILURE OR MALFUNCTION, OR ANY AND ALL OTHER\par + COMMERCIAL DAMAGES OR LOSSES, EVEN IF SUCH PARTY SHALL HAVE BEEN\par + INFORMED OF THE POSSIBILITY OF SUCH DAMAGES. THIS LIMITATION OF\par + LIABILITY SHALL NOT APPLY TO LIABILITY FOR DEATH OR PERSONAL INJURY\par + RESULTING FROM SUCH PARTY'S NEGLIGENCE TO THE EXTENT APPLICABLE LAW\par + PROHIBITS SUCH LIMITATION. SOME JURISDICTIONS DO NOT ALLOW THE\par + EXCLUSION OR LIMITATION OF INCIDENTAL OR CONSEQUENTIAL DAMAGES, SO\par + THIS EXCLUSION AND LIMITATION MAY NOT APPLY TO YOU.\par +\par +10. U.S. GOVERNMENT END USERS.\par +\par + The Covered Code is a "commercial item," as that term is defined in\par + 48 C.F.R. 2.101 (Oct. 1995), consisting of "commercial computer\par + software" and "commercial computer software documentation," as such\par + terms are used in 48 C.F.R. 12.212 (Sept. 1995). Consistent with 48\par + C.F.R. 12.212 and 48 C.F.R. 227.7202-1 through 227.7202-4 (June 1995),\par + all U.S. Government End Users acquire Covered Code with only those\par + rights set forth herein.\par +\par +11. MISCELLANEOUS.\par +\par + This License represents the complete agreement concerning subject\par + matter hereof. If any provision of this License is held to be\par + unenforceable, such provision shall be reformed only to the extent\par + necessary to make it enforceable. This License shall be governed by\par + California law provisions (except to the extent applicable law, if\par + any, provides otherwise), excluding its conflict-of-law provisions.\par + With respect to disputes in which at least one party is a citizen of,\par + or an entity chartered or registered to do business in the United\par + States of America, any litigation relating to this License shall be\par + subject to the jurisdiction of the Federal Courts of the Northern\par + District of California, with venue lying in Santa Clara County,\par + California, with the losing party responsible for costs, including\par + without limitation, court costs and reasonable attorneys' fees and\par + expenses. The application of the United Nations Convention on\par + Contracts for the International Sale of Goods is expressly excluded.\par + Any law or regulation which provides that the language of a contract\par + shall be construed against the drafter shall not apply to this\par + License.\par +\par +12. RESPONSIBILITY FOR CLAIMS.\par +\par + As between Initial Developer and the Contributors, each party is\par + responsible for claims and damages arising, directly or indirectly,\par + out of its utilization of rights under this License and You agree to\par + work with Initial Developer and Contributors to distribute such\par + responsibility on an equitable basis. Nothing herein is intended or\par + shall be deemed to constitute any admission of liability.\par +\par +13. MULTIPLE-LICENSED CODE.\par +\par + Initial Developer may designate portions of the Covered Code as\par + "Multiple-Licensed". "Multiple-Licensed" means that the Initial\par + Developer permits you to utilize portions of the Covered Code under\par + Your choice of the NPL or the alternative licenses, if any, specified\par + by the Initial Developer in the file described in Exhibit A.\par +\par +EXHIBIT A -Mozilla Public License.\par +\par + ``The contents of this file are subject to the Mozilla Public License\par + Version 1.1 (the "License"); you may not use this file except in\par + compliance with the License. You may obtain a copy of the License at\par + {{\field{\*\fldinst{HYPERLINK http://www.mozilla.org/MPL/ }}{\fldrslt{http://www.mozilla.org/MPL/\ul0\cf0}}}}\f0\fs20\par +\par + Software distributed under the License is distributed on an "AS IS"\par + basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See the\par + License for the specific language governing rights and limitations\par + under the License.\par +\par + The Original Code is ______________________________________.\par +\par + The Initial Developer of the Original Code is ________________________.\par + Portions created by ______________________ are Copyright (C) ______\par + _______________________. All Rights Reserved.\par +\par + Contributor(s): ______________________________________.\par +\par + Alternatively, the contents of this file may be used under the terms\par + of the _____ license (the "[___] License"), in which case the\par + provisions of [______] License are applicable instead of those\par + above. If you wish to allow use of your version of this file only\par + under the terms of the [____] License and not to allow others to use\par + your version of this file under the MPL, indicate your decision by\par + deleting the provisions above and replace them with the notice and\par + other provisions required by the [___] License. If you do not delete\par + the provisions above, a recipient may use your version of this file\par + under either the MPL or the [___] License."\par +\par + [NOTE: The text of this Exhibit A may differ slightly from the text of\par + the notices in the Source Code files of the Original Code. You should\par + use the text of this Exhibit A rather than the text found in the\par + Original Code Source Code for Your Modifications.]\par +\par +-------------------------------------------------------\par +About The Cisco-Provided Binary of OpenH264 Video Codec\par +-------------------------------------------------------\par +\par +Cisco provides this program under the terms of the BSD license. \par +\par +Additionally, this binary is licensed under Cisco\rquote s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. \par +\par +As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. \par +\par +For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at {{\field{\*\fldinst{HYPERLINK http://www.openh264.org/faq.html#binary }}{\fldrslt{http://www.openh264.org/faq.html#binary\ul0\cf0}}}}\f0\fs20 \par +\par +A corresponding source code to this binary program is available under the same BSD terms, which can be found at {{\field{\*\fldinst{HYPERLINK http://www.openh264.org }}{\fldrslt{http://www.openh264.org\ul0\cf0}}}}\f0\fs20\par +\par +-----------\par +BSD License\par +-----------\par +\par +Copyright \f1\lang1033\'a9 2014 Cisco Systems, Inc.\par +\par +All rights reserved.\par +\par +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met:\par +\par +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer.\par +\par +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution.\par +\par +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS \ldblquote AS IS\rdblquote AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\par +\par +-----------------------------------------\par +AVC/H.264 Patent Portfolio License Notice\par +-----------------------------------------\par +\par +The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: \par +\par +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (\ldblquote AVC VIDEO\rdblquote ) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE {{\field{\*\fldinst{HYPERLINK HTTP://WWW.MPEGLA.COM }}{\fldrslt{HTTP://WWW.MPEGLA.COM\ul0\cf0}}}}\f1\fs20\par +\par +Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at {{\field{\*\fldinst{HYPERLINK http://www.openh264.org/mpegla }}{\fldrslt{http://www.openh264.org/mpegla\ul0\cf0}}}}\f1\fs20\par +\par +---------------------------------------------\par +AVC/H.264 Patent Portfolio License Conditions\par +---------------------------------------------\par +\par +In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met:\par +\par +1. The Cisco-provided binary is separately downloaded to an end user\rquote s device, and not integrated into or combined with third party software prior to being downloaded to the end user\rquote s device;\par +\par +2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary;\par +\par +3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text:\par +\par + "OpenH264 Video Codec provided by Cisco Systems, Inc."\par +\par +4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. \par + \par +\par +\par + v1.0\f0\lang1049\par +\par +\par +\par +} + \ No newline at end of file diff --git a/docs/OPENH264_BINARY_LICENSE.txt b/docs/OPENH264_BINARY_LICENSE.txt new file mode 100644 index 0000000000..e41a30ec88 --- /dev/null +++ b/docs/OPENH264_BINARY_LICENSE.txt @@ -0,0 +1,59 @@ +------------------------------------------------------- +About The Cisco-Provided Binary of OpenH264 Video Codec +------------------------------------------------------- + +Cisco provides this program under the terms of the BSD license. + +Additionally, this binary is licensed under Cisco’s AVC/H.264 Patent Portfolio License from MPEG LA, at no cost to you, provided that the requirements and conditions shown below in the AVC/H.264 Patent Portfolio sections are met. + +As with all AVC/H.264 codecs, you may also obtain your own patent license from MPEG LA or from the individual patent owners, or proceed at your own risk. Your rights from Cisco under the BSD license are not affected by this choice. + +For more information on the OpenH264 binary licensing, please see the OpenH264 FAQ found at http://www.openh264.org/faq.html#binary + +A corresponding source code to this binary program is available under the same BSD terms, which can be found at http://www.openh264.org + +----------- +BSD License +----------- + +Copyright © 2014 Cisco Systems, Inc. + +All rights reserved. + +Redistribution and use in source and binary forms, with or without modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following disclaimer. + +2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the following disclaimer in the documentation and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS “AS IS” AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +----------------------------------------- +AVC/H.264 Patent Portfolio License Notice +----------------------------------------- + +The binary form of this Software is distributed by Cisco under the AVC/H.264 Patent Portfolio License from MPEG LA, and is subject to the following requirements, which may or may not be applicable to your use of this software: + +THIS PRODUCT IS LICENSED UNDER THE AVC PATENT PORTFOLIO LICENSE FOR THE PERSONAL USE OF A CONSUMER OR OTHER USES IN WHICH IT DOES NOT RECEIVE REMUNERATION TO (i) ENCODE VIDEO IN COMPLIANCE WITH THE AVC STANDARD (“AVC VIDEO”) AND/OR (ii) DECODE AVC VIDEO THAT WAS ENCODED BY A CONSUMER ENGAGED IN A PERSONAL ACTIVITY AND/OR WAS OBTAINED FROM A VIDEO PROVIDER LICENSED TO PROVIDE AVC VIDEO. NO LICENSE IS GRANTED OR SHALL BE IMPLIED FOR ANY OTHER USE. ADDITIONAL INFORMATION MAY BE OBTAINED FROM MPEG LA, L.L.C. SEE HTTP://WWW.MPEGLA.COM + +Accordingly, please be advised that content providers and broadcasters using AVC/H.264 in their service may be required to obtain a separate use license from MPEG LA, referred to as "(b) sublicenses" in the SUMMARY OF AVC/H.264 LICENSE TERMS from MPEG LA found at http://www.openh264.org/mpegla + +--------------------------------------------- +AVC/H.264 Patent Portfolio License Conditions +--------------------------------------------- + +In addition, the Cisco-provided binary of this Software is licensed under Cisco's license from MPEG LA only if the following conditions are met: + +1. The Cisco-provided binary is separately downloaded to an end user’s device, and not integrated into or combined with third party software prior to being downloaded to the end user’s device; + +2. The end user must have the ability to control (e.g., to enable, disable, or re-enable) the use of the Cisco-provided binary; + +3. Third party software, in the location where end users can control the use of the Cisco-provided binary, must display the following text: + + "OpenH264 Video Codec provided by Cisco Systems, Inc." + +4. Any third-party software that makes use of the Cisco-provided binary must reproduce all of the above text, as well as this last condition, in the EULA and/or in another location where licensing information is to be presented to the end user. + + + + v1.0 \ No newline at end of file diff --git a/freeswitch-config-rayo.spec b/freeswitch-config-rayo.spec index cefc22312d..d022978834 100644 --- a/freeswitch-config-rayo.spec +++ b/freeswitch-config-rayo.spec @@ -28,7 +28,8 @@ # ###################################################################################################################### -%define version 1.7.0 +%define nonparsedversion 1.7.0 +%define version %(echo '%{nonparsedversion}' | sed 's/-//g') %define release 1 %define fsname freeswitch @@ -74,7 +75,7 @@ Summary: Rayo configuration for the FreeSWITCH Open Source telephone platform. Group: System/Libraries Packager: Chris Rienzo URL: http://www.freeswitch.org/ -Source0: freeswitch-%{version}.tar.bz2 +Source0: freeswitch-%{nonparsedversion}.tar.bz2 Requires: freeswitch Requires: freeswitch-application-conference Requires: freeswitch-application-esf @@ -103,7 +104,7 @@ BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root-%(%{__id_u} -n) FreeSWITCH rayo server implementation. %prep -%setup -b0 -q -n freeswitch-%{version} +%setup -b0 -q -n freeswitch-%{nonparsedversion} %build @@ -164,6 +165,8 @@ FreeSWITCH rayo server implementation. # ###################################################################################################################### %changelog +* Tue Apr 23 2019 - Andrey Volk +- Fix build for Stack 20.x * Tue Jun 10 2014 crienzo@grasshopper.com - Remove dependency to high resolution music and sounds files - Remove dependency to specific FreeSWITCH package version diff --git a/freeswitch-sounds-en-ca-june.spec b/freeswitch-sounds-en-ca-june.spec index 78cc361f34..880d1d0504 100644 --- a/freeswitch-sounds-en-ca-june.spec +++ b/freeswitch-sounds-en-ca-june.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-en-ca-june (version 1.0.50-1) +# Spec file for package freeswitch-sounds-en-ca-june (version 1.0.51-1) # # Based on parts by Copyright (c) 2009 Patrick Laimbock # Copyright (c) 2014 FreeSWITCH.org @@ -14,7 +14,7 @@ # Set variables ############################################################################## -%define version 1.0.50 +%define version 1.0.51 %define release 1 %define fsname freeswitch @@ -314,5 +314,7 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.51-1 +- version bump * Fri Sep 12 2014 Ken Rice - 1.0.50-1 - created out of the spec file for june diff --git a/freeswitch-sounds-en-us-allison.spec b/freeswitch-sounds-en-us-allison.spec index d92eb74f59..26d386461d 100644 --- a/freeswitch-sounds-en-us-allison.spec +++ b/freeswitch-sounds-en-us-allison.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-en-us-allison (version 1.0.0-1) +# Spec file for package freeswitch-sounds-en-us-allison (version 1.0.1-1) # # Copyright (c) 2009 Patrick Laimbock # Some fixes and additions (c) 2011 Michal Bielicki @@ -20,7 +20,7 @@ # Set variables ############################################################################## -%define version 1.0.0 +%define version 1.0.1 %define release 1 %define fsname freeswitch @@ -203,6 +203,7 @@ popd %files -n freeswitch-sounds-en-us-allison-8000 %defattr(-,root,root,-) +%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/alt/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ascii/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/base256/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/conference/8000 @@ -211,10 +212,10 @@ popd %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/directory/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ivr/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/misc/8000 -%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/phonetic-ascii/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/time/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/voicemail/8000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/zrtp/8000 +%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/alt/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ascii/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/base256/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/conference/8000/*.wav @@ -223,13 +224,13 @@ popd %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/directory/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ivr/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/misc/8000/*.wav -%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/phonetic-ascii/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/time/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/voicemail/8000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/zrtp/8000/*.wav %files -n freeswitch-sounds-en-us-allison-16000 %defattr(-,root,root,-) +%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/alt/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ascii/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/base256/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/conference/16000 @@ -238,10 +239,10 @@ popd %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/directory/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ivr/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/misc/16000 -%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/phonetic-ascii/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/time/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/voicemail/16000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/zrtp/16000 +%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/alt/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ascii/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/base256/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/conference/16000/*.wav @@ -250,13 +251,13 @@ popd %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/directory/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ivr/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/misc/16000/*.wav -%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/phonetic-ascii/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/time/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/voicemail/16000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/zrtp/16000/*.wav %files -n freeswitch-sounds-en-us-allison-32000 %defattr(-,root,root,-) +%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/alt/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ascii/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/base256/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/conference/32000 @@ -265,10 +266,10 @@ popd %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/directory/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ivr/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/misc/32000 -%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/phonetic-ascii/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/time/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/voicemail/32000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/zrtp/32000 +%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/alt/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ascii/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/base256/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/conference/32000/*.wav @@ -277,13 +278,13 @@ popd %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/directory/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ivr/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/misc/32000/*.wav -%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/phonetic-ascii/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/time/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/voicemail/32000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/zrtp/32000/*.wav %files -n freeswitch-sounds-en-us-allison-48000 %defattr(-,root,root,-) +%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/alt/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ascii/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/base256/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/conference/48000 @@ -292,10 +293,10 @@ popd %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/directory/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/ivr/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/misc/48000 -%attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/phonetic-ascii/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/time/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/voicemail/48000 %attr(0750,freeswitch,daemon) %dir %{SOUNDSDIR}/en/us/allison/zrtp/48000 +%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/alt/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ascii/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/base256/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/conference/48000/*.wav @@ -304,7 +305,6 @@ popd %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/directory/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/ivr/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/misc/48000/*.wav -%attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/phonetic-ascii/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/time/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/voicemail/48000/*.wav %attr(0640,freeswitch,daemon) %{SOUNDSDIR}/en/us/allison/zrtp/48000/*.wav @@ -316,6 +316,9 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.1-1 +- add missing alt folder and remove non-existing items +- bump up version * Tue Jul 25 2017 Mike Jerris - 1.0.0-1 - update to FHS Layout for FreeSWITCH - bump up version diff --git a/freeswitch-sounds-en-us-callie.spec b/freeswitch-sounds-en-us-callie.spec index 210e6f5df6..537e5668ef 100644 --- a/freeswitch-sounds-en-us-callie.spec +++ b/freeswitch-sounds-en-us-callie.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-en-us-callie (version 1.0.18-1) +# Spec file for package freeswitch-sounds-en-us-callie (version 1.0.52-1) # # Copyright (c) 2009 Patrick Laimbock # Some fixes and additions (c) 2011 Michal Bielicki @@ -20,7 +20,7 @@ # Set variables ############################################################################## -%define version 1.0.50 +%define version 1.0.52 %define release 1 %define fsname freeswitch @@ -316,6 +316,8 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.52-1 +- bump up version * Sun Mar 05 2012 Ken Rice - 1.0.18-1 - update to FHS Layout for FreeSWITCH - bump up version diff --git a/freeswitch-sounds-fr-ca-june.spec b/freeswitch-sounds-fr-ca-june.spec index d926e84ba1..c8d413d4ab 100644 --- a/freeswitch-sounds-fr-ca-june.spec +++ b/freeswitch-sounds-fr-ca-june.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-fr-ca-june (version 1.0.50-1) +# Spec file for package freeswitch-sounds-fr-ca-june (version 1.0.51-1) # # Based on parts by Copyright (c) 2009 Patrick Laimbock # Copyright (c) 2014 FreeSWITCH.org @@ -14,7 +14,7 @@ # Set variables ############################################################################## -%define version 1.0.50 +%define version 1.0.51 %define release 1 %define fsname freeswitch @@ -322,5 +322,7 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.51-1 +- bump up version * Fri Sep 12 2014 Ken Rice - 1.0.50-1 - created out of the spec file for june diff --git a/freeswitch-sounds-music.spec b/freeswitch-sounds-music.spec index 592e8def0c..a885d2e7e1 100644 --- a/freeswitch-sounds-music.spec +++ b/freeswitch-sounds-music.spec @@ -35,8 +35,8 @@ Summary: FreeSWITCH Music on Hold soundfiles Name: freeswitch-sounds-music -Version: 1.0.50 -Release: 2%{?dist} +Version: 1.0.52 +Release: 1%{?dist} License: MPL Group: Productivity/Telephony/Servers Packager: Joseph L. Casale @@ -153,6 +153,8 @@ FreeSWITCH 48kHz Music On Hold soundfiles %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.52-1 +- bump up version * Sat Jul 16 2011 Joseph Casale 1.0.8-2 - Fix up for FreeSWITCH FHS and AutoBuild System * Sat Jul 16 2011 Joseph Casale 1.0.8-1 diff --git a/freeswitch-sounds-pt-BR-karina.spec b/freeswitch-sounds-pt-BR-karina.spec index 1260d6a65f..c0a9a6ffe0 100644 --- a/freeswitch-sounds-pt-BR-karina.spec +++ b/freeswitch-sounds-pt-BR-karina.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-pt-BR-karina (version 1.0.50-1) +# Spec file for package freeswitch-sounds-pt-BR-karina (version 1.0.51-1) # # Based on parts by Copyright (c) 2009 Patrick Laimbock # Copyright (c) 2014 FreeSWITCH.org @@ -14,7 +14,7 @@ # Set variables ############################################################################## -%define version 1.0.50 +%define version 1.0.51 %define release 1 %define fsname freeswitch @@ -314,5 +314,7 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.51-1 +- bump up version * Fri Sep 12 2014 Ken Rice - 1.0.50-1 - created out of the spec file for june diff --git a/freeswitch-sounds-ru-RU-elena.spec b/freeswitch-sounds-ru-RU-elena.spec index f7192b33ce..28f5f5bafe 100644 --- a/freeswitch-sounds-ru-RU-elena.spec +++ b/freeswitch-sounds-ru-RU-elena.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-ru-RU-elena (version 1.0.13-1) +# Spec file for package freeswitch-sounds-ru-RU-elena (version 1.0.51-1) # # Based on parts by Copyright (c) 2009 Patrick Laimbock # Copyright (c) 2011 Michal Bielicki @@ -20,7 +20,7 @@ # Set variables ############################################################################## -%define version 1.0.50 +%define version 1.0.51 %define release 1 %define fsname freeswitch @@ -320,6 +320,8 @@ popd ############################################################################## %changelog +* Fri Apr 19 2019 Andrey Volk - 1.0.51-1 +- bump up version * Fri Sep 12 2014 Ken Rice - 1.0.50-1 - created out of the spec file for elena * Mon Mar 06 2012 Ken Rice - 1.0.13-2 diff --git a/freeswitch-sounds-sv-se-jakob.spec b/freeswitch-sounds-sv-se-jakob.spec index 8300cc8515..5ddf6218c8 100644 --- a/freeswitch-sounds-sv-se-jakob.spec +++ b/freeswitch-sounds-sv-se-jakob.spec @@ -2,7 +2,7 @@ # Copyright and license ############################################################################## # -# Spec file for package freeswitch-sounds-sv-se-jakob (version 1.0.18-1) +# Spec file for package freeswitch-sounds-sv-se-jakob (version 1.0.50-1) # # Copyright (c) 2009 Patrick Laimbock # Copied and modified for mod_say_sv (c) 2013 Jakob Sundberg diff --git a/freeswitch.spec b/freeswitch.spec index f0fee3ca72..4a96e41dc9 100644 --- a/freeswitch.spec +++ b/freeswitch.spec @@ -37,7 +37,9 @@ %define build_mod_esl 0 %define build_mod_rayo 1 %define build_mod_ssml 1 -%define build_mod_shout 0 +%define build_mod_shout 1 +%define build_mod_opusfile 0 +%define build_mod_v8 0 %{?with_sang_tc:%define build_sng_tc 1 } %{?with_sang_isdn:%define build_sng_isdn 1 } @@ -46,8 +48,11 @@ %{?with_timerfd:%define build_timerfd 1 } %{?with_mod_esl:%define build_mod_esl 1 } %{?with_mod_shout:%define build_mod_shout 1 } +%{?with_mod_opusfile:%define build_mod_opusfile 1 } +%{?with_mod_v8:%define build_mod_v8 1 } -%define version 1.7.0 +%define nonparsedversion 1.7.0 +%define version %(echo '%{nonparsedversion}' | sed 's/-//g') %define release 1 ###################################################################################################################### @@ -116,7 +121,7 @@ Vendor: http://www.freeswitch.org/ # Source files and where to get them # ###################################################################################################################### -Source0: http://files.freeswitch.org/%{name}-%{version}.tar.bz2 +Source0: http://files.freeswitch.org/%{name}-%{nonparsedversion}.tar.bz2 Source1: http://files.freeswitch.org/downloads/libs/v8-3.24.14.tar.bz2 Source2: http://files.freeswitch.org/downloads/libs/mongo-c-driver-1.1.0.tar.gz Source3: http://files.freeswitch.org/downloads/libs/pocketsphinx-0.8.tar.gz @@ -189,7 +194,7 @@ BuildRequires: broadvoice-devel BuildRequires: flite-devel BuildRequires: ilbc2-devel BuildRequires: g722_1-devel -BuildRequires: libcodec2-devel +BuildRequires: codec2-devel BuildRequires: libsilk-devel BuildRequires: libyuv-devel >= 0.0.1280 BuildRequires: lua-devel @@ -540,6 +545,7 @@ the entries aloud via a TTS engine Summary: FreeSWITCH mod_signalwire Group: System/Libraries Requires: %{name} = %{version}-%{release} +BuildRequires: libks signalwire-client-c %description application-signalwire Provides FreeSWITCH mod_signalwire @@ -1145,10 +1151,10 @@ a soundcard, etc. Summary: Implements Media Steaming from arbitrary shell commands for the FreeSWITCH open source telephony platform Group: System/Libraries Requires: %{name} = %{version}-%{release} -Requires: libshout >= 2.3.1 +Requires: libshout >= 2.2.2 Requires: libmpg123 >= 1.20.1 Requires: lame -BuildRequires: libshout-devel >= 2.3.1 +BuildRequires: libshout-devel >= 2.2.2 BuildRequires: libmpg123-devel >= 1.20.1 BuildRequires: lame-devel @@ -1157,6 +1163,18 @@ Mod Shout is a FreeSWITCH module to allow you to stream audio from MP3s or a i shoutcast stream. %endif +%if %{build_mod_opusfile} +%package format-mod-opusfile +Summary: Plays Opus encoded files +Group: System/Libraries +Requires: %{name} = %{version}-%{release} +Requires: opusfile >= 0.5 +BuildRequires: opusfile-devel >= 0.5 + +%description format-mod-opusfile +Mod Opusfile is a FreeSWITCH module to allow you to play Opus encoded files +%endif + %if %{build_mod_ssml} %package format-ssml Summary: Adds Speech Synthesis Markup Language (SSML) parser format for the FreeSWITCH open source telephony platform @@ -1202,12 +1220,14 @@ Requires: python %description python +%if %{build_mod_v8} %package v8 Summary: JavaScript support for the FreeSWITCH open source telephony platform, using Google V8 JavaScript engine Group: System/Libraries Requires: %{name} = %{version}-%{release} %description v8 +%endif ###################################################################################################################### # FreeSWITCH Say Modules @@ -1415,7 +1435,7 @@ Basic vanilla config set for the FreeSWITCH Open Source telephone platform. ###################################################################################################################### %prep -%setup -b0 -q +%setup -b0 -q -n %{name}-%{nonparsedversion} cp %{SOURCE1} libs/ cp %{SOURCE2} libs/ cp %{SOURCE3} libs/ @@ -1546,6 +1566,9 @@ FORMATS_MODULES+=" formats/mod_shout " %if %{build_mod_ssml} FORMATS_MODULES+=" formats/mod_ssml" %endif +%if %{build_mod_opusfile} +FORMATS_MODULES+=" formats/mod_opusfile" +%endif ###################################################################################################################### # @@ -1553,7 +1576,9 @@ FORMATS_MODULES+=" formats/mod_ssml" # ###################################################################################################################### LANGUAGES_MODULES="languages/mod_lua languages/mod_perl languages/mod_python " -#LANGUAGES_MODULES+="languages/mod_v8" +%if %{build_mod_v8} +LANGUAGES_MODULES+="languages/mod_v8" +%endif ###################################################################################################################### # @@ -1623,6 +1648,8 @@ else ./rebootstrap.sh fi +autoreconf --force --install + %configure -C \ --prefix=%{PREFIX} \ --exec-prefix=%{EXECPREFIX} \ @@ -1911,6 +1938,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/amrwb.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/alsa.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/amqp.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/av.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/avmd.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/blacklist.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/callcenter.conf.xml @@ -1923,6 +1951,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/conference.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/conference_layouts.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/console.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/curl.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/db.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/dialplan_directory.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/dingaling.conf.xml @@ -1979,6 +2008,7 @@ fi %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/verto.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/voicemail.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/voicemail_ivr.conf.xml +%config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/vpx.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/xml_cdr.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/xml_curl.conf.xml %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/xml_rpc.conf.xml @@ -2397,12 +2427,14 @@ fi %dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/python.conf.xml +%if %{build_mod_v8} %files v8 -#%{MODINSTDIR}/mod_v8*.so* -#%{LIBDIR}/libv8.so -#%{LIBDIR}/libicui18n.so -#%{LIBDIR}/libicuuc.so -#%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs +%{MODINSTDIR}/mod_v8*.so* +%{LIBDIR}/libv8.so +%{LIBDIR}/libicui18n.so +%{LIBDIR}/libicuuc.so +%endif +%dir %attr(0750, freeswitch, daemon) %{sysconfdir}/autoload_configs %config(noreplace) %attr(0640, freeswitch, daemon) %{sysconfdir}/autoload_configs/v8.conf.xml ###################################################################################################################### @@ -2553,6 +2585,8 @@ fi # ###################################################################################################################### %changelog +* Tue Apr 23 2019 - Andrey Volk +- Fix build for Stack 20.x * Tue Dec 11 2018 - Andrey Volk - add mod_signalwire * Sun Mar 13 2016 - Matthew Vale diff --git a/html5/verto/demo/js/verto-min.js b/html5/verto/demo/js/verto-min.js index 2ac8e89e7e..7a6a42b8a0 100644 --- a/html5/verto/demo/js/verto-min.js +++ b/html5/verto/demo/js/verto-min.js @@ -1,9508 +1,725 @@ -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.FSRTC.js - WebRTC Glue code - * - */ -(function($) { - - // Find the line in sdpLines that starts with |prefix|, and, if specified, - // contains |substr| (case-insensitive search). - function findLine(sdpLines, prefix, substr) { - return findLineInRange(sdpLines, 0, -1, prefix, substr); - } - - // Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| - // and, if specified, contains |substr| (case-insensitive search). - function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { - var realEndLine = (endLine != -1) ? endLine : sdpLines.length; - for (var i = startLine; i < realEndLine; ++i) { - if (sdpLines[i].indexOf(prefix) === 0) { - if (!substr || sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { - return i; - } - } - } - return null; - } - - // Gets the codec payload type from an a=rtpmap:X line. - function getCodecPayloadType(sdpLine) { - var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); - var result = sdpLine.match(pattern); - return (result && result.length == 2) ? result[1] : null; - } - - // Returns a new m= line with the specified codec as the first one. - function setDefaultCodec(mLine, payload) { - var elements = mLine.split(' '); - var newLine = []; - var index = 0; - for (var i = 0; i < elements.length; i++) { - if (index === 3) { // Format of media starts from the fourth. - newLine[index++] = payload; // Put target payload to the first. - } - if (elements[i] !== payload) newLine[index++] = elements[i]; - } - return newLine.join(' '); - } - - $.FSRTC = function(options) { - this.options = $.extend({ - useVideo: null, - useStereo: false, - userData: null, - localVideo: null, - screenShare: false, - useCamera: "any", - iceServers: false, - videoParams: {}, - audioParams: {}, - callbacks: { - onICEComplete: function() {}, - onICE: function() {}, - onOfferSDP: function() {} - }, - useStream: null, - }, options); - - this.audioEnabled = true; - this.videoEnabled = true; - - - this.mediaData = { - SDP: null, - profile: {}, - candidateList: [] - }; - - this.constraints = { - offerToReceiveAudio: this.options.useSpeak === "none" ? false : true, - offerToReceiveVideo: this.options.useVideo ? true : false, - }; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - - setCompat(); - checkCompat(); - }; - - $.FSRTC.validRes = []; - - $.FSRTC.prototype.useVideo = function(obj, local) { - var self = this; - - if (obj) { - self.options.useVideo = obj; - self.options.localVideo = local; - self.constraints.offerToReceiveVideo = true; - } else { - self.options.useVideo = null; - self.options.localVideo = null; - self.constraints.offerToReceiveVideo = false; - } - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - }; - - $.FSRTC.prototype.useStereo = function(on) { - var self = this; - self.options.useStereo = on; - }; - - // Sets Opus in stereo if stereo is enabled, by adding the stereo=1 fmtp param. - $.FSRTC.prototype.stereoHack = function(sdp) { - var self = this; - - if (!self.options.useStereo) { - return sdp; - } - - var sdpLines = sdp.split('\r\n'); - - // Find opus payload. - var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'), opusPayload; - - if (!opusIndex) { - return sdp; - } else { - opusPayload = getCodecPayloadType(sdpLines[opusIndex]); - } - - // Find the payload in fmtp line. - var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString()); - - if (fmtpLineIndex === null) { - // create an fmtp line - sdpLines[opusIndex] = sdpLines[opusIndex] + '\r\na=fmtp:' + opusPayload.toString() + " stereo=1; sprop-stereo=1" - } else { - // Append stereo=1 to fmtp line. - sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1; sprop-stereo=1'); - } - - sdp = sdpLines.join('\r\n'); - return sdp; - }; - - function setCompat() { - } - - function checkCompat() { - return true; - } - - function onStreamError(self, e) { - console.log('There has been a problem retrieving the streams - did you allow access? Check Device Resolution', e); - doCallback(self, "onError", e); - } - - function onStreamSuccess(self, stream) { - console.log("Stream Success"); - doCallback(self, "onStream", stream); - } - - function onRemoteStreamSuccess(self, stream) { - console.log("Remote Stream Success"); - doCallback(self, "onRemoteStream", stream); - } - - function onICE(self, candidate) { - self.mediaData.candidate = candidate; - self.mediaData.candidateList.push(self.mediaData.candidate); - - doCallback(self, "onICE"); - } - - function doCallback(self, func, arg) { - if (func in self.options.callbacks) { - self.options.callbacks[func](self, arg); - } - } - - function onICEComplete(self, candidate) { - console.log("ICE Complete"); - doCallback(self, "onICEComplete"); - } - - function onChannelError(self, e) { - console.error("Channel Error", e); - doCallback(self, "onError", e); - } - - function onICESDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("ICE SDP"); - doCallback(self, "onICESDP"); - } - - function onAnswerSDP(self, sdp) { - self.answer.SDP = self.stereoHack(sdp.sdp); - console.log("ICE ANSWER SDP"); - doCallback(self, "onAnswerSDP", self.answer.SDP); - } - - function onMessage(self, msg) { - console.log("Message"); - doCallback(self, "onICESDP", msg); - } - - FSRTCattachMediaStream = function(element, stream) { - if (typeof element.srcObject !== 'undefined') { - element.srcObject = stream; - } else { - console.error('Error attaching stream to element.'); - } - } - - function onRemoteStream(self, stream) { - if (self.options.useVideo) { - self.options.useVideo.style.display = 'block'; - - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - - if (iOS) { - self.options.useVideo.setAttribute("playsinline", true); - } - } - - var element = self.options.useAudio; - console.log("REMOTE STREAM", stream, element); - - FSRTCattachMediaStream(element, stream); - - - - //self.options.useAudio.play(); - self.remoteStream = stream; - onRemoteStreamSuccess(self, stream); - } - - function onOfferSDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("Offer SDP"); - doCallback(self, "onOfferSDP"); - } - - $.FSRTC.prototype.answer = function(sdp, onSuccess, onError) { - this.peer.addAnswerSDP({ - type: "answer", - sdp: sdp - }, - onSuccess, onError); - }; - - $.FSRTC.prototype.stopPeer = function() { - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - } - - $.FSRTC.prototype.stop = function() { - var self = this; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - self.options.useVideo['src'] = ''; - } - - if (self.localStream && !self.options.useStream) { - if(typeof self.localStream.stop == 'function') { - self.localStream.stop(); - } else { - if (self.localStream.active){ - var tracks = self.localStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - self.localStream = null; - } - - if (self.options.localVideo) { - deactivateLocalVideo(self.options.localVideo); - } - - if (self.options.localVideoStream && !self.options.useStream) { - if(typeof self.options.localVideoStream.stop == 'function') { - self.options.localVideoStream.stop(); - } else { - if (self.options.localVideoStream.active){ - var tracks = self.options.localVideoStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - } - - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - }; - - $.FSRTC.prototype.getMute = function() { - var self = this; - return self.audioEnabled; - } - - $.FSRTC.prototype.setMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var audioTracks = self.localStream.getAudioTracks(); - - for (var i = 0, len = audioTracks.length; i < len; i++ ) { - switch(what) { - case "on": - audioTracks[i].enabled = true; - break; - case "off": - audioTracks[i].enabled = false; - break; - case "toggle": - audioTracks[i].enabled = !audioTracks[i].enabled; - default: - break; - } - - self.audioEnabled = audioTracks[i].enabled; - } - - return !self.audioEnabled; - } - - $.FSRTC.prototype.getVideoMute = function() { - var self = this; - return self.videoEnabled; - } - - $.FSRTC.prototype.setVideoMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var videoTracks = self.localStream.getVideoTracks(); - - for (var i = 0, len = videoTracks.length; i < len; i++ ) { - switch(what) { - case "on": - videoTracks[i].enabled = true; - break; - case "off": - videoTracks[i].enabled = false; - break; - case "toggle": - videoTracks[i].enabled = !videoTracks[i].enabled; - default: - break; - } - - self.videoEnabled = videoTracks[i].enabled; - } - - return !self.videoEnabled; - } - - $.FSRTC.prototype.createAnswer = function(params) { - var self = this; - self.type = "answer"; - self.remoteSDP = params.sdp; - console.debug("inbound sdp: ", params.sdp); - - function onSuccess(stream) { - self.localStream = stream; - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: function(stream) { - return onRemoteStream(self, stream); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - offerSDP: { - type: "offer", - sdp: self.remoteSDP - }, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useVideo && self.options.localVideo && !self.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: params.useCamera }, - }, - localVideo: self.options.localVideo, - onsuccess: function(e) {self.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else { - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - } - - }; - - function getMediaParams(obj) { - - var audio; - - if (obj.options.useMic && obj.options.useMic === "none") { - console.log("Microphone Disabled"); - audio = false; - } else if (obj.options.videoParams && obj.options.screenShare) {//obj.options.videoParams.chromeMediaSource == 'desktop') { - console.error("SCREEN SHARE", obj.options.videoParams); - audio = false; - } else { - audio = { - }; - - if (obj.options.audioParams) { - audio = obj.options.audioParams; - } - - if (obj.options.useMic !== "any") { - //audio.optional = [{sourceId: obj.options.useMic}]; - audio.deviceId = {exact: obj.options.useMic}; - } - } - - if (obj.options.useVideo && obj.options.localVideo && !obj.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: obj.options.useCamera }, - }, - localVideo: obj.options.localVideo, - onsuccess: function(e) {obj.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - var video = {}; - var bestFrameRate = obj.options.videoParams.vertoBestFrameRate; - var minFrameRate = obj.options.videoParams.minFrameRate || 15; - delete obj.options.videoParams.vertoBestFrameRate; - - if (obj.options.screenShare) { - if (!obj.options.useCamera && !!navigator.mozGetUserMedia) { - //This is an issue, only FireFox needs to ask this additional question if its screen or window we need a better way - var dowin = window.confirm("Do you want to share an application window? If not you can share an entire screen."); - - video = { - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight}, - mediaSource: dowin ? "window" : "screen" - } - } else { - var opt = []; - if (obj.options.useCamera) { - opt.push({sourceId: obj.options.useCamera}); - } - - if (bestFrameRate) { - opt.push({minFrameRate: bestFrameRate}); - opt.push({maxFrameRate: bestFrameRate}); - } - - video = { - mandatory: obj.options.videoParams, - optional: opt - }; - // NOTE: This is a workaround for - // https://bugs.chromium.org/p/chromium/issues/detail?id=862325 - if (!!navigator.userAgent.match(/Android/i)) { - delete video.frameRate.min; - } - } - } else { - - video = { - //mandatory: obj.options.videoParams, - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight} - }; - - - - var useVideo = obj.options.useVideo; - - if (useVideo && obj.options.useCamera && obj.options.useCamera !== "none") { - //if (!video.optional) { - //video.optional = []; - //} - - - if (obj.options.useCamera !== "any") { - //video.optional.push({sourceId: obj.options.useCamera}); - video.deviceId = { - exact: obj.options.useCamera, - }; - } - - if (bestFrameRate) { - //video.optional.push({minFrameRate: bestFrameRate}); - //video.optional.push({maxFrameRate: bestFrameRate}); - video.frameRate = {ideal: bestFrameRate, min: minFrameRate, max: 30}; - } - - } else { - console.log("Camera Disabled"); - video = false; - useVideo = false; - } - } - - return {audio: audio, video: video, useVideo: useVideo}; - } - - $.FSRTC.prototype.call = function(profile) { - checkCompat(); - - var self = this; - var screen = false; - - self.type = "offer"; - - if (self.options.videoParams && self.options.screenShare) { //self.options.videoParams.chromeMediaSource == 'desktop') { - screen = true; - } - - function onSuccess(stream) { - self.localStream = stream; - - if (screen) { - self.constraints.offerToReceiveVideo = false; - self.constraints.offerToReceiveAudio = false; - self.constraints.offerToSendAudio = false; - } - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: screen ? function(stream) {} : function(stream) { - return onRemoteStream(self, stream); - }, - onOfferSDP: function(sdp) { - return onOfferSDP(self, sdp); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else if (mediaParams.audio || mediaParams.video) { - - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - - } else { - onSuccess(null); - } - - - - /* - navigator.getUserMedia({ - video: self.options.useVideo, - audio: true - }, onSuccess, onError); - */ - - }; - - // DERIVED from RTCPeerConnection-v1.5 - // 2013, @muazkh - github.com/muaz-khan - // MIT License - https://www.webrtc-experiment.com/licence/ - // Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection - - function FSRTCPeerConnection(options) { - var gathering = false, done = false; - var config = {}; - var default_ice = [{ urls: ['stun:stun.l.google.com:19302'] }]; - - if (self.options.turnServer) { - default_ice.push(self.options.turnServer) - } - - if (options.iceServers) { - if (typeof(options.iceServers) === "boolean") { - config.iceServers = default_ice; - } else { - config.iceServers = options.iceServers; - } - } - - config.bundlePolicy = "max-compat"; - - var peer = new window.RTCPeerConnection(config); - - openOffererChannel(); - var x = 0; - - function ice_handler() { - - done = true; - gathering = null; - - if (options.onICEComplete) { - options.onICEComplete(); - } - - if (options.type == "offer") { - options.onICESDP(peer.localDescription); - } else { - if (!x && options.onICESDP) { - options.onICESDP(peer.localDescription); - } - } - } - - peer.onicecandidate = function(event) { - - if (done) { - return; - } - - if (!gathering) { - gathering = setTimeout(ice_handler, 1000); - } - - if (event) { - if (event.candidate) { - options.onICE(event.candidate); - } - } else { - done = true; - - if (gathering) { - clearTimeout(gathering); - gathering = null; - } - - ice_handler(); - } - }; - - // attachStream = MediaStream; - if (options.attachStream) peer.addStream(options.attachStream); - - // attachStreams[0] = audio-stream; - // attachStreams[1] = video-stream; - // attachStreams[2] = screen-capturing-stream; - if (options.attachStreams && options.attachStream.length) { - var streams = options.attachStreams; - for (var i = 0; i < streams.length; i++) { - peer.addStream(streams[i]); - } - } - - peer.onaddstream = function(event) { - var remoteMediaStream = event.stream; - - // onRemoteStreamEnded(MediaStream) - remoteMediaStream.oninactive = function () { - if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream); - }; - - // onRemoteStream(MediaStream) - if (options.onRemoteStream) options.onRemoteStream(remoteMediaStream); - - //console.debug('on:add:stream', remoteMediaStream); - }; - - //var constraints = options.constraints || { - // offerToReceiveAudio: true, - //offerToReceiveVideo: true - //}; - - // onOfferSDP(RTCSessionDescription) - function createOffer() { - if (!options.onOfferSDP) return; - - peer.createOffer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - options.onOfferSDP(sessionDescription); - }, - onSdpError, options.constraints); - } - - // onAnswerSDP(RTCSessionDescription) - function createAnswer() { - if (options.type != "answer") return; - - //options.offerSDP.sdp = addStereo(options.offerSDP.sdp); - peer.setRemoteDescription(new window.RTCSessionDescription(options.offerSDP), onSdpSuccess, onSdpError); - peer.createAnswer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onAnswerSDP) { - options.onAnswerSDP(sessionDescription); - } - }, - onSdpError); - } - - - if ((options.onChannelMessage) || !options.onChannelMessage) { - createOffer(); - createAnswer(); - } - - // DataChannel Bandwidth - function setBandwidth(sdp) { - // remove existing bandwidth lines - sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); - sdp = sdp.replace(/a=mid:data\r\n/g, 'a=mid:data\r\nb=AS:1638400\r\n'); - - return sdp; - } - - // old: FF<>Chrome interoperability management - function getInteropSDP(sdp) { - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), - extractedChars = ''; - - function getChars() { - extractedChars += chars[parseInt(Math.random() * 40)] || ''; - if (extractedChars.length < 40) getChars(); - - return extractedChars; - } - - // usually audio-only streaming failure occurs out of audio-specific crypto line - // a=crypto:1 AES_CM_128_HMAC_SHA1_32 --------- kAttributeCryptoVoice - if (options.onAnswerSDP) sdp = sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g, ''); - - // video-specific crypto line i.e. SHA1_80 - // a=crypto:1 AES_CM_128_HMAC_SHA1_80 --------- kAttributeCryptoVideo - var inline = getChars() + '\r\n' + (extractedChars = ''); - sdp = sdp.indexOf('a=crypto') == -1 ? sdp.replace(/c=IN/g, 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:' + inline + 'c=IN') : sdp; - - return sdp; - } - - function serializeSdp(sdp) { - return sdp; - } - - // DataChannel management - var channel; - - function openOffererChannel() { - if (!options.onChannelMessage) return; - - _openOffererChannel(); - - return; - } - - function _openOffererChannel() { - channel = peer.createDataChannel(options.channel || 'RTCDataChannel', { - reliable: false - }); - - setChannelEvents(); - } - - function setChannelEvents() { - channel.onmessage = function(event) { - if (options.onChannelMessage) options.onChannelMessage(event); - }; - - channel.onopen = function() { - if (options.onChannelOpened) options.onChannelOpened(channel); - }; - channel.onclose = function(event) { - if (options.onChannelClosed) options.onChannelClosed(event); - - console.warn('WebRTC DataChannel closed', event); - }; - channel.onerror = function(event) { - if (options.onChannelError) options.onChannelError(event); - - console.error('WebRTC DataChannel error', event); - }; - } - - function openAnswererChannel() { - peer.ondatachannel = function(event) { - channel = event.channel; - channel.binaryType = 'blob'; - setChannelEvents(); - }; - - return; - } - - // fake:true is also available on chrome under a flag! - function useless() { - log('Error in fake:true'); - } - - function onSdpSuccess() {} - - function onSdpError(e) { - if (options.onChannelError) { - options.onChannelError(e); - } - console.error('sdp error:', e); - } - - return { - addAnswerSDP: function(sdp, cbSuccess, cbError) { - - peer.setRemoteDescription(new window.RTCSessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError); - }, - addICE: function(candidate) { - peer.addIceCandidate(new window.RTCIceCandidate({ - sdpMLineIndex: candidate.sdpMLineIndex, - candidate: candidate.candidate - })); - }, - - peer: peer, - channel: channel, - sendData: function(message) { - if (channel) { - channel.send(message); - } - }, - - stop: function() { - peer.close(); - if (options.attachStream) { - if(typeof options.attachStream.stop == 'function') { - options.attachStream.stop(); - } else { - options.attachStream.active = false; - } - } - } - - }; - } - - // getUserMedia - var video_constraints = { - //mandatory: {}, - //optional: [] - }; - - function activateLocalVideo(el, stream) { - el.srcObject = stream; - el.style.display = 'block'; - } - - function deactivateLocalVideo(el) { - el.srcObject = null; - el.style.display = 'none'; - } - - function getUserMedia(options) { - var n = navigator, - media; - n.getMedia = n.getUserMedia; - n.getMedia(options.constraints || { - audio: true, - video: video_constraints - }, - streaming, options.onerror || - function(e) { - console.error(e); - }); - - function streaming(stream) { - if (options.localVideo) { - activateLocalVideo(options.localVideo, stream); - } - - if (options.onsuccess) { - options.onsuccess(stream); - } - - media = stream; - } - - return media; - } - - $.FSRTC.resSupported = function(w, h) { - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] == w && $.FSRTC.validRes[i][1] == h) { - return true; - } - } - - return false; - } - - $.FSRTC.bestResSupported = function() { - var w = 0, h = 0; - - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] >= w && $.FSRTC.validRes[i][1] >= h) { - w = $.FSRTC.validRes[i][0]; - h = $.FSRTC.validRes[i][1]; - } - } - - return [w, h]; - } - - var resList = [[160, 120], [320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; - var resI = 0; - var ttl = 0; - - var checkRes = function (cam, func) { - - if (resI >= resList.length) { - var res = { - 'validRes': $.FSRTC.validRes, - 'bestResSupported': $.FSRTC.bestResSupported() - }; - - localStorage.setItem("res_" + cam, $.toJSON(res)); - - if (func) return func(res); - return; - } - - w = resList[resI][0]; - h = resList[resI][1]; - resI++; - - var video = { - width: {exact: w}, - height: {exact: h} - }; - - if (cam !== "any") { - video.deviceId = { - exact: cam, - }; - } - - getUserMedia({ - constraints: { - audio: ttl++ == 0, - video: video - }, - onsuccess: function(e) { - e.getTracks().forEach(function(track) {track.stop();}); - console.info(w + "x" + h + " supported."); $.FSRTC.validRes.push([w, h]); checkRes(cam, func);}, - onerror: function(e) {console.warn( w + "x" + h + " not supported."); checkRes(cam, func);} - }); - } - - - $.FSRTC.getValidRes = function (cam, func) { - var used = []; - var cached = localStorage.getItem("res_" + cam); - - if (cached) { - var cache = $.parseJSON(cached); - - if (cache) { - $.FSRTC.validRes = cache.validRes; - console.log("CACHED RES FOR CAM " + cam, cache); - } else { - console.error("INVALID CACHE"); - } - return func ? func(cache) : null; - } - - - $.FSRTC.validRes = []; - resI = 0; - - checkRes(cam, func); - } - - $.FSRTC.checkPerms = function (runtime, check_audio, check_video) { - getUserMedia({ - constraints: { - audio: check_audio, - video: check_video, - }, - onsuccess: function(e) { - - e.getTracks().forEach(function(track) {track.stop();}); - - console.info("media perm init complete"); - if (runtime) { - setTimeout(runtime, 100, true); - } - }, - onerror: function(e) { - if (check_video && check_audio) { - console.error("error, retesting with audio params only"); - return $.FSRTC.checkPerms(runtime, check_audio, false); - } - - console.error("media perm init error"); - - if (runtime) { - runtime(false) - } - } - }); - } - -})(jQuery); -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Textalk AB http://textalk.se/ - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.jsonrpclient.js - JSON RPC client code - * - */ -/** - * This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and - * $.parseJSON. - * - * The plan is to make use of websockets if they are available, but work just as well with only - * http if not. - * - * Usage example: - * - * var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' }); - * foo.call( - * 'bar', [ 'A parameter', 'B parameter' ], - * function(result) { alert('Foo bar answered: ' + result.my_answer); }, - * function(error) { console.log('There was an error', error); } - * ); - * - * More examples are available in README.md - */ -(function($) { - /** - * @fn new - * @memberof $.JsonRpcClient - * - * @param options An object stating the backends: - * ajaxUrl A url (relative or absolute) to a http(s) backend. - * socketUrl A url (relative of absolute) to a ws(s) backend. - * onmessage A socket message handler for other messages (non-responses). - * getSocket A function returning a WebSocket or null. - * It must take an onmessage_cb and bind it to the onmessage event - * (or chain it before/after some other onmessage handler). - * Or, it could return null if no socket is available. - * The returned instance must have readyState <= 1, and if less than 1, - * react to onopen binding. - */ - $.JsonRpcClient = function(options) { - var self = this; - this.options = $.extend({ - ajaxUrl : null, - socketUrl : null, ///< The ws-url for default getSocket. - onmessage : null, ///< Other onmessage-handler. - login : null, /// auth login - passwd : null, /// auth passwd - sessid : null, - loginParams : null, - userVariables : null, - getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } - }, options); - - self.ws_cnt = 0; - - // Declare an instance version of the onmessage callback to wrap 'this'. - this.wsOnMessage = function(event) { self._wsOnMessage(event); }; - }; - - /// Holding the WebSocket on default getsocket. - $.JsonRpcClient.prototype._ws_socket = null; - - /// Object : { success_cb: cb, error_cb: cb } - $.JsonRpcClient.prototype._ws_callbacks = {}; - - /// The next JSON-RPC request id. - $.JsonRpcClient.prototype._current_id = 1; - - - $.JsonRpcClient.prototype.speedTest = function (bytes, cb) { - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this.speedCB = cb; - this.speedBytes = bytes; - socket.send("#SPU " + bytes); - - var loops = bytes / 1024; - var rem = bytes % 1024; - var i; - var data = new Array(1024).join("."); - for (i = 0; i < loops; i++) { - socket.send("#SPB " + data); - } - - if (rem) { - socket.send("#SPB " + data); - } - - socket.send("#SPE"); - } - }; - - - - /** - * @fn call - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - * @param success_cb A callback for successful request. - * @param error_cb A callback for error. - */ - $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { - // Construct the JSON-RPC 2.0 request. - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc : '2.0', - method : method, - params : params, - id : this._current_id++ // Increase the id counter to match request/response - }; - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request, success_cb, error_cb); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false, - - success : function(data) { - if ('error' in data) error_cb(data.error, this); - success_cb(data.result, this); - }, - - // JSON-RPC Server could return non-200 on error - error : function(jqXHR, textStatus, errorThrown) { - try { - var response = $.parseJSON(jqXHR.responseText); - - if ('console' in window) console.log(response); - - error_cb(response.error, this); - } catch (err) { - // Perhaps the responseText wasn't really a jsonrpc-error. - error_cb({ error: jqXHR.responseText }, this); - } - } - }); - }; - - /** - * Notify sends a command to the server that won't need a response. In http, there is probably - * an empty response - that will be dropped, but in ws there should be no response at all. - * - * This is very similar to call, but has no id and no handling of callbacks. - * - * @fn notify - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - */ - $.JsonRpcClient.prototype.notify = function(method, params) { - // Construct the JSON-RPC 2.0 request. - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc: '2.0', - method: method, - params: params - }; - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false - }); - }; - - /** - * Make a batch-call by using a callback. - * - * The callback will get an object "batch" as only argument. On batch, you can call the methods - * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be - * sent as a batch call then the callback is done. - * - * @fn batch - * @memberof $.JsonRpcClient - * - * @param callback The main function which will get a batch handler to run call and notify on. - * @param all_done_cb A callback function to call after all results have been handled. - * @param error_cb A callback function to call if there is an error from the server. - * Note, that batch calls should always get an overall success, and the - * only error - */ - $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { - var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); - callback(batch); - batch._execute(); - }; - - /** - * The default getSocket handler. - * - * @param onmessage_cb The callback to be bound to onmessage events on the socket. - * - * @fn _getSocket - * @memberof $.JsonRpcClient - */ - - $.JsonRpcClient.prototype.socketReady = function() { - if (this._ws_socket === null || this._ws_socket.readyState > 1) { - return false; - } - - return true; - }; - - $.JsonRpcClient.prototype.closeSocket = function() { - var self = this; - if (self.socketReady()) { - self._ws_socket.onclose = function (w) {console.log("Closing Socket");}; - self._ws_socket.close(); - } - }; - - $.JsonRpcClient.prototype.loginData = function(params) { - var self = this; - self.options.login = params.login; - self.options.passwd = params.passwd; - self.options.loginParams = params.loginParams; - self.options.userVariables = params.userVariables; - }; - - $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { - var self = this; - - if (self.to) { - clearTimeout(self.to); - } - - if (!self.socketReady()) { - self.authing = false; - - if (self._ws_socket) { - delete self._ws_socket; - } - - // No socket, or dying socket, let's get a new one. - self._ws_socket = new WebSocket(self.options.socketUrl); - - if (self._ws_socket) { - // Set up onmessage handler. - self._ws_socket.onmessage = onmessage_cb; - self._ws_socket.onclose = function (w) { - if (!self.ws_sleep) { - self.ws_sleep = 1000; - } - - if (self.options.onWSClose) { - self.options.onWSClose(self); - } - - if (self.ws_cnt > 10 && self.options.wsFallbackURL) { - self.options.socketUrl = self.options.wsFallbackURL; - } - - console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); - - self.to = setTimeout(function() { - console.log("Attempting Reconnection...."); - self.connectSocket(onmessage_cb); - }, self.ws_sleep); - - self.ws_cnt++; - - if (self.ws_sleep < 3000 && (self.ws_cnt % 10) === 0) { - self.ws_sleep += 1000; - } - }; - - // Set up sending of message for when the socket is open. - self._ws_socket.onopen = function() { - if (self.to) { - clearTimeout(self.to); - } - self.ws_sleep = 1000; - self.ws_cnt = 0; - if (self.options.onWSConnect) { - self.options.onWSConnect(self); - } - - var req; - // Send the requests. - while ((req = $.JsonRpcClient.q.pop())) { - self._ws_socket.send(req); - } - }; - } - } - - return self._ws_socket ? true : false; - }; - - $.JsonRpcClient.prototype.stopRetrying = function() { - if (self.to) - clearTimeout(self.to); - } - - $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { - // If there is no ws url set, we don't have a socket. - // Likewise, if there is no window.WebSocket. - if (this.options.socketUrl === null || !("WebSocket" in window)) return null; - - this.connectSocket(onmessage_cb); - - return this._ws_socket; - }; - - /** - * Queue to save messages delivered when websocket is not ready - */ - $.JsonRpcClient.q = []; - - /** - * Internal handler to dispatch a JRON-RPC request through a websocket. - * - * @fn _wsCall - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { - var request_json = $.toJSON(request); - - if (socket.readyState < 1) { - // The websocket is not open yet; we have to set sending of the message in onopen. - self = this; // In closure below, this is set to the WebSocket. Use self instead. - $.JsonRpcClient.q.push(request_json); - } else { - // We have a socket and it should be ready to send on. - socket.send(request_json); - } - - // Setup callbacks. If there is an id, this is a call and not a notify. - if ('id' in request && typeof success_cb !== 'undefined') { - this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; - } - }; - - /** - * Internal handler for the websocket messages. It determines if the message is a JSON-RPC - * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to - * given external onmessage-handler, if any. - * - * @param event The websocket onmessage-event. - */ - $.JsonRpcClient.prototype._wsOnMessage = function(event) { - // Check if this could be a JSON RPC message. - var response; - - // Special sub proto - if (event.data[0] == "#" && event.data[1] == "S" && event.data[2] == "P") { - if (event.data[3] == "U") { - this.up_dur = parseInt(event.data.substring(4)); - } else if (this.speedCB && event.data[3] == "D") { - this.down_dur = parseInt(event.data.substring(4)); - - var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0); - var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0); - - console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps); - var cb = this.speedCB; - this.speedCB = null; - cb(event, { - upDur: this.up_dur, - downDur: this.down_dur, - upKPS: up_kps, - downKPS: down_kps - }); - } - - return; - } - - - try { - response = $.parseJSON(event.data); - - /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. - - if (typeof response === 'object' && - 'jsonrpc' in response && - response.jsonrpc === '2.0') { - - /// @todo Handle bad response (without id). - - // If this is an object with result, it is a response. - if ('result' in response && this._ws_callbacks[response.id]) { - // Get the success callback. - var success_cb = this._ws_callbacks[response.id].success_cb; - - /* - // set the sessid if present - if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { - this.options.sessid = response.result.sessid; - if (this.options.sessid) { - console.log("setting session UUID to: " + this.options.sessid); - } - } - */ - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with result as parameter. - success_cb(response.result, this); - return; - } else if ('error' in response && this._ws_callbacks[response.id]) { - // If this is an object with error, it is an error response. - - // Get the error callback. - var error_cb = this._ws_callbacks[response.id].error_cb; - var orig_req = this._ws_callbacks[response.id].request; - - // if this is an auth request, send the credentials and resend the failed request - if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { - self.authing = true; - - this.call("login", { login: self.options.login, passwd: self.options.passwd, loginParams: self.options.loginParams, - userVariables: self.options.userVariables}, - this._ws_callbacks[response.id].request_obj.method == "login" ? - function(e) { - self.authing = false; - console.log("logged in"); - delete self._ws_callbacks[response.id]; - - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - } - - : - - function(e) { - self.authing = false; - console.log("logged in, resending request id: " + response.id); - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send(orig_req); - } - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - }, - - function(e) { - console.log("error logging in, request id:", response.id); - delete self._ws_callbacks[response.id]; - error_cb(response.error, this); - if (self.options.onWSLogin) { - self.options.onWSLogin(false, self); - } - }); - return; - } - - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with the error object as parameter. - error_cb(response.error, this); - return; - } - } - } catch (err) { - // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are - // handled above, and the fallback method is called below. - console.log("ERROR: "+ err); - return; - } - - // This is not a JSON-RPC response. Call the fallback message handler, if given. - if (typeof this.options.onmessage === 'function') { - event.eventData = response; - if (!event.eventData) { - event.eventData = {}; - } - - var reply = this.options.onmessage(event); - - if (reply && typeof reply === "object" && event.eventData.id) { - var msg = { - jsonrpc: "2.0", - id: event.eventData.id, - result: reply - }; - - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send($.toJSON(msg)); - } - } - } - }; - - - /************************************************************************************************ - * Batch object with methods - ************************************************************************************************/ - - /** - * Handling object for batch calls. - */ - $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { - // Array of objects to hold the call and notify requests. Each objects will have the request - // object, and unless it is a notify, success_cb and error_cb. - this._requests = []; - - this.jsonrpcclient = jsonrpcclient; - this.all_done_cb = all_done_cb; - this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; - - }; - - /** - * @sa $.JsonRpcClient.prototype.call - */ - $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params, - id : this.jsonrpcclient._current_id++ // Use the client's id series. - }, - success_cb : success_cb, - error_cb : error_cb - }); - }; - - /** - * @sa $.JsonRpcClient.prototype.notify - */ - $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params - } - }); - }; - - /** - * Executes the batched up calls. - */ - $.JsonRpcClient._batchObject.prototype._execute = function() { - var self = this; - - if (this._requests.length === 0) return; // All done :P - - // Collect all request data and sort handlers by request id. - var batch_request = []; - var handlers = {}; - var i = 0; - var call; - var success_cb; - var error_cb; - - // If we have a WebSocket, just send the requests individually like normal calls. - var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); - if (socket !== null) { - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - success_cb = ('success_cb' in call) ? call.success_cb : undefined; - error_cb = ('error_cb' in call) ? call.error_cb : undefined; - self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - return; - } - - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - batch_request.push(call.request); - - // If the request has an id, it should handle returns (otherwise it's a notify). - if ('id' in call.request) { - handlers[call.request.id] = { - success_cb : call.success_cb, - error_cb : call.error_cb - }; - } - } - - success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; - - // No WebSocket, and no HTTP backend? This won't work. - if (self.jsonrpcclient.options.ajaxUrl === null) { - throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; - } - - // Send request - $.ajax({ - url : self.jsonrpcclient.options.ajaxUrl, - data : $.toJSON(batch_request), - dataType : 'json', - cache : false, - type : 'POST', - - // Batch-requests should always return 200 - error : function(jqXHR, textStatus, errorThrown) { - self.error_cb(jqXHR, textStatus, errorThrown); - }, - success : success_cb - }); - }; - - /** - * Internal helper to match the result array from a batch call to their respective callbacks. - * - * @fn _batchCb - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { - for (var i = 0; i < result.length; i++) { - var response = result[i]; - - // Handle error - if ('error' in response) { - if (response.id === null || !(response.id in handlers)) { - // An error on a notify? Just log it to the console. - if ('console' in window) console.log(response); - } else { - handlers[response.id].error_cb(response.error, this); - } - } else { - // Here we should always have a correct id and no error. - if (!(response.id in handlers) && 'console' in window) { - console.log(response); - } else { - handlers[response.id].success_cb(response.result, this); - } - } - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - }; - -})(jQuery); - -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.verto.js - Main interface - * - */ - -(function($) { - var sources = []; - - var generateGUID = (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') ? - function() { - // If we have a cryptographically secure PRNG, use that - // http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript - var buf = new Uint16Array(8); - window.crypto.getRandomValues(buf); - var S4 = function(num) { - var ret = num.toString(16); - while (ret.length < 4) { - ret = "0" + ret; - } - return ret; - }; - return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7])); - } - - : - - function() { - // Otherwise, just use Math.random - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, - v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - }; - - /// MASTER OBJ - $.verto = function(options, callbacks) { - var verto = this; - - $.verto.saved.push(verto); - - verto.options = $.extend({ - login: null, - passwd: null, - socketUrl: null, - tag: null, - localTag: null, - videoParams: {}, - audioParams: {}, - loginParams: {}, - deviceParams: {onResCheck: null}, - userVariables: {}, - iceServers: false, - ringSleep: 6000, - sessid: null, - useStream: null - }, options); - - if (verto.options.deviceParams.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, verto.options.deviceParams.onResCheck); - } - - if (!verto.options.deviceParams.useMic) { - verto.options.deviceParams.useMic = "any"; - } - - if (!verto.options.deviceParams.useSpeak) { - verto.options.deviceParams.useSpeak = "any"; - } - - if (verto.options.sessid) { - verto.sessid = verto.options.sessid; - } else { - verto.sessid = localStorage.getItem("verto_session_uuid") || generateGUID(); - localStorage.setItem("verto_session_uuid", verto.sessid); - } - - verto.dialogs = {}; - verto.callbacks = callbacks || {}; - verto.eventSUBS = {}; - - verto.rpcClient = new $.JsonRpcClient({ - login: verto.options.login, - passwd: verto.options.passwd, - socketUrl: verto.options.socketUrl, - wsFallbackURL: verto.options.wsFallbackURL, - turnServer: verto.options.turnServer, - loginParams: verto.options.loginParams, - userVariables: verto.options.userVariables, - sessid: verto.sessid, - onmessage: function(e) { - return verto.handleMessage(e.eventData); - }, - onWSConnect: function(o) { - o.call('login', {}); - }, - onWSLogin: function(success) { - if (verto.callbacks.onWSLogin) { - verto.callbacks.onWSLogin(verto, success); - } - }, - onWSClose: function(success) { - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, success); - } - verto.purge(); - } - }); - - var tag = verto.options.tag; - if (typeof(tag) === "function") { - tag = tag(); - } - - if (verto.options.ringFile && verto.options.tag) { - verto.ringer = $("#" + tag); - } - - verto.rpcClient.call('login', {}); - - }; - - - $.verto.prototype.deviceParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.deviceParams[i] = obj[i]; - } - - if (obj.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, obj ? obj.onResCheck : undefined); - } - }; - - $.verto.prototype.videoParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.videoParams[i] = obj[i]; - } - }; - - $.verto.prototype.iceServers = function(obj) { - var verto = this; - verto.options.iceServers = obj; - }; - - $.verto.prototype.loginData = function(params) { - var verto = this; - verto.options.login = params.login; - verto.options.passwd = params.passwd; - verto.rpcClient.loginData(params); - }; - - $.verto.prototype.logout = function(msg) { - var verto = this; - verto.rpcClient.closeSocket(); - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, false); - } - verto.purge(); - }; - - $.verto.prototype.login = function(msg) { - var verto = this; - verto.logout(); - verto.rpcClient.call('login', {}); - }; - - $.verto.prototype.message = function(msg) { - var verto = this; - var err = 0; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - verto.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.prototype.processReply = function(method, success, e) { - var verto = this; - var i; - - //console.log("Response: " + method, success, e); - - switch (method) { - case "verto.subscribe": - for (i in e.unauthorizedChannels) { - drop_bad(verto, e.unauthorizedChannels[i]); - } - for (i in e.subscribedChannels) { - mark_ready(verto, e.subscribedChannels[i]); - } - - break; - case "verto.unsubscribe": - //console.error(e); - break; - } - }; - - $.verto.prototype.sendMethod = function(method, params) { - var verto = this; - - verto.rpcClient.call(method, params, - - function(e) { - /* Success */ - verto.processReply(method, true, e); - }, - - function(e) { - /* Error */ - verto.processReply(method, false, e); - }); - }; - - function do_sub(verto, channel, obj) { - - } - - function drop_bad(verto, channel) { - console.error("drop unauthorized channel: " + channel); - delete verto.eventSUBS[channel]; - } - - function mark_ready(verto, channel) { - for (var j in verto.eventSUBS[channel]) { - verto.eventSUBS[channel][j].ready = true; - console.log("subscribed to channel: " + channel); - if (verto.eventSUBS[channel][j].readyHandler) { - verto.eventSUBS[channel][j].readyHandler(verto, channel); - } - } - } - - var SERNO = 1; - - function do_subscribe(verto, channel, subChannels, sparams) { - var params = sparams || {}; - - var local = params.local; - - var obj = { - eventChannel: channel, - userData: params.userData, - handler: params.handler, - ready: false, - readyHandler: params.readyHandler, - serno: SERNO++ - }; - - var isnew = false; - - if (!verto.eventSUBS[channel]) { - verto.eventSUBS[channel] = []; - subChannels.push(channel); - isnew = true; - } - - verto.eventSUBS[channel].push(obj); - - if (local) { - obj.ready = true; - obj.local = true; - } - - if (!isnew && verto.eventSUBS[channel][0].ready) { - obj.ready = true; - if (obj.readyHandler) { - obj.readyHandler(verto, channel); - } - } - - return { - serno: obj.serno, - eventChannel: channel - }; - - } - - $.verto.prototype.subscribe = function(channel, sparams) { - var verto = this; - var r = []; - var subChannels = []; - var params = sparams || {}; - - if (typeof(channel) === "string") { - r.push(do_subscribe(verto, channel, subChannels, params)); - } else { - for (var i in channel) { - r.push(do_subscribe(verto, channel, subChannels, params)); - } - } - - if (subChannels.length) { - verto.sendMethod("verto.subscribe", { - eventChannel: subChannels.length == 1 ? subChannels[0] : subChannels, - subParams: params.subParams - }); - } - - return r; - }; - - $.verto.prototype.unsubscribe = function(handle) { - var verto = this; - var i; - - if (!handle) { - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - verto.unsubscribe(verto.eventSUBS[i]); - } - } - } else { - var unsubChannels = {}; - var sendChannels = []; - var channel; - - if (typeof(handle) == "string") { - delete verto.eventSUBS[handle]; - unsubChannels[handle]++; - } else { - for (i in handle) { - if (typeof(handle[i]) == "string") { - channel = handle[i]; - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } else { - var repl = []; - channel = handle[i].eventChannel; - - for (var j in verto.eventSUBS[channel]) { - if (verto.eventSUBS[channel][j].serno == handle[i].serno) {} else { - repl.push(verto.eventSUBS[channel][j]); - } - } - - verto.eventSUBS[channel] = repl; - - if (verto.eventSUBS[channel].length === 0) { - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } - } - } - } - - for (var u in unsubChannels) { - console.log("Sending Unsubscribe for: ", u); - sendChannels.push(u); - } - - if (sendChannels.length) { - verto.sendMethod("verto.unsubscribe", { - eventChannel: sendChannels.length == 1 ? sendChannels[0] : sendChannels - }); - } - } - }; - - $.verto.prototype.broadcast = function(channel, params) { - var verto = this; - var msg = { - eventChannel: channel, - data: {} - }; - for (var i in params) { - msg.data[i] = params[i]; - } - verto.sendMethod("verto.broadcast", msg); - }; - - $.verto.prototype.purge = function(callID) { - var verto = this; - var x = 0; - var i; - - for (i in verto.dialogs) { - if (!x) { - console.log("purging dialogs"); - } - x++; - verto.dialogs[i].setState($.verto.enum.state.purge); - } - - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - console.log("purging subscription: " + i); - delete verto.eventSUBS[i]; - } - } - }; - - $.verto.prototype.hangup = function(callID) { - var verto = this; - if (callID) { - var dialog = verto.dialogs[callID]; - - if (dialog) { - dialog.hangup(); - } - } else { - for (var i in verto.dialogs) { - verto.dialogs[i].hangup(); - } - } - }; - - $.verto.prototype.newCall = function(args, callbacks) { - var verto = this; - - if (!verto.rpcClient.socketReady()) { - console.error("Not Connected..."); - return; - } - - if (args["useCamera"]) { - verto.options.deviceParams["useCamera"] = args["useCamera"]; - } - - var dialog = new $.verto.dialog($.verto.enum.direction.outbound, this, args); - - if (callbacks) { - dialog.callbacks = callbacks; - } - - dialog.invite(); - - return dialog; - }; - - $.verto.prototype.handleMessage = function(data) { - var verto = this; - - if (!(data && data.method)) { - console.error("Invalid Data", data); - return; - } - - if (data.params.callID) { - var dialog = verto.dialogs[data.params.callID]; - - if (data.method === "verto.attach" && dialog) { - delete dialog.verto.dialogs[dialog.callID]; - dialog.rtc.stop(); - dialog = null; - } - - if (dialog) { - - switch (data.method) { - case 'verto.bye': - dialog.hangup(data.params); - break; - case 'verto.answer': - dialog.handleAnswer(data.params); - break; - case 'verto.media': - dialog.handleMedia(data.params); - break; - case 'verto.display': - dialog.handleDisplay(data.params); - break; - case 'verto.info': - dialog.handleInfo(data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", dialog, data.method); - break; - } - } else { - - switch (data.method) { - case 'verto.attach': - data.params.attach = true; - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.useVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - dialog.setState($.verto.enum.state.recovering); - - break; - case 'verto.invite': - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.wantVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED"); - break; - } - } - - return { - method: data.method - }; - } else { - switch (data.method) { - case 'verto.punt': - verto.purge(); - verto.logout(); - break; - case 'verto.event': - var list = null; - var key = null; - - if (data.params) { - key = data.params.eventChannel; - } - - if (key) { - list = verto.eventSUBS[key]; - - if (!list) { - list = verto.eventSUBS[key.split(".")[0]]; - } - } - - if (!list && key && key === verto.sessid) { - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); - } - } else if (!list && key && verto.dialogs[key]) { - verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params); - } else if (!list) { - if (!key) { - key = "UNDEFINED"; - } - console.error("UNSUBBED or invalid EVENT " + key + " IGNORED"); - } else { - for (var i in list) { - var sub = list[i]; - - if (!sub || !sub.ready) { - console.error("invalid EVENT for " + key + " IGNORED"); - } else if (sub.handler) { - sub.handler(verto, data.params, sub.userData); - } else if (verto.callbacks.onEvent) { - verto.callbacks.onEvent(verto, data.params, sub.userData); - } else { - console.log("EVENT:", data.params); - } - } - } - - break; - - case "verto.info": - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.info, data.params.msg); - } - //console.error(data); - console.debug("MESSAGE from: " + data.params.msg.from, data.params.msg.body); - - break; - - case 'verto.clientReady': - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.clientReady, data.params); - } - console.debug("CLIENT READY", data.params); - break; - - default: - console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method); - break; - } - } - }; - - var del_array = function(array, name) { - var r = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] != name) { - r.push(array[i]); - } - } - - return r; - }; - - var hashArray = function() { - var vha = this; - - var hash = {}; - var array = []; - - vha.reorder = function(a) { - array = a; - var h = hash; - hash = {}; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - if (h[key]) { - hash[key] = h[key]; - delete h[key]; - } - } - h = undefined; - }; - - vha.clear = function() { - hash = undefined; - array = undefined; - hash = {}; - array = []; - }; - - vha.add = function(name, val, insertAt) { - var redraw = false; - - if (!hash[name]) { - if (insertAt === undefined || insertAt < 0 || insertAt >= array.length) { - array.push(name); - } else { - var x = 0; - var n = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (x++==insertAt) { - n.push(name); - } - n.push(array[i]); - } - - array = undefined; - array = n; - n = undefined; - redraw = true; - } - } - - hash[name] = val; - - return redraw; - }; - - vha.del = function(name) { - var r = false; - - if (hash[name]) { - array = del_array(array, name); - delete hash[name]; - r = true; - } else { - console.error("can't del nonexistant key " + name); - } - - return r; - }; - - vha.get = function(name) { - return hash[name]; - }; - - vha.order = function() { - return array; - }; - - vha.hash = function() { - return hash; - }; - - vha.indexOf = function(name) { - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] == name) { - return i; - } - } - }; - - vha.arrayLen = function() { - return array.length; - }; - - vha.asArray = function() { - var r = []; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - r.push(hash[key]); - } - - return r; - }; - - vha.each = function(cb) { - var len = array.length; - - for (var i = 0; i < len; i++) { - cb(array[i], hash[array[i]]); - } - }; - - vha.dump = function(html) { - var str = ""; - - vha.each(function(name, val) { - str += "name: " + name + " val: " + JSON.stringify(val) + (html ? "
" : "\n"); - }); - - return str; - }; - - }; - - $.verto.liveArray = function(verto, context, name, config) { - var la = this; - var lastSerno = 0; - var binding = null; - var user_obj = config.userObj; - var local = false; - - // Inherit methods of hashArray - hashArray.call(la); - - // Save the hashArray add, del, reorder, clear methods so we can make our own. - la._add = la.add; - la._del = la.del; - la._reorder = la.reorder; - la._clear = la.clear; - - la.context = context; - la.name = name; - la.user_obj = user_obj; - - la.verto = verto; - la.broadcast = function(channel, obj) { - verto.broadcast(channel, obj); - }; - la.errs = 0; - - la.clear = function() { - la._clear(); - lastSerno = 0; - - if (la.onChange) { - la.onChange(la, { - action: "clear" - }); - } - }; - - la.checkSerno = function(serno) { - if (serno < 0) { - return true; - } - - if (lastSerno > 0 && serno != (lastSerno + 1)) { - if (la.onErr) { - la.onErr(la, { - lastSerno: lastSerno, - serno: serno - }); - } - la.errs++; - console.debug(la.errs); - if (la.errs < 3) { - la.bootstrap(la.user_obj); - } - return false; - } else { - lastSerno = serno; - return true; - } - }; - - la.reorder = function(serno, a) { - if (la.checkSerno(serno)) { - la._reorder(a); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "reorder" - }); - } - } - }; - - la.init = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "init", - index: index, - key: key, - data: val - }); - } - } - }; - - la.bootObj = function(serno, val) { - if (la.checkSerno(serno)) { - - //la.clear(); - for (var i in val) { - la._add(val[i][0], val[i][1]); - } - - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "bootObj", - data: val, - redraw: true - }); - } - } - }; - - // @param serno La is the serial number for la particular request. - // @param key If looking at it as a hash table, la represents the key in the hashArray object where you want to store the val object. - // @param index If looking at it as an array, la represents the position in the array where you want to store the val object. - // @param val La is the object you want to store at the key or index location in the hash table / array. - la.add = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - var redraw = la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "add", - index: index, - key: key, - data: val, - redraw: redraw - }); - } - } - }; - - la.modify = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "modify", - key: key, - data: val, - index: index - }); - } - } - }; - - la.del = function(serno, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (index === null || index < 0 || index === undefined) { - index = la.indexOf(key); - } - var ok = la._del(key); - - if (ok && la.onChange) { - la.onChange(la, { - serno: serno, - action: "del", - key: key, - index: index - }); - } - } - }; - - var eventHandler = function(v, e, la) { - var packet = e.data; - - //console.error("READ:", packet); - - if (packet.name != la.name) { - return; - } - - switch (packet.action) { - - case "init": - la.init(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "bootObj": - la.bootObj(packet.wireSerno, packet.data); - break; - case "add": - la.add(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "modify": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.modify(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - } - break; - case "del": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.del(packet.wireSerno, packet.hashKey, packet.arrIndex); - } - break; - - case "clear": - la.clear(); - break; - - case "reorder": - la.reorder(packet.wireSerno, packet.order); - break; - - default: - if (la.checkSerno(packet.wireSerno)) { - if (la.onChange) { - la.onChange(la, { - serno: packet.wireSerno, - action: packet.action, - data: packet.data - }); - } - } - break; - } - }; - - if (la.context) { - binding = la.verto.subscribe(la.context, { - handler: eventHandler, - userData: la, - subParams: config.subParams - }); - } - - la.destroy = function() { - la._clear(); - la.verto.unsubscribe(binding); - }; - - la.sendCommand = function(cmd, obj) { - var self = la; - self.broadcast(self.context, { - liveArray: { - command: cmd, - context: self.context, - name: self.name, - obj: obj - } - }); - }; - - la.bootstrap = function(obj) { - var self = la; - la.sendCommand("bootstrap", obj); - //self.heartbeat(); - }; - - la.changepage = function(obj) { - var self = la; - self.clear(); - self.broadcast(self.context, { - liveArray: { - command: "changepage", - context: la.context, - name: la.name, - obj: obj - } - }); - }; - - la.heartbeat = function(obj) { - var self = la; - - var callback = function() { - self.heartbeat.call(self, obj); - }; - self.broadcast(self.context, { - liveArray: { - command: "heartbeat", - context: self.context, - name: self.name, - obj: obj - } - }); - self.hb_pid = setTimeout(callback, 30000); - }; - - la.bootstrap(la.user_obj); - }; - - $.verto.liveTable = function(verto, context, name, jq, config) { - var dt; - var la = new $.verto.liveArray(verto, context, name, { - subParams: config.subParams - }); - var lt = this; - - lt.liveArray = la; - lt.dataTable = dt; - lt.verto = verto; - - lt.destroy = function() { - if (dt) { - dt.fnDestroy(); - } - if (la) { - la.destroy(); - } - - dt = null; - la = null; - }; - - la.onErr = function(obj, args) { - console.error("Error: ", obj, args); - }; - - /* back compat so jsonstatus can always be enabled */ - function genRow(data) { - if (typeof(data[4]) === "string" && data[4].indexOf("{") > -1) { - var tmp = $.parseJSON(data[4]); - data[4] = tmp.oldStatus; - data[5] = null; - } - return data; - } - - function genArray(obj) { - var data = obj.asArray(); - - for (var i in data) { - data[i] = genRow(data[i]); - } - - return data; - } - - - la.onChange = function(obj, args) { - var index = 0; - var iserr = 0; - - if (!dt) { - if (!config.aoColumns) { - if (args.action != "init") { - return; - } - - config.aoColumns = []; - - for (var i in args.data) { - config.aoColumns.push({ - "sTitle": args.data[i] - }); - } - } - - dt = jq.dataTable(config); - } - - if (dt && (args.action == "del" || args.action == "modify")) { - index = args.index; - - if (index === undefined && args.key) { - index = la.indexOf(args.key); - } - - if (index === undefined) { - console.error("INVALID PACKET Missing INDEX\n", args); - return; - } - } - - if (config.onChange) { - config.onChange(obj, args); - } - - try { - switch (args.action) { - case "bootObj": - if (!args.data) { - console.error("missing data"); - return; - } - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - dt.fnAdjustColumnSizing(); - break; - case "add": - if (!args.data) { - console.error("missing data"); - return; - } - if (args.redraw > -1) { - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - } else { - dt.fnAddData(genRow(args.data)); - } - dt.fnAdjustColumnSizing(); - break; - case "modify": - if (!args.data) { - return; - } - //console.debug(args, index); - dt.fnUpdate(genRow(args.data), index); - dt.fnAdjustColumnSizing(); - break; - case "del": - dt.fnDeleteRow(index); - dt.fnAdjustColumnSizing(); - break; - case "clear": - dt.fnClearTable(); - break; - case "reorder": - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - break; - case "hide": - jq.hide(); - break; - - case "show": - jq.show(); - break; - - } - } catch(err) { - console.error("ERROR: " + err); - iserr++; - } - - if (iserr) { - obj.errs++; - if (obj.errs < 3) { - obj.bootstrap(obj.user_obj); - } - } else { - obj.errs = 0; - } - - }; - - la.onChange(la, { - action: "init" - }); - - }; - - var CONFMAN_SERNO = 1; - - /* - Conference Manager without jQuery table. - */ - - $.verto.conf = function(verto, params) { - var conf = this; - - conf.params = $.extend({ - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - conf.verto = verto; - conf.serno = CONFMAN_SERNO++; - - createMainModeratorMethods(); - - verto.subscribe(conf.params.laData.modChannel, { - handler: function(v, e) { - if (conf.params.onBroadcast) { - conf.params.onBroadcast(verto, conf, e.data); - } - } - }); - - verto.subscribe(conf.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(conf.params.infoCallback) === "function") { - conf.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(conf.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(conf.params.chatCallback) === "function") { - conf.params.chatCallback(v,e); - } - } - }); - }; - - $.verto.conf.prototype.modCommand = function(cmd, id, value) { - var conf = this; - - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.conf.prototype.destroy = function() { - var conf = this; - - conf.destroyed = true; - conf.params.onBroadcast(conf.verto, conf, 'destroy'); - - if (conf.params.laData.modChannel) { - conf.verto.unsubscribe(conf.params.laData.modChannel); - } - - if (conf.params.laData.chatChannel) { - conf.verto.unsubscribe(conf.params.laData.chatChannel); - } - - if (conf.params.laData.infoChannel) { - conf.verto.unsubscribe(conf.params.laData.infoChannel); - } - }; - - function createMainModeratorMethods() { - $.verto.conf.prototype.listVideoLayouts = function() { - this.modCommand("list-videoLayouts", null, null); - }; - - $.verto.conf.prototype.play = function(file) { - this.modCommand("play", null, file); - }; - - $.verto.conf.prototype.stop = function() { - this.modCommand("stop", null, "all"); - }; - - $.verto.conf.prototype.deaf = function(memberID) { - this.modCommand("deaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.undeaf = function(memberID) { - this.modCommand("undeaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.record = function(file) { - this.modCommand("recording", null, ["start", file]); - }; - - $.verto.conf.prototype.stopRecord = function() { - this.modCommand("recording", null, ["stop", "all"]); - }; - - $.verto.conf.prototype.snapshot = function(file) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-write-png", null, file); - }; - - $.verto.conf.prototype.setVideoLayout = function(layout, canvasID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - if (canvasID) { - this.modCommand("vid-layout", null, [layout, canvasID]); - } else { - this.modCommand("vid-layout", null, layout); - } - }; - - $.verto.conf.prototype.kick = function(memberID) { - this.modCommand("kick", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteMic = function(memberID) { - this.modCommand("tmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteVideo = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("tvmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.presenter = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-res-id", parseInt(memberID), "presenter"); - }; - - $.verto.conf.prototype.videoFloor = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-floor", parseInt(memberID), "force"); - }; - - $.verto.conf.prototype.banner = function(memberID, text) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-banner", parseInt(memberID), escape(text)); - }; - - $.verto.conf.prototype.volumeDown = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.volumeUp = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.gainDown = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.gainUp = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.transfer = function(memberID, exten) { - this.modCommand("transfer", parseInt(memberID), exten); - }; - - $.verto.conf.prototype.sendChat = function(message, type) { - var conf = this; - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - } - - $.verto.modfuncs = {}; - - $.verto.confMan = function(verto, params) { - var confMan = this; - - confMan.params = $.extend({ - tableID: null, - statusID: null, - mainModID: null, - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - confMan.verto = verto; - confMan.serno = CONFMAN_SERNO++; - confMan.canvasCount = confMan.params.laData.canvasCount; - - function genMainMod(jq) { - var play_id = "play_" + confMan.serno; - var stop_id = "stop_" + confMan.serno; - var recording_id = "recording_" + confMan.serno; - var snapshot_id = "snapshot_" + confMan.serno; - var rec_stop_id = "recording_stop" + confMan.serno; - var div_id = "confman_" + confMan.serno; - - var html = "

" + - "" + - "" + - "" + - "" + - (confMan.params.hasVid ? "" : "") + - "

"; - - jq.html(html); - - $.verto.modfuncs.change_video_layout = function(id, canvas_id) { - var val = $("#" + id + " option:selected").text(); - if (val !== "none") { - confMan.modCommand("vid-layout", null, [val, canvas_id]); - } - }; - - if (confMan.params.hasVid) { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno; - var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno; - - - var vlhtml = "

" + - "Video Layout Canvas " + (j+1) + - " " + - "

"; - jq.append(vlhtml); - } - - $("#" + snapshot_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("vid-write-png", null, file); - } - }); - } - - $("#" + play_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("play", null, file); - } - }); - - $("#" + stop_id).click(function() { - confMan.modCommand("stop", null, "all"); - }); - - $("#" + recording_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("recording", null, ["start", file]); - } - }); - - $("#" + rec_stop_id).click(function() { - confMan.modCommand("recording", null, ["stop", "all"]); - }); - - } - - function genControls(jq, rowid) { - var x = parseInt(rowid); - var kick_id = "kick_" + x; - var canvas_in_next_id = "canvas_in_next_" + x; - var canvas_in_prev_id = "canvas_in_prev_" + x; - var canvas_out_next_id = "canvas_out_next_" + x; - var canvas_out_prev_id = "canvas_out_prev_" + x; - - var canvas_in_set_id = "canvas_in_set_" + x; - var canvas_out_set_id = "canvas_out_set_" + x; - - var layer_set_id = "layer_set_" + x; - var layer_next_id = "layer_next_" + x; - var layer_prev_id = "layer_prev_" + x; - - var tmute_id = "tmute_" + x; - var tvmute_id = "tvmute_" + x; - var vbanner_id = "vbanner_" + x; - var tvpresenter_id = "tvpresenter_" + x; - var tvfloor_id = "tvfloor_" + x; - var box_id = "box_" + x; - var gainup_id = "gain_in_up" + x; - var gaindn_id = "gain_in_dn" + x; - var volup_id = "vol_in_up" + x; - var voldn_id = "vol_in_dn" + x; - var transfer_id = "transfer" + x; - - - var html = "
"; - - html += "General Controls
"; - - html += "" + - "" + - "" + - "" + - "" + - "" + - ""; - - if (confMan.params.hasVid) { - html += "

Video Controls
"; - - - html += "" + - "" + - "" + - ""; - - if (confMan.canvasCount > 1) { - html += "

Canvas Controls
" + - "" + - "" + - "" + - - "
" + - - "" + - "" + - ""; - } - - html += "
" + - - "" + - "" + - "" + - - - - "
"; - } - - jq.html(html); - - - if (!jq.data("mouse")) { - $("#" + box_id).hide(); - } - - jq.mouseover(function(e) { - jq.data({"mouse": true}); - $("#" + box_id).show(); - }); - - jq.mouseout(function(e) { - jq.data({"mouse": false}); - $("#" + box_id).hide(); - }); - - $("#" + transfer_id).click(function() { - var xten = prompt("Enter Extension"); - if (xten) { - confMan.modCommand("transfer", x, xten); - } - }); - - $("#" + kick_id).click(function() { - confMan.modCommand("kick", x); - }); - - - $("#" + layer_set_id).click(function() { - var cid = prompt("Please enter layer ID", ""); - if (cid) { - confMan.modCommand("vid-layer", x, cid); - } - }); - - $("#" + layer_next_id).click(function() { - confMan.modCommand("vid-layer", x, "next"); - }); - $("#" + layer_prev_id).click(function() { - confMan.modCommand("vid-layer", x, "prev"); - }); - - $("#" + canvas_in_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-canvas", x, cid); - } - }); - - $("#" + canvas_out_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-watching-canvas", x, cid); - } - }); - - $("#" + canvas_in_next_id).click(function() { - confMan.modCommand("vid-canvas", x, "next"); - }); - $("#" + canvas_in_prev_id).click(function() { - confMan.modCommand("vid-canvas", x, "prev"); - }); - - - $("#" + canvas_out_next_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "next"); - }); - $("#" + canvas_out_prev_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "prev"); - }); - - $("#" + tmute_id).click(function() { - confMan.modCommand("tmute", x); - }); - - if (confMan.params.hasVid) { - $("#" + tvmute_id).click(function() { - confMan.modCommand("tvmute", x); - }); - $("#" + tvpresenter_id).click(function() { - confMan.modCommand("vid-res-id", x, "presenter"); - }); - $("#" + tvfloor_id).click(function() { - confMan.modCommand("vid-floor", x, "force"); - }); - $("#" + vbanner_id).click(function() { - var text = prompt("Please enter text", ""); - if (text) { - confMan.modCommand("vid-banner", x, escape(text)); - } - }); - } - - $("#" + gainup_id).click(function() { - confMan.modCommand("volume_in", x, "up"); - }); - - $("#" + gaindn_id).click(function() { - confMan.modCommand("volume_in", x, "down"); - }); - - $("#" + volup_id).click(function() { - confMan.modCommand("volume_out", x, "up"); - }); - - $("#" + voldn_id).click(function() { - confMan.modCommand("volume_out", x, "down"); - }); - - return html; - } - - var atitle = ""; - var awidth = 0; - - //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px"); - - verto.subscribe(confMan.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(confMan.params.infoCallback) === "function") { - confMan.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(confMan.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(confMan.params.chatCallback) === "function") { - confMan.params.chatCallback(v,e); - } - } - }); - - if (confMan.params.laData.role === "moderator") { - atitle = "Action"; - awidth = 600; - - if (confMan.params.mainModID) { - genMainMod($(confMan.params.mainModID)); - $(confMan.params.displayID).html("Moderator Controls Ready

"); - } else { - $(confMan.params.mainModID).html(""); - } - - verto.subscribe(confMan.params.laData.modChannel, { - handler: function(v, e) { - //console.error("MODDATA:", e.data); - if (confMan.params.onBroadcast) { - confMan.params.onBroadcast(verto, confMan, e.data); - } - - if (e.data["conf-command"] === "list-videoLayouts") { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno; - var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno; - - var x = 0; - var options; - - $(vlselect_id).selectmenu({}); - $(vlselect_id).selectmenu("enable"); - $(vlselect_id).empty(); - - $(vlselect_id).append(new Option("Choose a Layout", "none")); - - if (e.data.responseData) { - var rdata = []; - - for (var i in e.data.responseData) { - rdata.push(e.data.responseData[i].name); - } - - options = rdata.sort(function(a, b) { - var ga = a.substring(0, 6) == "group:" ? true : false; - var gb = b.substring(0, 6) == "group:" ? true : false; - - if ((ga || gb) && ga != gb) { - return ga ? -1 : 1; - } - - return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) ); - }); - - for (var i in options) { - $(vlselect_id).append(new Option(options[i], options[i])); - x++; - } - } - - if (x) { - $(vlselect_id).selectmenu('refresh', true); - } else { - $(vlayout_id).hide(); - } - } - } else { - - if (!confMan.destroyed && confMan.params.displayID) { - $(confMan.params.displayID).html(e.data.response + "

"); - if (confMan.lastTimeout) { - clearTimeout(confMan.lastTimeout); - confMan.lastTimeout = 0; - } - confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

");}, 4000); - } - } - } - }); - - - if (confMan.params.hasVid) { - confMan.modCommand("list-videoLayouts", null, null); - } - } - - var row_callback = null; - - if (confMan.params.laData.role === "moderator") { - row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { - if (!aData[5]) { - var $row = $('td:eq(5)', nRow); - genControls($row, aData); - - if (confMan.params.onLaRow) { - confMan.params.onLaRow(verto, confMan, $row, aData); - } - } - }; - } - - confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), { - subParams: { - callID: confMan.params.dialog ? confMan.params.dialog.callID : null - }, - - "onChange": function(obj, args) { - $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)"); - if (confMan.params.onLaChange) { - confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); - } - }, - - "aaData": [], - "aoColumns": [ - { - "sTitle": "ID", - "sWidth": "50" - }, - { - "sTitle": "Number", - "sWidth": "250" - }, - { - "sTitle": "Name", - "sWidth": "250" - }, - { - "sTitle": "Codec", - "sWidth": "100" - }, - { - "sTitle": "Status", - "sWidth": confMan.params.hasVid ? "200px" : "150px" - }, - { - "sTitle": atitle, - "sWidth": awidth, - } - ], - "bAutoWidth": true, - "bDestroy": true, - "bSort": false, - "bInfo": false, - "bFilter": false, - "bLengthChange": false, - "bPaginate": false, - "iDisplayLength": 1400, - - "oLanguage": { - "sEmptyTable": "The Conference is Empty....." - }, - - "fnRowCallback": row_callback - - }); - }; - - $.verto.confMan.prototype.modCommand = function(cmd, id, value) { - var confMan = this; - - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.confMan.prototype.sendChat = function(message, type) { - var confMan = this; - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - - $.verto.confMan.prototype.destroy = function() { - var confMan = this; - - confMan.destroyed = true; - - if (confMan.lt) { - confMan.lt.destroy(); - } - - if (confMan.params.laData.chatChannel) { - confMan.verto.unsubscribe(confMan.params.laData.chatChannel); - } - - if (confMan.params.laData.modChannel) { - confMan.verto.unsubscribe(confMan.params.laData.modChannel); - } - - if (confMan.params.mainModID) { - $(confMan.params.mainModID).html(""); - } - }; - - $.verto.dialog = function(direction, verto, params) { - var dialog = this; - - dialog.params = $.extend({ - useVideo: verto.options.useVideo, - useStereo: verto.options.useStereo, - screenShare: false, - useCamera: false, - useMic: verto.options.deviceParams.useMic, - useSpeak: verto.options.deviceParams.useSpeak, - tag: verto.options.tag, - localTag: verto.options.localTag, - login: verto.options.login, - videoParams: verto.options.videoParams, - useStream: verto.options.useStream, - }, params); - - - if (!dialog.params.screenShare) { - dialog.params.useCamera = verto.options.deviceParams.useCamera; - } - - dialog.verto = verto; - dialog.direction = direction; - dialog.lastState = null; - dialog.state = dialog.lastState = $.verto.enum.state.new; - dialog.callbacks = verto.callbacks; - dialog.answered = false; - dialog.attach = params.attach || false; - dialog.screenShare = params.screenShare || false; - dialog.useCamera = dialog.params.useCamera; - dialog.useMic = dialog.params.useMic; - dialog.useSpeak = dialog.params.useSpeak; - - if (dialog.params.callID) { - dialog.callID = dialog.params.callID; - } else { - dialog.callID = dialog.params.callID = generateGUID(); - } - - if (typeof(dialog.params.tag) === "function") { - dialog.params.tag = dialog.params.tag(); - } - - if (dialog.params.tag) { - dialog.audioStream = document.getElementById(dialog.params.tag); - - if (dialog.params.useVideo) { - dialog.videoStream = dialog.audioStream; - } - } //else conjure one TBD - - if (dialog.params.localTag) { - dialog.localVideo = document.getElementById(dialog.params.localTag); - } - - dialog.verto.dialogs[dialog.callID] = dialog; - - var RTCcallbacks = {}; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.params.display_direction === "outbound") { - dialog.params.remote_caller_id_name = dialog.params.caller_id_name; - dialog.params.remote_caller_id_number = dialog.params.caller_id_number; - } else { - dialog.params.remote_caller_id_name = dialog.params.callee_id_name; - dialog.params.remote_caller_id_number = dialog.params.callee_id_number; - } - - if (!dialog.params.remote_caller_id_name) { - dialog.params.remote_caller_id_name = "Nobody"; - } - - if (!dialog.params.remote_caller_id_number) { - dialog.params.remote_caller_id_number = "UNKNOWN"; - } - - RTCcallbacks.onMessage = function(rtc, msg) { - console.debug(msg); - }; - - RTCcallbacks.onAnswerSDP = function(rtc, sdp) { - console.error("answer sdp", sdp); - }; - } else { - dialog.params.remote_caller_id_name = "Outbound Call"; - dialog.params.remote_caller_id_number = dialog.params.destination_number; - } - - RTCcallbacks.onICESDP = function(rtc) { - console.log("RECV " + rtc.type + " SDP", rtc.mediaData.SDP); - - if (dialog.state == $.verto.enum.state.requesting || dialog.state == $.verto.enum.state.answering || dialog.state == $.verto.enum.state.active) { - location.reload(); - return; - } - - if (rtc.type == "offer") { - if (dialog.state == $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.requesting); - dialog.sendMethod("verto.attach", { - sdp: rtc.mediaData.SDP - }); - } else { - dialog.setState($.verto.enum.state.requesting); - - dialog.sendMethod("verto.invite", { - sdp: rtc.mediaData.SDP - }); - } - } else { //answer - dialog.setState($.verto.enum.state.answering); - - dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", { - sdp: dialog.rtc.mediaData.SDP - }); - } - }; - - RTCcallbacks.onICE = function(rtc) { - //console.log("cand", rtc.mediaData.candidate); - if (rtc.type == "offer") { - console.log("offer", rtc.mediaData.candidate); - return; - } - }; - - RTCcallbacks.onStream = function(rtc, stream) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onGranted === 'function') { - dialog.callbacks.permissionCallback.onGranted(stream); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onGranted === 'function'){ - dialog.verto.options.permissionCallback.onGranted(stream); - } - console.log("stream started"); - }; - - RTCcallbacks.onRemoteStream = function(rtc, stream) { - if (typeof dialog.callbacks.onRemoteStream === 'function') { - dialog.callbacks.onRemoteStream(stream, dialog); - } - console.log("remote stream started"); - }; - - RTCcallbacks.onError = function(e) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onDenied === 'function') { - dialog.callbacks.permissionCallback.onDenied(); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onDenied === 'function'){ - dialog.verto.options.permissionCallback.onDenied(); - } - console.error("ERROR:", e); - dialog.hangup({cause: "Device or Permission Error"}); - }; - - dialog.rtc = new $.FSRTC({ - callbacks: RTCcallbacks, - localVideo: dialog.screenShare ? null : dialog.localVideo, - useVideo: dialog.params.useVideo ? dialog.videoStream : null, - useAudio: dialog.audioStream, - useStereo: dialog.params.useStereo, - videoParams: dialog.params.videoParams, - audioParams: verto.options.audioParams, - iceServers: verto.options.iceServers, - screenShare: dialog.screenShare, - useCamera: dialog.useCamera, - useMic: dialog.useMic, - useSpeak: dialog.useSpeak, - turnServer: verto.options.turnServer, - useStream: dialog.params.useStream - }); - - dialog.rtc.verto = dialog.verto; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.attach) { - dialog.answer(); - } else { - dialog.ring(); - } - } - }; - - $.verto.dialog.prototype.invite = function() { - var dialog = this; - dialog.rtc.call(); - }; - - $.verto.dialog.prototype.sendMethod = function(method, obj) { - var dialog = this; - obj.dialogParams = {}; - - for (var i in dialog.params) { - if (i == "sdp" && method != "verto.invite" && method != "verto.attach") { - continue; - } - - if ((obj.noDialogParams && i != "callID")) { - continue; - } - - obj.dialogParams[i] = dialog.params[i]; - } - - delete obj.noDialogParams; - - dialog.verto.rpcClient.call(method, obj, - - function(e) { - /* Success */ - dialog.processReply(method, true, e); - }, - - function(e) { - /* Error */ - dialog.processReply(method, false, e); - }); - }; - - function checkStateChange(oldS, newS) { - - if (newS == $.verto.enum.state.purge || $.verto.enum.states[oldS.name][newS.name]) { - return true; - } - - return false; - } - - - // Attach audio output device to video element using device/sink ID. - function find_name(id) { - for (var i in $.verto.audioOutDevices) { - var source = $.verto.audioOutDevices[i]; - if (source.id === id) { - return(source.label); - } - } - - return id; - } - - $.verto.dialog.prototype.setAudioPlaybackDevice = function(sinkId, callback, arg) { - var dialog = this; - var element = dialog.audioStream; - - if (typeof element.sinkId !== 'undefined') { - var devname = find_name(sinkId); - console.info("Dialog: " + dialog.callID + " Setting speaker:", element, devname); - - element.setSinkId(sinkId) - .then(function() { - console.log("Dialog: " + dialog.callID + ' Success, audio output device attached: ' + sinkId); - if (callback) { - callback(true, devname, arg); - } - }) - .catch(function(error) { - var errorMessage = error; - if (error.name === 'SecurityError') { - errorMessage = "Dialog: " + dialog.callID + ' You need to use HTTPS for selecting audio output ' + - 'device: ' + error; - } - if (callback) { - callback(false, null, arg); - } - console.error(errorMessage); - }); - } else { - console.warn("Dialog: " + dialog.callID + ' Browser does not support output device selection.'); - if (callback) { - callback(false, null, arg); - } - } - } - - $.verto.dialog.prototype.setState = function(state) { - var dialog = this; - - if (dialog.state == $.verto.enum.state.ringing) { - dialog.stopRinging(); - } - - if (dialog.state == state || !checkStateChange(dialog.state, state)) { - console.error("Dialog " + dialog.callID + ": INVALID state change from " + dialog.state.name + " to " + state.name); - dialog.hangup(); - return false; - } - - console.log("Dialog " + dialog.callID + ": state change from " + dialog.state.name + " to " + state.name); - - dialog.lastState = dialog.state; - dialog.state = state; - - if (dialog.callbacks.onDialogState) { - dialog.callbacks.onDialogState(this); - } - - switch (dialog.state) { - - case $.verto.enum.state.early: - case $.verto.enum.state.active: - - var speaker = dialog.useSpeak; - console.info("Using Speaker: ", speaker); - - if (speaker && speaker !== "any" && speaker !== "none") { - setTimeout(function() { - dialog.setAudioPlaybackDevice(speaker); - }, 500); - } - - break; - - case $.verto.enum.state.trying: - setTimeout(function() { - if (dialog.state == $.verto.enum.state.trying) { - dialog.setState($.verto.enum.state.hangup); - } - }, 30000); - break; - case $.verto.enum.state.purge: - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.hangup: - - if (dialog.lastState.val > $.verto.enum.state.requesting.val && dialog.lastState.val < $.verto.enum.state.hangup.val) { - dialog.sendMethod("verto.bye", {}); - } - - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.destroy: - - if (typeof(dialog.verto.options.tag) === "function") { - $('#' + dialog.params.tag).remove(); - } - - delete dialog.verto.dialogs[dialog.callID]; - if (dialog.params.screenShare) { - dialog.rtc.stopPeer(); - } else { - dialog.rtc.stop(); - } - break; - } - - return true; - }; - - $.verto.dialog.prototype.processReply = function(method, success, e) { - var dialog = this; - - //console.log("Response: " + method + " State:" + dialog.state.name, success, e); - - switch (method) { - - case "verto.answer": - case "verto.attach": - if (success) { - dialog.setState($.verto.enum.state.active); - } else { - dialog.hangup(); - } - break; - case "verto.invite": - if (success) { - dialog.setState($.verto.enum.state.trying); - } else { - dialog.setState($.verto.enum.state.destroy); - } - break; - - case "verto.bye": - dialog.hangup(); - break; - - case "verto.modify": - if (e.holdState) { - if (e.holdState == "held") { - if (dialog.state != $.verto.enum.state.held) { - dialog.setState($.verto.enum.state.held); - } - } else if (e.holdState == "active") { - if (dialog.state != $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.active); - } - } - } - - if (success) {} - - break; - - default: - break; - } - - }; - - $.verto.dialog.prototype.hangup = function(params) { - var dialog = this; - - if (params) { - if (params.causeCode) { - dialog.causeCode = params.causeCode; - } - - if (params.cause) { - dialog.cause = params.cause; - } - } - - if (!dialog.cause && !dialog.causeCode) { - dialog.cause = "NORMAL_CLEARING"; - } - - if (dialog.state.val >= $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) { - dialog.setState($.verto.enum.state.hangup); - } else if (dialog.state.val < $.verto.enum.state.destroy) { - dialog.setState($.verto.enum.state.destroy); - } - }; - - $.verto.dialog.prototype.stopRinging = function() { - var dialog = this; - if (dialog.verto.ringer) { - dialog.verto.ringer.stop(); - } - }; - - $.verto.dialog.prototype.indicateRing = function() { - var dialog = this; - - if (dialog.verto.ringer) { - dialog.verto.ringer.attr("src", dialog.verto.options.ringFile)[0].play(); - - setTimeout(function() { - dialog.stopRinging(); - if (dialog.state == $.verto.enum.state.ringing) { - dialog.indicateRing(); - } - }, - dialog.verto.options.ringSleep); - } - }; - - $.verto.dialog.prototype.ring = function() { - var dialog = this; - - dialog.setState($.verto.enum.state.ringing); - dialog.indicateRing(); - }; - - $.verto.dialog.prototype.useVideo = function(on) { - var dialog = this; - - dialog.params.useVideo = on; - - if (on) { - dialog.videoStream = dialog.audioStream; - } else { - dialog.videoStream = null; - } - - dialog.rtc.useVideo(dialog.videoStream, dialog.localVideo); - - }; - - $.verto.dialog.prototype.setMute = function(what) { - var dialog = this; - return dialog.rtc.setMute(what); - }; - - $.verto.dialog.prototype.getMute = function() { - var dialog = this; - return dialog.rtc.getMute(); - }; - - $.verto.dialog.prototype.setVideoMute = function(what) { - var dialog = this; - return dialog.rtc.setVideoMute(what); - }; - - $.verto.dialog.prototype.getVideoMute = function() { - var dialog = this; - return dialog.rtc.getVideoMute(); - }; - - $.verto.dialog.prototype.useStereo = function(on) { - var dialog = this; - - dialog.params.useStereo = on; - dialog.rtc.useStereo(on); - }; - - $.verto.dialog.prototype.dtmf = function(digits) { - var dialog = this; - if (digits) { - dialog.sendMethod("verto.info", { - dtmf: digits - }); - } - }; - - $.verto.dialog.prototype.rtt = function(obj) { - var dialog = this; - var pobj = {}; - - if (!obj) { - return false; - } - - pobj.code = obj.code; - pobj.chars = obj.chars; - - - if (pobj.chars || pobj.code) { - dialog.sendMethod("verto.info", { - txt: obj, - noDialogParams: true - }); - } - }; - - $.verto.dialog.prototype.transfer = function(dest, params) { - var dialog = this; - if (dest) { - dialog.sendMethod("verto.modify", { - action: "transfer", - destination: dest, - params: params - }); - } - }; - - $.verto.dialog.prototype.replace = function(replaceCallID, params) { - var dialog = this; - if (replaceCallID) { - dialog.sendMethod("verto.modify", { - action: "replace", - replaceCallID: replaceCallID, - params: params - }); - } - }; - - $.verto.dialog.prototype.hold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "hold", - params: params - }); - }; - - $.verto.dialog.prototype.unhold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "unhold", - params: params - }); - }; - - $.verto.dialog.prototype.toggleHold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "toggleHold", - params: params - }); - }; - - $.verto.dialog.prototype.message = function(msg) { - var dialog = this; - var err = 0; - - msg.from = dialog.params.login; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - dialog.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.dialog.prototype.answer = function(params) { - var dialog = this; - - if (!dialog.answered) { - if (!params) { - params = {}; - } - - params.sdp = dialog.params.sdp; - - if (params) { - if (params.useVideo) { - dialog.useVideo(true); - } - dialog.params.callee_id_name = params.callee_id_name; - dialog.params.callee_id_number = params.callee_id_number; - - if (params.useCamera) { - dialog.useCamera = params.useCamera; - } - - if (params.useMic) { - dialog.useMic = params.useMic; - } - - if (params.useSpeak) { - dialog.useSpeak = params.useSpeak; - } - } - - dialog.rtc.createAnswer(params); - dialog.answered = true; - } - }; - - $.verto.dialog.prototype.handleAnswer = function(params) { - var dialog = this; - - dialog.gotAnswer = true; - - if (dialog.state.val >= $.verto.enum.state.active.val) { - return; - } - - if (dialog.state.val >= $.verto.enum.state.early.val) { - dialog.setState($.verto.enum.state.active); - } else { - if (dialog.gotEarly) { - console.log("Dialog " + dialog.callID + " Got answer while still establishing early media, delaying..."); - } else { - console.log("Dialog " + dialog.callID + " Answering Channel"); - dialog.rtc.answer(params.sdp, function() { - dialog.setState($.verto.enum.state.active); - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); - } - } - - - }; - - $.verto.dialog.prototype.cidString = function(enc) { - var dialog = this; - var party = dialog.params.remote_caller_id_name + (enc ? " <" : " <") + dialog.params.remote_caller_id_number + (enc ? ">" : ">"); - return party; - }; - - $.verto.dialog.prototype.sendMessage = function(msg, params) { - var dialog = this; - - if (dialog.callbacks.onMessage) { - dialog.callbacks.onMessage(dialog.verto, dialog, msg, params); - } - }; - - $.verto.dialog.prototype.handleInfo = function(params) { - var dialog = this; - - dialog.sendMessage($.verto.enum.message.info, params); - - }; - - $.verto.dialog.prototype.handleDisplay = function(params) { - var dialog = this; - - if (params.display_name) { - dialog.params.remote_caller_id_name = params.display_name; - } - if (params.display_number) { - dialog.params.remote_caller_id_number = params.display_number; - } - - dialog.sendMessage($.verto.enum.message.display, {}); - }; - - $.verto.dialog.prototype.handleMedia = function(params) { - var dialog = this; - - if (dialog.state.val >= $.verto.enum.state.early.val) { - return; - } - - dialog.gotEarly = true; - - dialog.rtc.answer(params.sdp, function() { - console.log("Dialog " + dialog.callID + "Establishing early media"); - dialog.setState($.verto.enum.state.early); - - if (dialog.gotAnswer) { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.setState($.verto.enum.state.active); - } - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "EARLY SDP", params.sdp); - }; - - $.verto.ENUM = function(s) { - var i = 0, - o = {}; - s.split(" ").map(function(x) { - o[x] = { - name: x, - val: i++ - }; - }); - return Object.freeze(o); - }; - - $.verto.enum = {}; - - $.verto.enum.states = Object.freeze({ - new: { - requesting: 1, - recovering: 1, - ringing: 1, - destroy: 1, - answering: 1, - hangup: 1 - }, - requesting: { - trying: 1, - hangup: 1, - active: 1 - }, - recovering: { - answering: 1, - hangup: 1 - }, - trying: { - active: 1, - early: 1, - hangup: 1 - }, - ringing: { - answering: 1, - hangup: 1 - }, - answering: { - active: 1, - hangup: 1 - }, - active: { - answering: 1, - requesting: 1, - hangup: 1, - held: 1 - }, - held: { - hangup: 1, - active: 1 - }, - early: { - hangup: 1, - active: 1 - }, - hangup: { - destroy: 1 - }, - destroy: {}, - purge: { - destroy: 1 - } - }); - - $.verto.enum.state = $.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge"); - $.verto.enum.direction = $.verto.ENUM("inbound outbound"); - $.verto.enum.message = $.verto.ENUM("display info pvtEvent clientReady"); - - $.verto.enum = Object.freeze($.verto.enum); - - $.verto.saved = []; - - $.verto.unloadJobs = []; - - var unloadEventName = 'beforeunload'; - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - if (iOS) { - unloadEventName = 'pagehide'; - } - - $(window).bind(unloadEventName, function() { - for (var f in $.verto.unloadJobs) { - $.verto.unloadJobs[f](); - } - - if ($.verto.haltClosure) - return $.verto.haltClosure(); - - for (var i in $.verto.saved) { - var verto = $.verto.saved[i]; - if (verto) { - verto.purge(); - verto.logout(); - } - } - - return $.verto.warnOnUnload; - }); - - $.verto.videoDevices = []; - $.verto.audioInDevices = []; - $.verto.audioOutDevices = []; - - var checkDevices = function(runtime) { - console.info("enumerating devices"); - var aud_in = [], aud_out = [], vid = []; - var has_video = 0, has_audio = 0; - var Xstream; - - function gotDevices(deviceInfos) { - // Handles being called several times to update labels. Preserve values. - for (var i = 0; i !== deviceInfos.length; ++i) { - var deviceInfo = deviceInfos[i]; - var text = ""; - - console.log(deviceInfo); - console.log(deviceInfo.kind + ": " + deviceInfo.label + " id = " + deviceInfo.deviceId); - - if (deviceInfo.kind === 'audioinput') { - text = deviceInfo.label || 'microphone ' + (aud_in.length + 1); - aud_in.push({id: deviceInfo.deviceId, kind: "audio_in", label: text}); - } else if (deviceInfo.kind === 'audiooutput') { - text = deviceInfo.label || 'speaker ' + (aud_out.length + 1); - aud_out.push({id: deviceInfo.deviceId, kind: "audio_out", label: text}); - } else if (deviceInfo.kind === 'videoinput') { - text = deviceInfo.label || 'camera ' + (vid.length + 1); - vid.push({id: deviceInfo.deviceId, kind: "video", label: text}); - } else { - console.log('Some other kind of source/device: ', deviceInfo); - } - } - - - $.verto.videoDevices = vid; - $.verto.audioInDevices = aud_in; - $.verto.audioOutDevices = aud_out; - - console.info("Audio IN Devices", $.verto.audioInDevices); - console.info("Audio Out Devices", $.verto.audioOutDevices); - console.info("Video Devices", $.verto.videoDevices); - - if (Xstream) { - Xstream.getTracks().forEach(function(track) {track.stop();}); - } - - if (runtime) { - runtime(true); - } - } - - - - - function handleError(error) { - console.log('device enumeration error: ', error); - if (runtime) runtime(false); - } - - - function checkTypes(devs) { - for (var i = 0; i !== devs.length; ++i) { - - if (devs[i].kind === 'audioinput') { - has_audio++; - } else if (devs[i].kind === 'videoinput') { - has_video++; - } - } - - navigator.getUserMedia({ audio: (has_audio > 0 ? true : false), video: (has_video > 0 ? true : false)}, - function(stream) { - Xstream = stream; - navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError); - }, - function(err) { - console.log("The following error occurred: " + err.name); - } - ); - } - - navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError); - - }; - - $.verto.refreshDevices = function(runtime) { - checkDevices(runtime); - } - - $.verto.init = function(obj, runtime) { - if (!obj) { - obj = {}; - } - - if (!obj.skipPermCheck && !obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - checkDevices(runtime); - }, true, true); - } else if (obj.skipPermCheck && !obj.skipDeviceCheck) { - checkDevices(runtime); - } else if (!obj.skipPermCheck && obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - runtime(status); - }, true, true); - } else { - runtime(null); - } - - } - - $.verto.genUUID = function () { - return generateGUID(); - } - - -})(jQuery); -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -function maybeAddCandidate(iceTransport, candidate) { - // Edge's internal representation adds some fields therefore - // not all fieldѕ are taken into account. - var alreadyAdded = iceTransport.getRemoteCandidates() - .find(function(remoteCandidate) { - return candidate.foundation === remoteCandidate.foundation && - candidate.ip === remoteCandidate.ip && - candidate.port === remoteCandidate.port && - candidate.priority === remoteCandidate.priority && - candidate.protocol === remoteCandidate.protocol && - candidate.type === remoteCandidate.type; - }); - if (!alreadyAdded) { - iceTransport.addRemoteCandidate(candidate); - } - return !alreadyAdded; -} - - -// https://w3c.github.io/mediacapture-main/#mediastream -// Helper function to add the track to the stream and -// dispatch the event ourselves. -function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); -} - -function makeError(name, description) { - var e = new Error(description); - e.name = name; - return e; -} - -module.exports = function(window, edgeVersion) { - var RTCPeerConnection = function(config) { - var pc = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - pc[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.canTrickleIceCandidates = null; - - this.needNegotiation = false; - - this.localStreams = []; - this.remoteStreams = []; - - this.localDescription = null; - this.remoteDescription = null; - - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - config = JSON.parse(JSON.stringify(config || {})); - - this.usingBundle = config.bundlePolicy === 'max-bundle'; - if (config.rtcpMuxPolicy === 'negotiate') { - throw(makeError('NotSupportedError', - 'rtcpMuxPolicy \'negotiate\' is not supported')); - } else if (!config.rtcpMuxPolicy) { - config.rtcpMuxPolicy = 'require'; - } - - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - break; - default: - config.iceTransportPolicy = 'all'; - break; - } - - switch (config.bundlePolicy) { - case 'balanced': - case 'max-compat': - case 'max-bundle': - break; - default: - config.bundlePolicy = 'balanced'; - break; - } - - config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); - - this._iceGatherers = []; - if (config.iceCandidatePoolSize) { - for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers = new window.RTCIceGatherer({ - iceServers: config.iceServers, - gatherPolicy: config.iceTransportPolicy - }); - } - } else { - config.iceCandidatePoolSize = 0; - } - - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - this._sdpSessionVersion = 0; - - this._dtlsRole = undefined; // role for a=setup to use in answers. - - this._isClosed = false; - }; - - // set up event handlers on prototype - RTCPeerConnection.prototype.onicecandidate = null; - RTCPeerConnection.prototype.onaddstream = null; - RTCPeerConnection.prototype.ontrack = null; - RTCPeerConnection.prototype.onremovestream = null; - RTCPeerConnection.prototype.onsignalingstatechange = null; - RTCPeerConnection.prototype.oniceconnectionstatechange = null; - RTCPeerConnection.prototype.onicegatheringstatechange = null; - RTCPeerConnection.prototype.onnegotiationneeded = null; - RTCPeerConnection.prototype.ondatachannel = null; - - RTCPeerConnection.prototype._dispatchEvent = function(name, event) { - if (this._isClosed) { - return; - } - this.dispatchEvent(event); - if (typeof this['on' + name] === 'function') { - this['on' + name](event); - } - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this._dispatchEvent('icegatheringstatechange', event); - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - RTCPeerConnection.prototype.getLocalStreams = function() { - return this.localStreams; - }; - - RTCPeerConnection.prototype.getRemoteStreams = function() { - return this.remoteStreams; - }; - - // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - associatedRemoteMediaStreams: [], - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - this.transceivers.push(transceiver); - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - var alreadyExists = this.transceivers.find(function(s) { - return s.track === track; - }); - - if (alreadyExists) { - throw makeError('InvalidAccessError', 'Track already exists.'); - } - - if (this.signalingState === 'closed') { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - this._maybeFireNegotiationNeeded(); - - if (this.localStreams.indexOf(stream) === -1) { - this.localStreams.push(stream); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - if (edgeVersion >= 15025) { - stream.getTracks().forEach(function(track) { - pc.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - pc.addTrack(track, clonedStream); - }); - } - }; - - RTCPeerConnection.prototype.removeTrack = function(sender) { - if (!(sender instanceof window.RTCRtpSender)) { - throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.'); - } - - var transceiver = this.transceivers.find(function(t) { - return t.rtpSender === sender; - }); - - if (!transceiver) { - throw makeError('InvalidAccessError', - 'Sender was not created by this connection.'); - } - var stream = transceiver.stream; - - transceiver.rtpSender.stop(); - transceiver.rtpSender = null; - transceiver.track = null; - transceiver.stream = null; - - // remove the stream from the set of local streams - var localStreams = this.transceivers.map(function(t) { - return t.stream; - }); - if (localStreams.indexOf(stream) === -1 && - this.localStreams.indexOf(stream) > -1) { - this.localStreams.splice(this.localStreams.indexOf(stream), 1); - } - - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - stream.getTracks().forEach(function(track) { - var sender = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (sender) { - pc.removeTrack(sender); - } - }); - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - - RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, - usingBundle) { - var pc = this; - if (usingBundle && sdpMLineIndex > 0) { - return this.transceivers[0].iceGatherer; - } else if (this._iceGatherers.length) { - return this._iceGatherers.shift(); - } - var iceGatherer = new window.RTCIceGatherer({ - iceServers: this._config.iceServers, - gatherPolicy: this._config.iceTransportPolicy - }); - Object.defineProperty(iceGatherer, 'state', - {value: 'new', writable: true} - ); - - this.transceivers[sdpMLineIndex].candidates = []; - this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].candidates !== null) { - pc.transceivers[sdpMLineIndex].candidates.push(event.candidate); - } - }; - iceGatherer.addEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - return iceGatherer; - }; - - // start gathering from an RTCIceGatherer. - RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { - var pc = this; - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer.onlocalcandidate) { - return; - } - var candidates = this.transceivers[sdpMLineIndex].candidates; - this.transceivers[sdpMLineIndex].candidates = null; - iceGatherer.removeEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - iceGatherer.onlocalcandidate = function(evt) { - if (pc.usingBundle && sdpMLineIndex > 0) { - // if we know that we use bundle we can drop candidates with - // ѕdpMLineIndex > 0. If we don't do this then our state gets - // confused since we dispose the extra ice gatherer. - return; - } - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - // Edge emits an empty object for RTCIceCandidateComplete‥ - var end = !cand || Object.keys(cand).length === 0; - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { - iceGatherer.state = 'completed'; - } - } else { - if (iceGatherer.state === 'new') { - iceGatherer.state = 'gathering'; - } - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(pc.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - pc.localDescription.sdp = sections.join(''); - var complete = pc.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - if (pc.iceGatheringState !== 'gathering') { - pc.iceGatheringState = 'gathering'; - pc._emitGatheringStateChange(); - } - - // Emit candidate. Also emit null candidate when all gatherers are - // complete. - if (!end) { - pc._dispatchEvent('icecandidate', event); - } - if (complete) { - pc._dispatchEvent('icecandidate', new Event('icecandidate')); - pc.iceGatheringState = 'complete'; - pc._emitGatheringStateChange(); - } - }; - - // emit already gathered candidates. - window.setTimeout(function() { - candidates.forEach(function(candidate) { - var e = new Event('RTCIceGatherEvent'); - e.candidate = candidate; - iceGatherer.onlocalcandidate(e); - }); - }, 0); - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var pc = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - pc._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - pc._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itpc. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - pc._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - if (transceiver.recvEncodingParameters.length) { - params.encodings = transceiver.recvEncodingParameters; - } - params.rtcp = { - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.rtcpParameters.cname) { - params.rtcp.cname = transceiver.rtcpParameters.cname; - } - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set local ' + description.type + - ' in state ' + pc.signalingState)); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - pc.transceivers[sdpMLineIndex].localCapabilities = caps; - }); - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - pc._gather(transceiver.mid, sdpMLineIndex); - }); - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = pc.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!pc.usingBundle || sdpMLineIndex === 0) { - pc._gather(transceiver.mid, sdpMLineIndex); - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - pc._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set remote ' + description.type + - ' in state ' + pc.signalingState)); - } - - var streams = {}; - this.remoteStreams.forEach(function(stream) { - streams[stream.id] = stream; - }); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - this.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { - pc.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - pc.transceivers[sdpMLineIndex]) { - pc._disposeIceAndDtlsTransports(sdpMLineIndex); - pc.transceivers[sdpMLineIndex].iceGatherer = - pc.transceivers[0].iceGatherer; - pc.transceivers[sdpMLineIndex].iceTransport = - pc.transceivers[0].iceTransport; - pc.transceivers[sdpMLineIndex].dtlsTransport = - pc.transceivers[0].dtlsTransport; - if (pc.transceivers[sdpMLineIndex].rtpSender) { - pc.transceivers[sdpMLineIndex].rtpSender.setTransport( - pc.transceivers[0].dtlsTransport); - } - if (pc.transceivers[sdpMLineIndex].rtpReceiver) { - pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - pc.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex] || - pc._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - usingBundle); - } - - if (cands.length && transceiver.iceTransport.state === 'new') { - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - var isNewTrack = false; - if (direction === 'sendrecv' || direction === 'sendonly') { - isNewTrack = !transceiver.rtpReceiver; - rtpReceiver = transceiver.rtpReceiver || - new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); - - if (isNewTrack) { - var stream; - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid && remoteMsid.stream === '-') { - // no-op. a stream id of '-' means: no associated stream. - } else if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - stream = streams[remoteMsid.stream]; - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - stream = streams.default; - } - if (stream) { - addTrackToStreamAndFireEvent(track, stream); - transceiver.associatedRemoteMediaStreams.push(stream); - } - receiverList.push([track, rtpReceiver, stream]); - } - } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { - transceiver.associatedRemoteMediaStreams.forEach(function(s) { - var nativeTrack = s.getTracks().find(function(t) { - return t.id === transceiver.rtpReceiver.track.id; - }); - if (nativeTrack) { - removeTrackFromStreamAndFireEvent(nativeTrack, s); - } - }); - transceiver.associatedRemoteMediaStreams = []; - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - pc._transceive(pc.transceivers[sdpMLineIndex], - false, - isNewTrack); - } else if (description.type === 'answer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - pc.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - pc.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (cands.length && iceTransport.state === 'new') { - if ((isIceLite || isComplete) && - (!usingBundle || sdpMLineIndex === 0)) { - iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - if (!usingBundle || sdpMLineIndex === 0) { - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - pc._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams.default); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - if (this._dtlsRole === undefined) { - this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; - } - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - if (pc.remoteStreams.indexOf(stream) === -1) { - pc.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - window.setTimeout(function() { - pc._dispatchEvent('addstream', event); - }); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - fireAddTrack(pc, track, receiver, [stream]); - }); - } - }); - receiverList.forEach(function(item) { - if (item[2]) { - return; - } - fireAddTrack(pc, item[0], item[1], []); - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(pc && pc.transceivers)) { - return; - } - pc.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._isClosed = true; - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this._dispatchEvent('signalingstatechange', event); - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var pc = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (pc.needNegotiation === false) { - return; - } - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); - }, 0); - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== this.iceConnectionState) { - this.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this._dispatchEvent('iceconnectionstatechange', event); - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createOffer after close')); - } - - var numAudioTracks = this.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = this.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - var offerOptions = arguments[0]; - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - this.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - this._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - this._createTransceiver('video'); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - pc.usingBundle); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video' && - !sendEncodingParameters[0].rtx) { - sendEncodingParameters[0].rtx = { - ssrc: sendEncodingParameters[0].ssrc + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, kind); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += writeMediaSection(transceiver, transceiver.localCapabilities, - 'offer', transceiver.stream, pc._dtlsRole); - sdp += 'a=rtcp-rsize\r\n'; - - if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && - (sdpMLineIndex === 0 || !pc.usingBundle)) { - transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { - cand.component = 1; - sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; - }); - - if (transceiver.iceGatherer.state === 'completed') { - sdp += 'a=end-of-candidates\r\n'; - } - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer after close')); - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - var mediaSectionsInOffer = SDPUtils.splitSections( - this.remoteDescription.sdp).length - 1; - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (sdpMLineIndex + 1 > mediaSectionsInOffer) { - return; - } - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video' && - !transceiver.sendEncodingParameters[0].rtx) { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream, pc._dtlsRole); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - var sections; - if (!candidate || candidate.candidate === '') { - for (var j = 0; j < this.transceivers.length; j++) { - if (this.transceivers[j].isDatachannel) { - continue; - } - this.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[j + 1] += 'a=end-of-candidates\r\n'; - this.remoteDescription.sdp = sections.join(''); - if (this.usingBundle) { - break; - } - } - } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { - throw new TypeError('sdpMLineIndex or sdpMid required'); - } else if (!this.remoteDescription) { - return Promise.reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.isDatachannel) { - return Promise.resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return Promise.resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== this.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); - } - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[sdpMLineIndex + 1] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } else { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - resolve(results); - }); - }); - }; - - // legacy callback shims. Should be moved to adapter.js some days. - var methods = ['createOffer', 'createAnswer']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[0] === 'function' || - typeof args[1] === 'function') { // legacy - return nativeMethod.apply(this, [arguments[2]]) - .then(function(description) { - if (typeof args[0] === 'function') { - args[0].apply(null, [description]); - } - }, function(error) { - if (typeof args[1] === 'function') { - args[1].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function' || - typeof args[2] === 'function') { // legacy - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }, function(error) { - if (typeof args[2] === 'function') { - args[2].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // getStats is special. It doesn't have a spec legacy method yet we support - // getStats(something, cb) without error callbacks. - ['getStats'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function') { - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - return RTCPeerConnection; -}; - -},{"sdp":2}],2:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - case 'ufrag': - candidate.ufrag = parts[i + 1]; // for backward compability. - candidate.usernameFragment = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr - sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.split(' '); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } - }; - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -SDPUtils.parseMLine = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return { - kind: mline[0].substr(2), - port: parseInt(mline[1], 10), - protocol: mline[2], - fmt: mline.slice(3).join(' ') - }; -}; - -// Expose public methods. -if (typeof module === 'object') { - module.exports = SDPUtils; -} - -},{}],3:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":4}],4:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var utils = require('./utils'); -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - var commonShim = require('./common_shim') || null; - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - commonShim.shimCreateObjectURL(window); - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - commonShim.shimCreateObjectURL(window); - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - commonShim.shimCreateObjectURL(window); - - edgeShim.shimGetUserMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - commonShim.shimCreateObjectURL(window); - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimCreateOfferLegacy(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){ - -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - } - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } else if (!('RTCRtpTransceiver' in window)) { - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - if (!e.transceiver) { - e.transceiver = {receiver: e.receiver}; - } - return e; - }); - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrackWithNative: function(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function(streamId) { - return pc._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - var existingSenders = pc.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = pc.getSenders().filter(function(newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function(streamId) { - var idx = pc._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - pc._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (pc._shimmedLocalStreams[streamId].length === 1) { - delete pc._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; - }, - - shimAddTrackRemoveTrack: function(window) { - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && - browserDetails.version >= 65) { - return this.shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - var nativeStreams = origGetLocalStreams.apply(this); - pc._reverseStreams = pc._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return pc._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function() { - pc.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), - externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), - internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - var args = arguments; - var isLegacyCall = arguments.length && - typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(pc, [ - function(description) { - var desc = replaceInternalStreamId(pc, description); - args[0].apply(null, [desc]); - }, - function(err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2] - ]); - } - return nativeMethod.apply(pc, arguments) - .then(function(description) { - return replaceInternalStreamId(pc, description); - }); - }; - }); - - var origSetLocalDescription = - window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function() { - var pc = this; - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(pc, arguments); - } - arguments[0] = replaceExternalStreamId(pc, arguments[0]); - return origSetLocalDescription.apply(pc, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor( - window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, - 'localDescription', { - get: function() { - var pc = this; - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(pc, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(pc._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var pc = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(pc, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var pc = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof arguments[0] === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - -},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - var constraintsToChrome_ = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - InvalidStateError: 'NotReadableError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotReadableError', - MediaDeviceKillSwitchOn: 'NotReadableError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return getUserMediaPromise_(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":13}],7:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var utils = require('./utils'); - -module.exports = { - shimRTCIceCandidate: function(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (window.RTCIceCandidate && 'foundation' in - window.RTCIceCandidate.prototype) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function(args) { - // Remove the a= which shouldn't be part of the candidate string. - if (typeof args === 'object' && args.candidate && - args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = SDPUtils.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, - parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment, - }; - }; - return augmentedCandidate; - }; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype && - URL.createObjectURL && URL.revokeObjectURL)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - }, - - shimMaxMessageSize: function(window) { - if (window.RTCSctpTransport || !window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function(description) { - var sections = SDPUtils.splitSections(description.sdp); - sections.shift(); - return sections.some(function(mediaSection) { - var mLine = SDPUtils.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' - && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = - browserDetails.version === 57 ? 65535 : 65536; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' - && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && - remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - pc._sctp = null; - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function() { - return maxMessageSize; - } - }); - pc._sctp = sctp; - } - - return origSetRemoteDescription.apply(pc, arguments); - }; - }, - - shimSendThrowTypeError: function(window) { - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - var origCreateDataChannel = - window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function() { - var pc = this; - var dataChannel = origCreateDataChannel.apply(pc, arguments); - var origDataChannelSend = dataChannel.send; - - // Patch 'send' method - dataChannel.send = function() { - var dc = this; - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (length > pc.sctp.maxMessageSize) { - throw new DOMException('Message too large (can send a maximum of ' + - pc.sctp.maxMessageSize + ' bytes)', 'TypeError'); - } - return origDataChannelSend.apply(dc, arguments); - }; - - return dataChannel; - }; - } -}; - -},{"./utils":13,"sdp":2}],8:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var shimRTCPeerConnection = require('rtcpeerconnection-shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - - window.RTCPeerConnection = - shimRTCPeerConnection(window, browserDetails.version); - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.transceiver = {receiver: event.receiver}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - if (typeof window === 'object' && window.RTCTrackEvent && - ('receiver' in window.RTCTrackEvent.prototype) && - !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - }, - - shimRemoveStream: function(window) { - if (!window.RTCPeerConnection || - 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function(sender) { - if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } -}; - -},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var getUserMedia_ = function(constraints, onSuccess, onError) { - var constraintsToFF37_ = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r. min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":13}],12:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; -var utils = require('../utils'); - -module.exports = { - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var pc = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(pc, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - return _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var pc = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - var pc = this; - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - e.streams.forEach(function(stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in window.RTCPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - }, - shimTrackEventTransceiver: function(window) { - // Add event.transceiver member over deprecated event.receiver - if (typeof window === 'object' && window.RTCPeerConnection && - ('receiver' in window.RTCTrackEvent.prototype) && - // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is - // defined for some reason even when window.RTCTransceiver is not. - !window.RTCTransceiver) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimCreateOfferLegacy: function(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { - var pc = this; - if (offerOptions) { - var audioTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && - !audioTransceiver) { - pc.addTransceiver('audio'); - } - - var videoTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - videoTransceiver.setDirection('sendonly'); - } else if (videoTransceiver.direction === 'recvonly') { - videoTransceiver.setDirection('inactive'); - } - } else if (offerOptions.offerToReceiveVideo === true && - !videoTransceiver) { - pc.addTransceiver('video'); - } - } - return origCreateOffer.apply(pc, arguments); - }; - } -}; - -},{"../utils":13}],13:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object. -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function(e) { - cb(wrapper(e)); - }; - this._eventMap = this._eventMap || {}; - this._eventMap[cb] = wrappedCallback; - return nativeAddEventListener.apply(this, [nativeEventName, - wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap - || !this._eventMap[cb]) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[cb]; - delete this._eventMap[cb]; - return nativeRemoveEventListener.apply(this, [nativeEventName, - unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function() { - return this['_on' + eventNameToWrap]; - }, - set: function(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, - this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, - this['_on' + eventNameToWrap] = cb); - } - } - }); -} - -// Utility methods. -module.exports = { - extractVersion: extractVersion, - wrapPeerConnectionEvent: wrapPeerConnectionEvent, - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - if (navigator.mozGetUserMedia) { // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -},{}]},{},[3])(3) -}); \ No newline at end of file +(function($){function findLine(sdpLines,prefix,substr){return findLineInRange(sdpLines,0,-1,prefix,substr);} +function findLineInRange(sdpLines,startLine,endLine,prefix,substr){var realEndLine=(endLine!=-1)?endLine:sdpLines.length;for(var i=startLine;i=0;if(iOS){self.options.useVideo.setAttribute("playsinline",true);}} +var element=self.options.useAudio;console.log("REMOTE STREAM",stream,element);FSRTCattachMediaStream(element,stream);self.remoteStream=stream;onRemoteStreamSuccess(self,stream);} +function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");} +$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stopPeer=function(){if(self.peer){console.log("stopping peer");self.peer.stop();}} +$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';self.options.useVideo['src']='';} +if(self.localStream&&!self.options.useStream){if(typeof self.localStream.stop=='function'){self.localStream.stop();}else{if(self.localStream.active){var tracks=self.localStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}} +self.localStream=null;} +if(self.options.localVideo){deactivateLocalVideo(self.options.localVideo);} +if(self.options.localVideoStream&&!self.options.useStream){if(typeof self.options.localVideoStream.stop=='function'){self.options.localVideoStream.stop();}else{if(self.options.localVideoStream.active){var tracks=self.options.localVideoStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}}} +if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.getMute=function(){var self=this;return self.audioEnabled;} +$.FSRTC.prototype.setMute=function(what){var self=this;if(!self.localStream){return false;} +var audioTracks=self.localStream.getAudioTracks();for(var i=0,len=audioTracks.length;i=w&&$.FSRTC.validRes[i][1]>=h){w=$.FSRTC.validRes[i][0];h=$.FSRTC.validRes[i][1];}} +return[w,h];} +var resList=[[160,120],[320,180],[320,240],[640,360],[640,480],[1280,720],[1920,1080]];var resI=0;var ttl=0;var checkRes=function(cam,func){if(resI>=resList.length){var res={'validRes':$.FSRTC.validRes,'bestResSupported':$.FSRTC.bestResSupported()};localStorage.setItem("res_"+cam,$.toJSON(res));if(func)return func(res);return;} +w=resList[resI][0];h=resList[resI][1];resI++;var video={width:{exact:w},height:{exact:h}};if(cam!=="any"){video=assignMediaIdToConstraint(cam,video);} +getUserMedia({constraints:{audio:ttl++==0,video:video},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info(w+"x"+h+" supported.");$.FSRTC.validRes.push([w,h]);checkRes(cam,func);},onerror:function(e){console.warn(w+"x"+h+" not supported.");checkRes(cam,func);}});} +$.FSRTC.getValidRes=function(cam,func){var used=[];var cached=localStorage.getItem("res_"+cam);if(cached){var cache=$.parseJSON(cached);if(cache){$.FSRTC.validRes=cache.validRes;console.log("CACHED RES FOR CAM "+cam,cache);}else{console.error("INVALID CACHE");} +return func?func(cache):null;} +$.FSRTC.validRes=[];resI=0;checkRes(cam,func);} +$.FSRTC.checkPerms=function(runtime,check_audio,check_video){getUserMedia({constraints:{audio:check_audio,video:check_video,},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info("media perm init complete");if(runtime){setTimeout(runtime,100,true);}},onerror:function(e){if(check_video&&check_audio){console.error("error, retesting with audio params only");return $.FSRTC.checkPerms(runtime,check_audio,false);} +console.error("media perm init error");if(runtime){runtime(false)}}});}})(jQuery);(function($){$.JsonRpcClient=function(options){var self=this;this.options=$.extend({ajaxUrl:null,socketUrl:null,onmessage:null,login:null,passwd:null,sessid:null,loginParams:null,userVariables:null,getSocket:function(onmessage_cb){return self._getSocket(onmessage_cb);}},options);self.ws_cnt=0;this.wsOnMessage=function(event){self._wsOnMessage(event);};};$.JsonRpcClient.prototype._ws_socket=null;$.JsonRpcClient.prototype._ws_callbacks={};$.JsonRpcClient.prototype._current_id=1;$.JsonRpcClient.prototype.speedTest=function(bytes,cb){var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this.speedCB=cb;this.speedBytes=bytes;socket.send("#SPU "+bytes);var loops=bytes/1024;var rem=bytes%1024;var i;var data=new Array(1024).join(".");for(i=0;i1){return false;} +return true;};$.JsonRpcClient.prototype.closeSocket=function(){var self=this;if(self.socketReady()){self._ws_socket.onclose=function(w){console.log("Closing Socket");};self._ws_socket.close();}};$.JsonRpcClient.prototype.loginData=function(params){var self=this;self.options.login=params.login;self.options.passwd=params.passwd;self.options.loginParams=params.loginParams;self.options.userVariables=params.userVariables;};$.JsonRpcClient.prototype.connectSocket=function(onmessage_cb){var self=this;if(self.to){clearTimeout(self.to);} +if(!self.socketReady()){self.authing=false;if(self._ws_socket){delete self._ws_socket;} +self._ws_socket=new WebSocket(self.options.socketUrl);if(self._ws_socket){self._ws_socket.onmessage=onmessage_cb;self._ws_socket.onclose=function(w){if(!self.ws_sleep){self.ws_sleep=1000;} +if(self.options.onWSClose){self.options.onWSClose(self);} +if(self.ws_cnt>10&&self.options.wsFallbackURL){self.options.socketUrl=self.options.wsFallbackURL;} +console.error("Websocket Lost "+self.ws_cnt+" sleep: "+self.ws_sleep+"msec");self.to=setTimeout(function(){console.log("Attempting Reconnection....");self.connectSocket(onmessage_cb);},self.ws_sleep);self.ws_cnt++;if(self.ws_sleep<3000&&(self.ws_cnt%10)===0){self.ws_sleep+=1000;}};self._ws_socket.onopen=function(){if(self.to){clearTimeout(self.to);} +self.ws_sleep=1000;self.ws_cnt=0;if(self.options.onWSConnect){self.options.onWSConnect(self);} +var req;while((req=$.JsonRpcClient.q.pop())){self._ws_socket.send(req);}};}} +return self._ws_socket?true:false;};$.JsonRpcClient.prototype.stopRetrying=function(){if(self.to) +clearTimeout(self.to);} +$.JsonRpcClient.prototype._getSocket=function(onmessage_cb){if(this.options.socketUrl===null||!("WebSocket"in window))return null;this.connectSocket(onmessage_cb);return this._ws_socket;};$.JsonRpcClient.q=[];$.JsonRpcClient.prototype._wsCall=function(socket,request,success_cb,error_cb){var request_json=$.toJSON(request);if(socket.readyState<1){self=this;$.JsonRpcClient.q.push(request_json);}else{socket.send(request_json);} +if('id'in request&&typeof success_cb!=='undefined'){this._ws_callbacks[request.id]={request:request_json,request_obj:request,success_cb:success_cb,error_cb:error_cb};}};$.JsonRpcClient.prototype._wsOnMessage=function(event){var response;if(event.data[0]=="#"&&event.data[1]=="S"&&event.data[2]=="P"){if(event.data[3]=="U"){this.up_dur=parseInt(event.data.substring(4));}else if(this.speedCB&&event.data[3]=="D"){this.down_dur=parseInt(event.data.substring(4));var up_kps=(((this.speedBytes*8)/(this.up_dur/1000))/1024).toFixed(0);var down_kps=(((this.speedBytes*8)/(this.down_dur/1000))/1024).toFixed(0);console.info("Speed Test: Up: "+up_kps+" Down: "+down_kps);var cb=this.speedCB;this.speedCB=null;cb(event,{upDur:this.up_dur,downDur:this.down_dur,upKPS:up_kps,downKPS:down_kps});} +return;} +try{response=$.parseJSON(event.data);if(typeof response==='object'&&'jsonrpc'in response&&response.jsonrpc==='2.0'){if('result'in response&&this._ws_callbacks[response.id]){var success_cb=this._ws_callbacks[response.id].success_cb;delete this._ws_callbacks[response.id];success_cb(response.result,this);return;}else if('error'in response&&this._ws_callbacks[response.id]){var error_cb=this._ws_callbacks[response.id].error_cb;var orig_req=this._ws_callbacks[response.id].request;if(!self.authing&&response.error.code==-32000&&self.options.login&&self.options.passwd){self.authing=true;this.call("login",{login:self.options.login,passwd:self.options.passwd,loginParams:self.options.loginParams,userVariables:self.options.userVariables},this._ws_callbacks[response.id].request_obj.method=="login"?function(e){self.authing=false;console.log("logged in");delete self._ws_callbacks[response.id];if(self.options.onWSLogin){self.options.onWSLogin(true,self);}}:function(e){self.authing=false;console.log("logged in, resending request id: "+response.id);var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send(orig_req);} +if(self.options.onWSLogin){self.options.onWSLogin(true,self);}},function(e){console.log("error logging in, request id:",response.id);delete self._ws_callbacks[response.id];error_cb(response.error,this);if(self.options.onWSLogin){self.options.onWSLogin(false,self);}});return;} +delete this._ws_callbacks[response.id];error_cb(response.error,this);return;}}}catch(err){console.log("ERROR: "+err);return;} +if(typeof this.options.onmessage==='function'){event.eventData=response;if(!event.eventData){event.eventData={};} +var reply=this.options.onmessage(event);if(reply&&typeof reply==="object"&&event.eventData.id){var msg={jsonrpc:"2.0",id:event.eventData.id,result:reply};var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send($.toJSON(msg));}}}};$.JsonRpcClient._batchObject=function(jsonrpcclient,all_done_cb,error_cb){this._requests=[];this.jsonrpcclient=jsonrpcclient;this.all_done_cb=all_done_cb;this.error_cb=typeof error_cb==='function'?error_cb:function(){};};$.JsonRpcClient._batchObject.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};} +if(this.options.sessid){params.sessid=this.options.sessid;} +if(!success_cb){success_cb=function(e){console.log("Success: ",e);};} +if(!error_cb){error_cb=function(e){console.log("Error: ",e);};} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params,id:this.jsonrpcclient._current_id++},success_cb:success_cb,error_cb:error_cb});};$.JsonRpcClient._batchObject.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params}});};$.JsonRpcClient._batchObject.prototype._execute=function(){var self=this;if(this._requests.length===0)return;var batch_request=[];var handlers={};var i=0;var call;var success_cb;var error_cb;var socket=self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);if(socket!==null){for(i=0;i0){data.params.useVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);dialog.setState($.verto.enum.state.recovering);break;case'verto.invite':if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.wantVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");break;}} +return{method:data.method};}else{switch(data.method){case'verto.punt':verto.purge();verto.logout();break;case'verto.event':var list=null;var key=null;if(data.params){key=data.params.eventChannel;} +if(key){list=verto.eventSUBS[key];if(!list){list=verto.eventSUBS[key.split(".")[0]];}} +if(!list&&key&&key===verto.sessid){if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.pvtEvent,data.params);}}else if(!list&&key&&verto.dialogs[key]){verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent,data.params);}else if(!list){if(!key){key="UNDEFINED";} +console.error("UNSUBBED or invalid EVENT "+key+" IGNORED");}else{for(var i in list){var sub=list[i];if(!sub||!sub.ready){console.error("invalid EVENT for "+key+" IGNORED");}else if(sub.handler){sub.handler(verto,data.params,sub.userData);}else if(verto.callbacks.onEvent){verto.callbacks.onEvent(verto,data.params,sub.userData);}else{console.log("EVENT:",data.params);}}} +break;case"verto.info":if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.info,data.params.msg);} +console.debug("MESSAGE from: "+data.params.msg.from,data.params.msg.body);break;case'verto.clientReady':if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.clientReady,data.params);} +console.debug("CLIENT READY",data.params);break;default:console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}};var del_array=function(array,name){var r=[];var len=array.length;for(var i=0;i=array.length){array.push(name);}else{var x=0;var n=[];var len=array.length;for(var i=0;i":"\n");});return str;};};$.verto.liveArray=function(verto,context,name,config){var la=this;var lastSerno=0;var binding=null;var user_obj=config.userObj;var local=false;hashArray.call(la);la._add=la.add;la._del=la.del;la._reorder=la.reorder;la._clear=la.clear;la.context=context;la.name=name;la.user_obj=user_obj;la.verto=verto;la.broadcast=function(channel,obj){verto.broadcast(channel,obj);};la.errs=0;la.clear=function(){la._clear();lastSerno=0;if(la.onChange){la.onChange(la,{action:"clear"});}};la.checkSerno=function(serno){if(serno<0){return true;} +if(lastSerno>0&&serno!=(lastSerno+1)){if(la.onErr){la.onErr(la,{lastSerno:lastSerno,serno:serno});} +la.errs++;console.debug(la.errs);if(la.errs<3){la.bootstrap(la.user_obj);} +return false;}else{lastSerno=serno;return true;}};la.reorder=function(serno,a){if(la.checkSerno(serno)){la._reorder(a);if(la.onChange){la.onChange(la,{serno:serno,action:"reorder"});}}};la.init=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(la.onChange){la.onChange(la,{serno:serno,action:"init",index:index,key:key,data:val});}}};la.bootObj=function(serno,val){if(la.checkSerno(serno)){for(var i in val){la._add(val[i][0],val[i][1]);} +if(la.onChange){la.onChange(la,{serno:serno,action:"bootObj",data:val,redraw:true});}}};la.add=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){var redraw=la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"add",index:index,key:key,data:val,redraw:redraw});}}};la.modify=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"modify",key:key,data:val,index:index});}}};la.del=function(serno,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(index===null||index<0||index===undefined){index=la.indexOf(key);} +var ok=la._del(key);if(ok&&la.onChange){la.onChange(la,{serno:serno,action:"del",key:key,index:index});}}};var eventHandler=function(v,e,la){var packet=e.data;if(packet.name!=la.name){return;} +switch(packet.action){case"init":la.init(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"bootObj":la.bootObj(packet.wireSerno,packet.data);break;case"add":la.add(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"modify":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.modify(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);} +break;case"del":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.del(packet.wireSerno,packet.hashKey,packet.arrIndex);} +break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,packet.order);break;default:if(la.checkSerno(packet.wireSerno)){if(la.onChange){la.onChange(la,{serno:packet.wireSerno,action:packet.action,data:packet.data});}} +break;}};if(la.context){binding=la.verto.subscribe(la.context,{handler:eventHandler,userData:la,subParams:config.subParams});} +la.destroy=function(){la._clear();la.verto.unsubscribe(binding);};la.sendCommand=function(cmd,obj){var self=la;self.broadcast(self.context,{liveArray:{command:cmd,context:self.context,name:self.name,obj:obj}});};la.bootstrap=function(obj){var self=la;la.sendCommand("bootstrap",obj);};la.changepage=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"changepage",context:la.context,name:la.name,obj:obj}});};la.heartbeat=function(obj){var self=la;var callback=function(){self.heartbeat.call(self,obj);};self.broadcast(self.context,{liveArray:{command:"heartbeat",context:self.context,name:self.name,obj:obj}});self.hb_pid=setTimeout(callback,30000);};la.bootstrap(la.user_obj);};$.verto.liveTable=function(verto,context,name,jq,config){var dt;var la=new $.verto.liveArray(verto,context,name,{subParams:config.subParams});var lt=this;lt.liveArray=la;lt.dataTable=dt;lt.verto=verto;lt.destroy=function(){if(dt){dt.fnDestroy();} +if(la){la.destroy();} +dt=null;la=null;};la.onErr=function(obj,args){console.error("Error: ",obj,args);};function genRow(data){if(typeof(data[4])==="string"&&data[4].indexOf("{")>-1){var tmp=$.parseJSON(data[4]);data[4]=tmp.oldStatus;data[5]=null;} +return data;} +function genArray(obj){var data=obj.asArray();for(var i in data){data[i]=genRow(data[i]);} +return data;} +la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;} +config.aoColumns=[];for(var i in args.data){config.aoColumns.push({"sTitle":args.data[i]});}} +dt=jq.dataTable(config);} +if(dt&&(args.action=="del"||args.action=="modify")){index=args.index;if(index===undefined&&args.key){index=la.indexOf(args.key);} +if(index===undefined){console.error("INVALID PACKET Missing INDEX\n",args);return;}} +if(config.onChange){config.onChange(obj,args);} +try{switch(args.action){case"bootObj":if(!args.data){console.error("missing data");return;} +dt.fnClearTable();dt.fnAddData(genArray(obj));dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;} +if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(genArray(obj));}else{dt.fnAddData(genRow(args.data));} +dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;} +dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;} +if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.infoChannel,{handler:function(v,e){if(typeof(conf.params.infoCallback)==="function"){conf.params.infoCallback(v,e);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);} +if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);} +if(conf.params.laData.infoChannel){conf.verto.unsubscribe(conf.params.laData.infoChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';} +if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-res-id",parseInt(memberID),"presenter");};$.verto.conf.prototype.videoFloor=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-floor",parseInt(memberID),"force");};$.verto.conf.prototype.banner=function(memberID,text){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-banner",parseInt(memberID),escape(text));};$.verto.conf.prototype.volumeDown=function(memberID){this.modCommand("volume_out",parseInt(memberID),"down");};$.verto.conf.prototype.volumeUp=function(memberID){this.modCommand("volume_out",parseInt(memberID),"up");};$.verto.conf.prototype.gainDown=function(memberID){this.modCommand("volume_in",parseInt(memberID),"down");};$.verto.conf.prototype.gainUp=function(memberID){this.modCommand("volume_in",parseInt(memberID),"up");};$.verto.conf.prototype.transfer=function(memberID,exten){this.modCommand("transfer",parseInt(memberID),exten);};$.verto.conf.prototype.sendChat=function(message,type){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};} +$.verto.modfuncs={};$.verto.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;confMan.canvasCount=confMan.params.laData.canvasCount;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="

"+""+""+""+""+ +(confMan.params.hasVid?"":"")+"

";jq.html(html);$.verto.modfuncs.change_video_layout=function(id,canvas_id){var val=$("#"+id+" option:selected").text();if(val!=="none"){confMan.modCommand("vid-layout",null,[val,canvas_id]);}};if(confMan.params.hasVid){for(var j=0;j
"+"Video Layout Canvas "+(j+1)+" "+"

";jq.append(vlhtml);} +$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});} +$("#"+play_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("play",null,file);}});$("#"+stop_id).click(function(){confMan.modCommand("stop",null,"all");});$("#"+recording_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("recording",null,["start",file]);}});$("#"+rec_stop_id).click(function(){confMan.modCommand("recording",null,["stop","all"]);});} +function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var canvas_in_next_id="canvas_in_next_"+x;var canvas_in_prev_id="canvas_in_prev_"+x;var canvas_out_next_id="canvas_out_next_"+x;var canvas_out_prev_id="canvas_out_prev_"+x;var canvas_in_set_id="canvas_in_set_"+x;var canvas_out_set_id="canvas_out_set_"+x;var layer_set_id="layer_set_"+x;var layer_next_id="layer_next_"+x;var layer_prev_id="layer_prev_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var gainup_id="gain_in_up"+x;var gaindn_id="gain_in_dn"+x;var volup_id="vol_in_up"+x;var voldn_id="vol_in_dn"+x;var transfer_id="transfer"+x;var html="
";html+="General Controls
";html+=""+""+""+""+""+""+"";if(confMan.params.hasVid){html+="

Video Controls
";html+=""+""+""+"";if(confMan.canvasCount>1){html+="

Canvas Controls
"+""+""+""+"
"+""+""+"";} +html+="
"+""+""+""+"
";} +jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();} +jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});} +$("#"+gainup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+gaindn_id).click(function(){confMan.modCommand("volume_in",x,"down");});$("#"+volup_id).click(function(){confMan.modCommand("volume_out",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_out",x,"down");});return html;} +var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.infoChannel,{handler:function(v,e){if(typeof(confMan.params.infoCallback)==="function"){confMan.params.infoCallback(v,e);}}});verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready

");}else{$(confMan.params.mainModID).html("");} +verto.subscribe(confMan.params.laData.modChannel,{handler:function(v,e){if(confMan.params.onBroadcast){confMan.params.onBroadcast(verto,confMan,e.data);} +if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;jb)?1:-1));});for(var i in options){$(vlselect_id).append(new Option(options[i],options[i]));x++;}} +if(x){$(vlselect_id).selectmenu('refresh',true);}else{$(vlayout_id).hide();}}}else{if(!confMan.destroyed&&confMan.params.displayID){$(confMan.params.displayID).html(e.data.response+"

");if(confMan.lastTimeout){clearTimeout(confMan.lastTimeout);confMan.lastTimeout=0;} +confMan.lastTimeout=setTimeout(function(){$(confMan.params.displayID).html(confMan.destroyed?"":"Moderator Controls Ready

");},4000);}}}});if(confMan.params.hasVid){confMan.modCommand("list-videoLayouts",null,null);}} +var row_callback=null;if(confMan.params.laData.role==="moderator"){row_callback=function(nRow,aData,iDisplayIndex,iDisplayIndexFull){if(!aData[5]){var $row=$('td:eq(5)',nRow);genControls($row,aData);if(confMan.params.onLaRow){confMan.params.onLaRow(verto,confMan,$row,aData);}}};} +confMan.lt=new $.verto.liveTable(verto,confMan.params.laData.laChannel,confMan.params.laData.laName,$(confMan.params.tableID),{subParams:{callID:confMan.params.dialog?confMan.params.dialog.callID:null},"onChange":function(obj,args){$(confMan.params.statusID).text("Conference Members: "+" ("+obj.arrayLen()+" Total)");if(confMan.params.onLaChange){confMan.params.onLaChange(verto,confMan,$.verto.enum.confEvent.laChange,obj,args);}},"aaData":[],"aoColumns":[{"sTitle":"ID","sWidth":"50"},{"sTitle":"Number","sWidth":"250"},{"sTitle":"Name","sWidth":"250"},{"sTitle":"Codec","sWidth":"100"},{"sTitle":"Status","sWidth":confMan.params.hasVid?"200px":"150px"},{"sTitle":atitle,"sWidth":awidth,}],"bAutoWidth":true,"bDestroy":true,"bSort":false,"bInfo":false,"bFilter":false,"bLengthChange":false,"bPaginate":false,"iDisplayLength":1400,"oLanguage":{"sEmptyTable":"The Conference is Empty....."},"fnRowCallback":row_callback});};$.verto.confMan.prototype.modCommand=function(cmd,id,value){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.confMan.prototype.sendChat=function(message,type){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};$.verto.confMan.prototype.destroy=function(){var confMan=this;confMan.destroyed=true;if(confMan.lt){confMan.lt.destroy();} +if(confMan.params.laData.chatChannel){confMan.verto.unsubscribe(confMan.params.laData.chatChannel);} +if(confMan.params.laData.modChannel){confMan.verto.unsubscribe(confMan.params.laData.modChannel);} +if(confMan.params.mainModID){$(confMan.params.mainModID).html("");}};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,screenShare:false,useCamera:false,useMic:verto.options.deviceParams.useMic,useMicLabel:verto.options.deviceParams.useMicLabel,useSpeak:verto.options.deviceParams.useSpeak,tag:verto.options.tag,localTag:verto.options.localTag,login:verto.options.login,videoParams:verto.options.videoParams,useStream:verto.options.useStream,},params);if(!dialog.params.screenShare){dialog.params.useCamera=verto.options.deviceParams.useCamera;dialog.params.useCameraLabel=verto.options.deviceParams.useCameraLabel;} +dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;dialog.screenShare=params.screenShare||false;dialog.useCamera=dialog.params.useCamera;dialog.useCameraLabel=dialog.params.useCameraLabel;dialog.useMic=dialog.params.useMic;dialog.useMicLabel=dialog.params.useMicLabel;dialog.useSpeak=dialog.params.useSpeak;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();} +if(typeof(dialog.params.tag)==="function"){dialog.params.tag=dialog.params.tag();} +if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}} +if(dialog.params.localTag){dialog.localVideo=document.getElementById(dialog.params.localTag);} +dialog.verto.dialogs[dialog.callID]=dialog;var RTCcallbacks={};if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.params.display_direction==="outbound"){dialog.params.remote_caller_id_name=dialog.params.caller_id_name;dialog.params.remote_caller_id_number=dialog.params.caller_id_number;}else{dialog.params.remote_caller_id_name=dialog.params.callee_id_name;dialog.params.remote_caller_id_number=dialog.params.callee_id_number;} +if(!dialog.params.remote_caller_id_name){dialog.params.remote_caller_id_name="Nobody";} +if(!dialog.params.remote_caller_id_number){dialog.params.remote_caller_id_number="UNKNOWN";} +RTCcallbacks.onMessage=function(rtc,msg){console.debug(msg);};RTCcallbacks.onAnswerSDP=function(rtc,sdp){console.error("answer sdp",sdp);};}else{dialog.params.remote_caller_id_name="Outbound Call";dialog.params.remote_caller_id_number=dialog.params.destination_number;} +RTCcallbacks.onICESDP=function(rtc){console.log("RECV "+rtc.type+" SDP",rtc.mediaData.SDP);if(dialog.state==$.verto.enum.state.requesting||dialog.state==$.verto.enum.state.answering||dialog.state==$.verto.enum.state.active){location.reload();return;} +if(rtc.type=="offer"){if(dialog.state==$.verto.enum.state.active){dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.attach",{sdp:rtc.mediaData.SDP});}else{dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.invite",{sdp:rtc.mediaData.SDP});}}else{dialog.setState($.verto.enum.state.answering);dialog.sendMethod(dialog.attach?"verto.attach":"verto.answer",{sdp:dialog.rtc.mediaData.SDP});}};RTCcallbacks.onICE=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.candidate);return;}};RTCcallbacks.onStream=function(rtc,stream){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onGranted==='function'){dialog.callbacks.permissionCallback.onGranted(stream);} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onGranted==='function'){dialog.verto.options.permissionCallback.onGranted(stream);} +console.log("stream started");};RTCcallbacks.onRemoteStream=function(rtc,stream){if(typeof dialog.callbacks.onRemoteStream==='function'){dialog.callbacks.onRemoteStream(stream,dialog);} +console.log("remote stream started");};RTCcallbacks.onError=function(e){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onDenied==='function'){dialog.callbacks.permissionCallback.onDenied();} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onDenied==='function'){dialog.verto.options.permissionCallback.onDenied();} +console.error("ERROR:",e);dialog.hangup({cause:"Device or Permission Error"});};dialog.rtc=new $.FSRTC({callbacks:RTCcallbacks,localVideo:dialog.screenShare?null:dialog.localVideo,useVideo:dialog.params.useVideo?dialog.videoStream:null,useAudio:dialog.audioStream,useStereo:dialog.params.useStereo,videoParams:dialog.params.videoParams,audioParams:verto.options.audioParams,iceServers:verto.options.iceServers,screenShare:dialog.screenShare,useCamera:dialog.useCamera,useCameraLabel:dialog.useCameraLabel,useMic:dialog.useMic,useMicLabel:dialog.useMicLabel,useSpeak:dialog.useSpeak,turnServer:verto.options.turnServer,useStream:dialog.params.useStream});dialog.rtc.verto=dialog.verto;if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.attach){dialog.answer();}else{dialog.ring();}}};$.verto.dialog.prototype.invite=function(){var dialog=this;dialog.rtc.call();};$.verto.dialog.prototype.sendMethod=function(method,obj){var dialog=this;obj.dialogParams={};for(var i in dialog.params){if(i=="sdp"&&method!="verto.invite"&&method!="verto.attach"){continue;} +if((obj.noDialogParams&&i!="callID")){continue;} +obj.dialogParams[i]=dialog.params[i];} +delete obj.noDialogParams;dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,true,e);},function(e){dialog.processReply(method,false,e);});};function checkStateChange(oldS,newS){if(newS==$.verto.enum.state.purge||$.verto.enum.states[oldS.name][newS.name]){return true;} +return false;} +function find_name(id){for(var i in $.verto.audioOutDevices){var source=$.verto.audioOutDevices[i];if(source.id===id){return(source.label);}} +return id;} +$.verto.dialog.prototype.setAudioPlaybackDevice=function(sinkId,callback,arg){var dialog=this;var element=dialog.audioStream;if(typeof element.sinkId!=='undefined'){var devname=find_name(sinkId);console.info("Dialog: "+dialog.callID+" Setting speaker:",element,devname);element.setSinkId(sinkId).then(function(){console.log("Dialog: "+dialog.callID+' Success, audio output device attached: '+sinkId);if(callback){callback(true,devname,arg);}}).catch(function(error){var errorMessage=error;if(error.name==='SecurityError'){errorMessage="Dialog: "+dialog.callID+' You need to use HTTPS for selecting audio output '+'device: '+error;} +if(callback){callback(false,null,arg);} +console.error(errorMessage);});}else{console.warn("Dialog: "+dialog.callID+' Browser does not support output device selection.');if(callback){callback(false,null,arg);}}} +$.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();} +if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;} +console.log("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);} +switch(dialog.state){case $.verto.enum.state.early:case $.verto.enum.state.active:var speaker=dialog.useSpeak;console.info("Using Speaker: ",speaker);if(speaker&&speaker!=="any"&&speaker!=="none"){setTimeout(function(){dialog.setAudioPlaybackDevice(speaker);},500);} +break;case $.verto.enum.state.trying:setTimeout(function(){if(dialog.state==$.verto.enum.state.trying){dialog.setState($.verto.enum.state.hangup);}},30000);break;case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});} +dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:if(typeof(dialog.verto.options.tag)==="function"){$('#'+dialog.params.tag).remove();} +delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();} +break;} +return true;};$.verto.dialog.prototype.processReply=function(method,success,e){var dialog=this;switch(method){case"verto.answer":case"verto.attach":if(success){dialog.setState($.verto.enum.state.active);}else{dialog.hangup();} +break;case"verto.invite":if(success){dialog.setState($.verto.enum.state.trying);}else{dialog.setState($.verto.enum.state.destroy);} +break;case"verto.bye":dialog.hangup();break;case"verto.modify":if(e.holdState){if(e.holdState=="held"){if(dialog.state!=$.verto.enum.state.held){dialog.setState($.verto.enum.state.held);}}else if(e.holdState=="active"){if(dialog.state!=$.verto.enum.state.active){dialog.setState($.verto.enum.state.active);}}} +if(success){} +break;default:break;}};$.verto.dialog.prototype.hangup=function(params){var dialog=this;if(params){if(params.causeCode){dialog.causeCode=params.causeCode;} +if(params.cause){dialog.cause=params.cause;}} +if(!dialog.cause&&!dialog.causeCode){dialog.cause="NORMAL_CLEARING";} +if(dialog.state.val>=$.verto.enum.state.new.val&&dialog.state.val<$.verto.enum.state.hangup.val){dialog.setState($.verto.enum.state.hangup);}else if(dialog.state.val<$.verto.enum.state.destroy){dialog.setState($.verto.enum.state.destroy);}};$.verto.dialog.prototype.stopRinging=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.stop();}};$.verto.dialog.prototype.indicateRing=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.attr("src",dialog.verto.options.ringFile)[0].play();setTimeout(function(){dialog.stopRinging();if(dialog.state==$.verto.enum.state.ringing){dialog.indicateRing();}},dialog.verto.options.ringSleep);}};$.verto.dialog.prototype.ring=function(){var dialog=this;dialog.setState($.verto.enum.state.ringing);dialog.indicateRing();};$.verto.dialog.prototype.useVideo=function(on){var dialog=this;dialog.params.useVideo=on;if(on){dialog.videoStream=dialog.audioStream;}else{dialog.videoStream=null;} +dialog.rtc.useVideo(dialog.videoStream,dialog.localVideo);};$.verto.dialog.prototype.setMute=function(what){var dialog=this;return dialog.rtc.setMute(what);};$.verto.dialog.prototype.getMute=function(){var dialog=this;return dialog.rtc.getMute();};$.verto.dialog.prototype.setVideoMute=function(what){var dialog=this;return dialog.rtc.setVideoMute(what);};$.verto.dialog.prototype.getVideoMute=function(){var dialog=this;return dialog.rtc.getVideoMute();};$.verto.dialog.prototype.useStereo=function(on){var dialog=this;dialog.params.useStereo=on;dialog.rtc.useStereo(on);};$.verto.dialog.prototype.dtmf=function(digits){var dialog=this;if(digits){dialog.sendMethod("verto.info",{dtmf:digits});}};$.verto.dialog.prototype.rtt=function(obj){var dialog=this;var pobj={};if(!obj){return false;} +pobj.code=obj.code;pobj.chars=obj.chars;if(pobj.chars||pobj.code){dialog.sendMethod("verto.info",{txt:obj,noDialogParams:true});}};$.verto.dialog.prototype.transfer=function(dest,params){var dialog=this;if(dest){dialog.sendMethod("verto.modify",{action:"transfer",destination:dest,params:params});}};$.verto.dialog.prototype.replace=function(replaceCallID,params){var dialog=this;if(replaceCallID){dialog.sendMethod("verto.modify",{action:"replace",replaceCallID:replaceCallID,params:params});}};$.verto.dialog.prototype.hold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"hold",params:params});};$.verto.dialog.prototype.unhold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"unhold",params:params});};$.verto.dialog.prototype.toggleHold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"toggleHold",params:params});};$.verto.dialog.prototype.message=function(msg){var dialog=this;var err=0;msg.from=dialog.params.login;if(!msg.to){console.error("Missing To");err++;} +if(!msg.body){console.error("Missing Body");err++;} +if(err){return false;} +dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(!params){params={};} +params.sdp=dialog.params.sdp;if(params){if(params.useVideo){dialog.useVideo(true);} +dialog.params.callee_id_name=params.callee_id_name;dialog.params.callee_id_number=params.callee_id_number;if(params.useCamera){dialog.useCamera=params.useCamera;dialog.useCameraLabel=params.useCameraLabel;} +if(params.useMic){dialog.useMic=params.useMic;dialog.useMic=params.useMicLabel;} +if(params.useSpeak){dialog.useSpeak=params.useSpeak;}} +dialog.rtc.createAnswer(params);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(params){var dialog=this;dialog.gotAnswer=true;if(dialog.state.val>=$.verto.enum.state.active.val){return;} +if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{if(dialog.gotEarly){console.log("Dialog "+dialog.callID+" Got answer while still establishing early media, delaying...");}else{console.log("Dialog "+dialog.callID+" Answering Channel");dialog.rtc.answer(params.sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"ANSWER SDP",params.sdp);}}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" <":" <")+dialog.params.remote_caller_id_number+(enc?">":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;} +if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;} +dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(params){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;} +dialog.gotEarly=true;dialog.rtc.answer(params.sdp,function(){console.log("Dialog "+dialog.callID+"Establishing early media");dialog.setState($.verto.enum.state.early);if(dialog.gotAnswer){console.log("Dialog "+dialog.callID+"Answering Channel");dialog.setState($.verto.enum.state.active);}},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"EARLY SDP",params.sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,recovering:1,ringing:1,destroy:1,answering:1,hangup:1},requesting:{trying:1,hangup:1,active:1},recovering:{answering:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{answering:1,requesting:1,hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent clientReady");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$.verto.unloadJobs=[];var unloadEventName='beforeunload';var iOS=['iPad','iPhone','iPod'].indexOf(navigator.platform)>=0;if(iOS){unloadEventName='pagehide';} +$(window).bind(unloadEventName,function(){for(var f in $.verto.unloadJobs){$.verto.unloadJobs[f]();} +if($.verto.haltClosure) +return $.verto.haltClosure();for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.purge();verto.logout();}} +return $.verto.warnOnUnload;});$.verto.videoDevices=[];$.verto.audioInDevices=[];$.verto.audioOutDevices=[];var checkDevices=function(runtime){console.info("enumerating devices");var aud_in=[],aud_out=[],vid=[];var has_video=0,has_audio=0;var Xstream;function gotDevices(deviceInfos){for(var i=0;i!==deviceInfos.length;++i){var deviceInfo=deviceInfos[i];var text="";console.log(deviceInfo);console.log(deviceInfo.kind+": "+deviceInfo.label+" id = "+deviceInfo.deviceId);if(deviceInfo.kind==='audioinput'){text=deviceInfo.label||'microphone '+(aud_in.length+1);aud_in.push({id:deviceInfo.deviceId,kind:"audio_in",label:text});}else if(deviceInfo.kind==='audiooutput'){text=deviceInfo.label||'speaker '+(aud_out.length+1);aud_out.push({id:deviceInfo.deviceId,kind:"audio_out",label:text});}else if(deviceInfo.kind==='videoinput'){text=deviceInfo.label||'camera '+(vid.length+1);vid.push({id:deviceInfo.deviceId,kind:"video",label:text});}else{console.log('Some other kind of source/device: ',deviceInfo);}} +$.verto.videoDevices=vid;$.verto.audioInDevices=aud_in;$.verto.audioOutDevices=aud_out;console.info("Audio IN Devices",$.verto.audioInDevices);console.info("Audio Out Devices",$.verto.audioOutDevices);console.info("Video Devices",$.verto.videoDevices);if(Xstream){Xstream.getTracks().forEach(function(track){track.stop();});} +if(runtime){runtime(true);}} +function handleError(error){console.log('device enumeration error: ',error);if(runtime)runtime(false);} +function checkTypes(devs){for(var i=0;i!==devs.length;++i){if(devs[i].kind==='audioinput'){has_audio++;}else if(devs[i].kind==='videoinput'){has_video++;}} +navigator.getUserMedia({audio:(has_audio>0?true:false),video:(has_video>0?true:false)},function(stream){Xstream=stream;navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);},function(err){console.log("The following error occurred: "+err.name);});} +navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError);};$.verto.refreshDevices=function(runtime){checkDevices(runtime);} +$.verto.init=function(obj,runtime){if(!obj){obj={};} +if(!obj.skipPermCheck&&!obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){checkDevices(runtime);},true,true);}else if(obj.skipPermCheck&&!obj.skipDeviceCheck){checkDevices(runtime);}else if(!obj.skipPermCheck&&obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){runtime(status);},true,true);}else{runtime(null);}} +$.verto.genUUID=function(){return generateGUID();}})(jQuery);(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter=f()}})(function(){var define,module,exports;return(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i0&&arguments[0]!==undefined?arguments[0]:{},window=_ref.window;var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{shimChrome:true,shimFirefox:true,shimEdge:true,shimSafari:true};var logging=utils.log;var browserDetails=utils.detectBrowser(window);var adapter={browserDetails:browserDetails,commonShim:commonShim,extractVersion:utils.extractVersion,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings};switch(browserDetails.browser){case'chrome':if(!chromeShim||!chromeShim.shimPeerConnection||!options.shimChrome){logging('Chrome shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming chrome.');adapter.browserShim=chromeShim;chromeShim.shimGetUserMedia(window);chromeShim.shimMediaStream(window);chromeShim.shimPeerConnection(window);chromeShim.shimOnTrack(window);chromeShim.shimAddTrackRemoveTrack(window);chromeShim.shimGetSendersWithDtmf(window);chromeShim.shimSenderReceiverGetStats(window);chromeShim.fixNegotiationNeeded(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;case'firefox':if(!firefoxShim||!firefoxShim.shimPeerConnection||!options.shimFirefox){logging('Firefox shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming firefox.');adapter.browserShim=firefoxShim;firefoxShim.shimGetUserMedia(window);firefoxShim.shimPeerConnection(window);firefoxShim.shimOnTrack(window);firefoxShim.shimRemoveStream(window);firefoxShim.shimSenderGetStats(window);firefoxShim.shimReceiverGetStats(window);firefoxShim.shimRTCDataChannel(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'edge':if(!edgeShim||!edgeShim.shimPeerConnection||!options.shimEdge){logging('MS edge shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming edge.');adapter.browserShim=edgeShim;edgeShim.shimGetUserMedia(window);edgeShim.shimGetDisplayMedia(window);edgeShim.shimPeerConnection(window);edgeShim.shimReplaceTrack(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'safari':if(!safariShim||!options.shimSafari){logging('Safari shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming safari.');adapter.browserShim=safariShim;safariShim.shimRTCIceServerUrls(window);safariShim.shimCreateOfferLegacy(window);safariShim.shimCallbacksAPI(window);safariShim.shimLocalStreamsAPI(window);safariShim.shimRemoteStreamsAPI(window);safariShim.shimTrackEventTransceiver(window);safariShim.shimGetUserMedia(window);commonShim.shimRTCIceCandidate(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;default:logging('Unsupported browser!');break;} +return adapter;}},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimMediaStream=shimMediaStream;exports.shimOnTrack=shimOnTrack;exports.shimGetSendersWithDtmf=shimGetSendersWithDtmf;exports.shimSenderReceiverGetStats=shimSenderReceiverGetStats;exports.shimAddTrackRemoveTrackWithNative=shimAddTrackRemoveTrackWithNative;exports.shimAddTrackRemoveTrack=shimAddTrackRemoveTrack;exports.shimPeerConnection=shimPeerConnection;exports.fixNegotiationNeeded=fixNegotiationNeeded;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function walkStats(stats,base,resultSet){if(!base||resultSet.has(base.id)){return;} +resultSet.set(base.id,base);Object.keys(base).forEach(function(name){if(name.endsWith('Id')){walkStats(stats,stats.get(base[name]),resultSet);}else if(name.endsWith('Ids')){base[name].forEach(function(id){walkStats(stats,stats.get(id),resultSet);});}});} +function filterStats(result,track,outbound){var streamStatsType=outbound?'outbound-rtp':'inbound-rtp';var filteredResult=new Map();if(track===null){return filteredResult;} +var trackStats=[];result.forEach(function(value){if(value.type==='track'&&value.trackIdentifier===track.id){trackStats.push(value);}});trackStats.forEach(function(trackStat){result.forEach(function(stats){if(stats.type===streamStatsType&&stats.trackId===trackStat.id){walkStats(result,stats,filteredResult);}});});return filteredResult;} +function shimMediaStream(window){window.MediaStream=window.MediaStream||window.webkitMediaStream;} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('ontrack'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'ontrack',{get:function get(){return this._ontrack;},set:function set(f){if(this._ontrack){this.removeEventListener('track',this._ontrack);} +this.addEventListener('track',this._ontrack=f);},enumerable:true,configurable:true});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var _this=this;if(!this._ontrackpoly){this._ontrackpoly=function(e){e.stream.addEventListener('addtrack',function(te){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===te.track.id;});}else{receiver={track:te.track};} +var event=new Event('track');event.track=te.track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});e.stream.getTracks().forEach(function(track){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===track.id;});}else{receiver={track:track};} +var event=new Event('track');event.track=track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});};this.addEventListener('addstream',this._ontrackpoly);} +return origSetRemoteDescription.apply(this,arguments);};}else{utils.wrapPeerConnectionEvent(window,'track',function(e){if(!e.transceiver){Object.defineProperty(e,'transceiver',{value:{receiver:e.receiver}});} +return e;});}} +function shimGetSendersWithDtmf(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('getSenders'in window.RTCPeerConnection.prototype)&&'createDTMFSender'in window.RTCPeerConnection.prototype){var shimSenderWithDtmf=function shimSenderWithDtmf(pc,track){return{track:track,get dtmf(){if(this._dtmf===undefined){if(track.kind==='audio'){this._dtmf=pc.createDTMFSender(track);}else{this._dtmf=null;}} +return this._dtmf;},_pc:pc};};if(!window.RTCPeerConnection.prototype.getSenders){window.RTCPeerConnection.prototype.getSenders=function(){this._senders=this._senders||[];return this._senders.slice();};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){var sender=origAddTrack.apply(this,arguments);if(!sender){sender=shimSenderWithDtmf(this,track);this._senders.push(sender);} +return sender;};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){origRemoveTrack.apply(this,arguments);var idx=this._senders.indexOf(sender);if(idx!==-1){this._senders.splice(idx,1);}};} +var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this2=this;this._senders=this._senders||[];origAddStream.apply(this,[stream]);stream.getTracks().forEach(function(track){_this2._senders.push(shimSenderWithDtmf(_this2,track));});};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;this._senders=this._senders||[];origRemoveStream.apply(this,[stream]);stream.getTracks().forEach(function(track){var sender=_this3._senders.find(function(s){return s.track===track;});if(sender){_this3._senders.splice(_this3._senders.indexOf(sender),1);}});};}else if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&'getSenders'in window.RTCPeerConnection.prototype&&'createDTMFSender'in window.RTCPeerConnection.prototype&&window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;window.RTCPeerConnection.prototype.getSenders=function(){var _this4=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this4;});return senders;};Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=this._pc.createDTMFSender(this.track);}else{this._dtmf=null;}} +return this._dtmf;}});}} +function shimSenderReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender&&window.RTCRtpReceiver)){return;} +if(!('getStats'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this5=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this5;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){var sender=this;return this._pc.getStats().then(function(result){return(filterStats(result,sender.track,true));});};} +if(!('getStats'in window.RTCRtpReceiver.prototype)){var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this6=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this6;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){var receiver=this;return this._pc.getStats().then(function(result){return filterStats(result,receiver.track,false);});};} +if(!('getStats'in window.RTCRtpSender.prototype&&'getStats'in window.RTCRtpReceiver.prototype)){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof window.MediaStreamTrack){var track=arguments[0];var sender=void 0;var receiver=void 0;var err=void 0;this.getSenders().forEach(function(s){if(s.track===track){if(sender){err=true;}else{sender=s;}}});this.getReceivers().forEach(function(r){if(r.track===track){if(receiver){err=true;}else{receiver=r;}} +return r.track===track;});if(err||sender&&receiver){return Promise.reject(new DOMException('There are more than one sender or receiver for the track.','InvalidAccessError'));}else if(sender){return sender.getStats();}else if(receiver){return receiver.getStats();} +return Promise.reject(new DOMException('There is no sender or receiver for the track.','InvalidAccessError'));} +return origGetStats.apply(this,arguments);};} +function shimAddTrackRemoveTrackWithNative(window){window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this7=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};return Object.keys(this._shimmedLocalStreams).map(function(streamId){return _this7._shimmedLocalStreams[streamId][0];});};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(!stream){return origAddTrack.apply(this,arguments);} +this._shimmedLocalStreams=this._shimmedLocalStreams||{};var sender=origAddTrack.apply(this,arguments);if(!this._shimmedLocalStreams[stream.id]){this._shimmedLocalStreams[stream.id]=[stream,sender];}else if(this._shimmedLocalStreams[stream.id].indexOf(sender)===-1){this._shimmedLocalStreams[stream.id].push(sender);} +return sender;};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this8=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this8.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});var existingSenders=this.getSenders();origAddStream.apply(this,arguments);var newSenders=this.getSenders().filter(function(newSender){return existingSenders.indexOf(newSender)===-1;});this._shimmedLocalStreams[stream.id]=[stream].concat(newSenders);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._shimmedLocalStreams=this._shimmedLocalStreams||{};delete this._shimmedLocalStreams[stream.id];return origRemoveStream.apply(this,arguments);};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this9=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};if(sender){Object.keys(this._shimmedLocalStreams).forEach(function(streamId){var idx=_this9._shimmedLocalStreams[streamId].indexOf(sender);if(idx!==-1){_this9._shimmedLocalStreams[streamId].splice(idx,1);} +if(_this9._shimmedLocalStreams[streamId].length===1){delete _this9._shimmedLocalStreams[streamId];}});} +return origRemoveTrack.apply(this,arguments);};} +function shimAddTrackRemoveTrack(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(window.RTCPeerConnection.prototype.addTrack&&browserDetails.version>=65){return shimAddTrackRemoveTrackWithNative(window);} +var origGetLocalStreams=window.RTCPeerConnection.prototype.getLocalStreams;window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this10=this;var nativeStreams=origGetLocalStreams.apply(this);this._reverseStreams=this._reverseStreams||{};return nativeStreams.map(function(stream){return _this10._reverseStreams[stream.id];});};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this11=this;this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this11.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});if(!this._reverseStreams[stream.id]){var newStream=new window.MediaStream(stream.getTracks());this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;stream=newStream;} +origAddStream.apply(this,[stream]);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};origRemoveStream.apply(this,[this._streams[stream.id]||stream]);delete this._reverseStreams[this._streams[stream.id]?this._streams[stream.id].id:stream.id];delete this._streams[stream.id];};window.RTCPeerConnection.prototype.addTrack=function(track,stream){var _this12=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +var streams=[].slice.call(arguments,1);if(streams.length!==1||!streams[0].getTracks().find(function(t){return t===track;})){throw new DOMException('The adapter.js addTrack polyfill only supports a single '+' stream which is associated with the specified track.','NotSupportedError');} +var alreadyExists=this.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');} +this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};var oldStream=this._streams[stream.id];if(oldStream){oldStream.addTrack(track);Promise.resolve().then(function(){_this12.dispatchEvent(new Event('negotiationneeded'));});}else{var newStream=new window.MediaStream([track]);this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;this.addStream(newStream);} +return this.getSenders().find(function(s){return s.track===track;});};function replaceInternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(internalStream.id,'g'),externalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +function replaceExternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(externalStream.id,'g'),internalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +['createOffer','createAnswer'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var _this13=this;var args=arguments;var isLegacyCall=arguments.length&&typeof arguments[0]==='function';if(isLegacyCall){return nativeMethod.apply(this,[function(description){var desc=replaceInternalStreamId(_this13,description);args[0].apply(null,[desc]);},function(err){if(args[1]){args[1].apply(null,err);}},arguments[2]]);} +return nativeMethod.apply(this,arguments).then(function(description){return replaceInternalStreamId(_this13,description);});};});var origSetLocalDescription=window.RTCPeerConnection.prototype.setLocalDescription;window.RTCPeerConnection.prototype.setLocalDescription=function(){if(!arguments.length||!arguments[0].type){return origSetLocalDescription.apply(this,arguments);} +arguments[0]=replaceExternalStreamId(this,arguments[0]);return origSetLocalDescription.apply(this,arguments);};var origLocalDescription=Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype,'localDescription');Object.defineProperty(window.RTCPeerConnection.prototype,'localDescription',{get:function get(){var description=origLocalDescription.get.apply(this);if(description.type===''){return description;} +return replaceInternalStreamId(this,description);}});window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this14=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +if(!sender._pc){throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.','TypeError');} +var isLocal=sender._pc===this;if(!isLocal){throw new DOMException('Sender was not created by this connection.','InvalidAccessError');} +this._streams=this._streams||{};var stream=void 0;Object.keys(this._streams).forEach(function(streamid){var hasTrack=_this14._streams[streamid].getTracks().find(function(track){return sender.track===track;});if(hasTrack){stream=_this14._streams[streamid];}});if(stream){if(stream.getTracks().length===1){this.removeStream(this._reverseStreams[stream.id]);}else{stream.removeTrack(sender.track);} +this.dispatchEvent(new Event('negotiationneeded'));}};} +function shimPeerConnection(window){if(!window.RTCPeerConnection&&window.webkitRTCPeerConnection){window.RTCPeerConnection=window.webkitRTCPeerConnection;} +if(!window.RTCPeerConnection){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,successCallback,errorCallback){var _this15=this;var args=arguments;if(arguments.length>0&&typeof selector==='function'){return origGetStats.apply(this,arguments);} +if(origGetStats.length===0&&(arguments.length===0||typeof arguments[0]!=='function')){return origGetStats.apply(this,[]);} +var fixChromeStats_=function fixChromeStats_(response){var standardReport={};var reports=response.result();reports.forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:{localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[report.type]||report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name);});standardReport[standardStats.id]=standardStats;});return standardReport;};var makeMapStats=function makeMapStats(stats){return new Map(Object.keys(stats).map(function(key){return[key,stats[key]];}));};if(arguments.length>=2){var successCallbackWrapper_=function successCallbackWrapper_(response){args[1](makeMapStats(fixChromeStats_(response)));};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]]);} +return new Promise(function(resolve,reject){origGetStats.apply(_this15,[function(response){resolve(makeMapStats(fixChromeStats_(response)));},reject]);}).then(successCallback,errorCallback);};['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};} +function fixNegotiationNeeded(window){utils.wrapPeerConnectionEvent(window,'negotiationneeded',function(e){var pc=e.target;if(pc.signalingState!=='stable'){return;} +return e;});}},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,getSourceId){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +if(typeof getSourceId!=='function'){console.error('shimGetDisplayMedia: getSourceId argument is not '+'a function');return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){return getSourceId(constraints).then(function(sourceId){var widthSpecified=constraints.video&&constraints.video.width;var heightSpecified=constraints.video&&constraints.video.height;var frameRateSpecified=constraints.video&&constraints.video.frameRate;constraints.video={mandatory:{chromeMediaSource:'desktop',chromeMediaSourceId:sourceId,maxFrameRate:frameRateSpecified||3}};if(widthSpecified){constraints.video.mandatory.maxWidth=widthSpecified;} +if(heightSpecified){constraints.video.mandatory.maxHeight=heightSpecified;} +return window.navigator.mediaDevices.getUserMedia(constraints);});};}},{}],5:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +var logging=utils.log;function shimGetUserMedia(window){var navigator=window&&window.navigator;if(!navigator.mediaDevices){return;} +var browserDetails=utils.detectBrowser(window);var constraintsToChrome_=function constraintsToChrome_(c){if((typeof c==='undefined'?'undefined':_typeof(c))!=='object'||c.mandatory||c.optional){return c;} +var cc={};Object.keys(c).forEach(function(key){if(key==='require'||key==='advanced'||key==='mediaSource'){return;} +var r=_typeof(c[key])==='object'?c[key]:{ideal:c[key]};if(r.exact!==undefined&&typeof r.exact==='number'){r.min=r.max=r.exact;} +var oldname_=function oldname_(prefix,name){if(prefix){return prefix+name.charAt(0).toUpperCase()+name.slice(1);} +return name==='deviceId'?'sourceId':name;};if(r.ideal!==undefined){cc.optional=cc.optional||[];var oc={};if(typeof r.ideal==='number'){oc[oldname_('min',key)]=r.ideal;cc.optional.push(oc);oc={};oc[oldname_('max',key)]=r.ideal;cc.optional.push(oc);}else{oc[oldname_('',key)]=r.ideal;cc.optional.push(oc);}} +if(r.exact!==undefined&&typeof r.exact!=='number'){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_('',key)]=r.exact;}else{['min','max'].forEach(function(mix){if(r[mix]!==undefined){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_(mix,key)]=r[mix];}});}});if(c.advanced){cc.optional=(cc.optional||[]).concat(c.advanced);} +return cc;};var shimConstraints_=function shimConstraints_(constraints,func){if(browserDetails.version>=61){return func(constraints);} +constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&_typeof(constraints.audio)==='object'){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} +if(constraints&&_typeof(constraints.video)==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='undefined'?'undefined':_typeof(face))==='object'?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<66;if(face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment')&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches=void 0;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} +if(matches){return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return d.kind==='videoinput';});var dev=devices.find(function(d){return matches.some(function(match){return d.label.toLowerCase().includes(match);});});if(!dev&&devices.length&&matches.includes('back')){dev=devices[devices.length-1];} +if(dev){constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId};} +constraints.video=constraintsToChrome_(constraints.video);logging('chrome: '+JSON.stringify(constraints));return func(constraints);});}} +constraints.video=constraintsToChrome_(constraints.video);} +logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function shimError_(e){if(browserDetails.version>=64){return e;} +return{name:{PermissionDeniedError:'NotAllowedError',PermissionDismissedError:'NotAllowedError',InvalidStateError:'NotAllowedError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotAllowedError',MediaDeviceKillSwitchOn:'NotAllowedError',TabCaptureError:'AbortError',ScreenCaptureError:'AbortError',DeviceCaptureError:'AbortError'}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function toString(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function getUserMedia_(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){if(onError){onError(shimError_(e));}});});};navigator.getUserMedia=getUserMedia_.bind(navigator);var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length){stream.getTracks().forEach(function(track){track.stop();});throw new DOMException('','NotFoundError');} +return stream;},function(e){return Promise.reject(shimError_(e));});});};}},{"../utils.js":15}],6:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimRTCIceCandidate=shimRTCIceCandidate;exports.shimMaxMessageSize=shimMaxMessageSize;exports.shimSendThrowTypeError=shimSendThrowTypeError;exports.shimConnectionState=shimConnectionState;exports.removeAllowExtmapMixed=removeAllowExtmapMixed;var _sdp=require('sdp');var _sdp2=_interopRequireDefault(_sdp);var _utils=require('./utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function shimRTCIceCandidate(window){if(!window.RTCIceCandidate||window.RTCIceCandidate&&'foundation'in window.RTCIceCandidate.prototype){return;} +var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){if((typeof args==='undefined'?'undefined':_typeof(args))==='object'&&args.candidate&&args.candidate.indexOf('a=')===0){args=JSON.parse(JSON.stringify(args));args.candidate=args.candidate.substr(2);} +if(args.candidate&&args.candidate.length){var nativeCandidate=new NativeRTCIceCandidate(args);var parsedCandidate=_sdp2.default.parseCandidate(args.candidate);var augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment};};return augmentedCandidate;} +return new NativeRTCIceCandidate(args);};window.RTCIceCandidate.prototype=NativeRTCIceCandidate.prototype;utils.wrapPeerConnectionEvent(window,'icecandidate',function(e){if(e.candidate){Object.defineProperty(e,'candidate',{value:new window.RTCIceCandidate(e.candidate),writable:'false'});} +return e;});} +function shimMaxMessageSize(window){if(window.RTCSctpTransport||!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(!('sctp'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'sctp',{get:function get(){return typeof this._sctp==='undefined'?null:this._sctp;}});} +var sctpInDescription=function sctpInDescription(description){var sections=_sdp2.default.splitSections(description.sdp);sections.shift();return sections.some(function(mediaSection){var mLine=_sdp2.default.parseMLine(mediaSection);return mLine&&mLine.kind==='application'&&mLine.protocol.indexOf('SCTP')!==-1;});};var getRemoteFirefoxVersion=function getRemoteFirefoxVersion(description){var match=description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(match===null||match.length<2){return-1;} +var version=parseInt(match[1],10);return version!==version?-1:version;};var getCanSendMaxMessageSize=function getCanSendMaxMessageSize(remoteIsFirefox){var canSendMaxMessageSize=65536;if(browserDetails.browser==='firefox'){if(browserDetails.version<57){if(remoteIsFirefox===-1){canSendMaxMessageSize=16384;}else{canSendMaxMessageSize=2147483637;}}else if(browserDetails.version<60){canSendMaxMessageSize=browserDetails.version===57?65535:65536;}else{canSendMaxMessageSize=2147483637;}} +return canSendMaxMessageSize;};var getMaxMessageSize=function getMaxMessageSize(description,remoteIsFirefox){var maxMessageSize=65536;if(browserDetails.browser==='firefox'&&browserDetails.version===57){maxMessageSize=65535;} +var match=_sdp2.default.matchPrefix(description.sdp,'a=max-message-size:');if(match.length>0){maxMessageSize=parseInt(match[0].substr(19),10);}else if(browserDetails.browser==='firefox'&&remoteIsFirefox!==-1){maxMessageSize=2147483637;} +return maxMessageSize;};var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){this._sctp=null;if(sctpInDescription(arguments[0])){var isFirefox=getRemoteFirefoxVersion(arguments[0]);var canSendMMS=getCanSendMaxMessageSize(isFirefox);var remoteMMS=getMaxMessageSize(arguments[0],isFirefox);var maxMessageSize=void 0;if(canSendMMS===0&&remoteMMS===0){maxMessageSize=Number.POSITIVE_INFINITY;}else if(canSendMMS===0||remoteMMS===0){maxMessageSize=Math.max(canSendMMS,remoteMMS);}else{maxMessageSize=Math.min(canSendMMS,remoteMMS);} +var sctp={};Object.defineProperty(sctp,'maxMessageSize',{get:function get(){return maxMessageSize;}});this._sctp=sctp;} +return origSetRemoteDescription.apply(this,arguments);};} +function shimSendThrowTypeError(window){if(!(window.RTCPeerConnection&&'createDataChannel'in window.RTCPeerConnection.prototype)){return;} +function wrapDcSend(dc,pc){var origDataChannelSend=dc.send;dc.send=function(){var data=arguments[0];var length=data.length||data.size||data.byteLength;if(dc.readyState==='open'&&pc.sctp&&length>pc.sctp.maxMessageSize){throw new TypeError('Message too large (can send a maximum of '+pc.sctp.maxMessageSize+' bytes)');} +return origDataChannelSend.apply(dc,arguments);};} +var origCreateDataChannel=window.RTCPeerConnection.prototype.createDataChannel;window.RTCPeerConnection.prototype.createDataChannel=function(){var dataChannel=origCreateDataChannel.apply(this,arguments);wrapDcSend(dataChannel,this);return dataChannel;};utils.wrapPeerConnectionEvent(window,'datachannel',function(e){wrapDcSend(e.channel,e.target);return e;});} +function shimConnectionState(window){if(!window.RTCPeerConnection||'connectionState'in window.RTCPeerConnection.prototype){return;} +var proto=window.RTCPeerConnection.prototype;Object.defineProperty(proto,'connectionState',{get:function get(){return{completed:'connected',checking:'connecting'}[this.iceConnectionState]||this.iceConnectionState;},enumerable:true,configurable:true});Object.defineProperty(proto,'onconnectionstatechange',{get:function get(){return this._onconnectionstatechange||null;},set:function set(cb){if(this._onconnectionstatechange){this.removeEventListener('connectionstatechange',this._onconnectionstatechange);delete this._onconnectionstatechange;} +if(cb){this.addEventListener('connectionstatechange',this._onconnectionstatechange=cb);}},enumerable:true,configurable:true});['setLocalDescription','setRemoteDescription'].forEach(function(method){var origMethod=proto[method];proto[method]=function(){if(!this._connectionstatechangepoly){this._connectionstatechangepoly=function(e){var pc=e.target;if(pc._lastConnectionState!==pc.connectionState){pc._lastConnectionState=pc.connectionState;var newEvent=new Event('connectionstatechange',e);pc.dispatchEvent(newEvent);} +return e;};this.addEventListener('iceconnectionstatechange',this._connectionstatechangepoly);} +return origMethod.apply(this,arguments);};});} +function removeAllowExtmapMixed(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(browserDetails.browser==='chrome'&&browserDetails.version>=71){return;} +var nativeSRD=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(desc){if(desc&&desc.sdp&&desc.sdp.indexOf('\na=extmap-allow-mixed')!==-1){desc.sdp=desc.sdp.split('\n').filter(function(line){return line.trim()!=='a=extmap-allow-mixed';}).join('\n');} +return nativeSRD.apply(this,arguments);};}},{"./utils":15,"sdp":17}],7:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimPeerConnection=shimPeerConnection;exports.shimReplaceTrack=shimReplaceTrack;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);var _filtericeservers=require('./filtericeservers');var _rtcpeerconnectionShim=require('rtcpeerconnection-shim');var _rtcpeerconnectionShim2=_interopRequireDefault(_rtcpeerconnectionShim);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} +if(!window.RTCSessionDescription){window.RTCSessionDescription=function(args){return args;};} +if(browserDetails.version<15025){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,'enabled');Object.defineProperty(window.MediaStreamTrack.prototype,'enabled',{set:function set(value){origMSTEnabled.set.call(this,value);var ev=new Event('enabled');ev.enabled=value;this.dispatchEvent(ev);}});}} +if(window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=new window.RTCDtmfSender(this);}else if(this.track.kind==='video'){this._dtmf=null;}} +return this._dtmf;}});} +if(window.RTCDtmfSender&&!window.RTCDTMFSender){window.RTCDTMFSender=window.RTCDtmfSender;} +var RTCPeerConnectionShim=(0,_rtcpeerconnectionShim2.default)(window,browserDetails.version);window.RTCPeerConnection=function(config){if(config&&config.iceServers){config.iceServers=(0,_filtericeservers.filterIceServers)(config.iceServers,browserDetails.version);utils.log('ICE servers after filtering:',config.iceServers);} +return new RTCPeerConnectionShim(config);};window.RTCPeerConnection.prototype=RTCPeerConnectionShim.prototype;} +function shimReplaceTrack(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.filterIceServers=filterIceServers;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){utils.deprecated('RTCIceServer.url','RTCIceServer.urls');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){if(url.indexOf('stun:')===0){return false;} +var validTurn=url.startsWith('turn')&&!url.startsWith('turn:[')&&url.includes('transport=udp');if(validTurn&&!hasTurn){hasTurn=true;return true;} +return validTurn&&!hasTurn;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});}},{"../utils":15}],9:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window){if(!('getDisplayMedia'in window.navigator)){return;} +if(!window.navigator.mediaDevices){return;} +if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=window.navigator.getDisplayMedia.bind(window.navigator.mediaDevices);}},{}],10:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetUserMedia=shimGetUserMedia;function shimGetUserMedia(window){var navigator=window&&window.navigator;var shimError_=function shimError_(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function toString(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};}},{}],11:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimOnTrack=shimOnTrack;exports.shimPeerConnection=shimPeerConnection;exports.shimSenderGetStats=shimSenderGetStats;exports.shimReceiverGetStats=shimReceiverGetStats;exports.shimRemoveStream=shimRemoveStream;exports.shimRTCDataChannel=shimRTCDataChannel;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCTrackEvent&&'receiver'in window.RTCTrackEvent.prototype&&!('transceiver'in window.RTCTrackEvent.prototype)){Object.defineProperty(window.RTCTrackEvent.prototype,'transceiver',{get:function get(){return{receiver:this.receiver};}});}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} +if(!window.RTCPeerConnection&&window.mozRTCPeerConnection){window.RTCPeerConnection=window.mozRTCPeerConnection;} +['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};var modernStatsTypes={inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'};var nativeGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,onSucc,onErr){return nativeGetStats.apply(this,[selector||null]).then(function(stats){if(browserDetails.version<53&&!onSucc){try{stats.forEach(function(stat){stat.type=modernStatsTypes[stat.type]||stat.type;});}catch(e){if(e.name!=='TypeError'){throw e;} +stats.forEach(function(stat,i){stats.set(i,Object.assign({},stat,{type:modernStatsTypes[stat.type]||stat.type}));});}} +return stats;}).then(onSucc,onErr);};} +function shimSenderGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpSender.prototype){return;} +var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map());};} +function shimReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpReceiver.prototype){return;} +var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this2=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this2;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track);};} +function shimRemoveStream(window){if(!window.RTCPeerConnection||'removeStream'in window.RTCPeerConnection.prototype){return;} +window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;utils.deprecated('removeStream','removeTrack');this.getSenders().forEach(function(sender){if(sender.track&&stream.getTracks().includes(sender.track)){_this3.removeTrack(sender);}});};} +function shimRTCDataChannel(window){if(window.DataChannel&&!window.RTCDataChannel){window.RTCDataChannel=window.DataChannel;}}},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,preferredMediaSource){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){if(!(constraints&&constraints.video)){var err=new DOMException('getDisplayMedia without video '+'constraints is undefined');err.name='NotFoundError';err.code=8;return Promise.reject(err);} +if(constraints.video===true){constraints.video={mediaSource:preferredMediaSource};}else{constraints.video.mediaSource=preferredMediaSource;} +return window.navigator.mediaDevices.getUserMedia(constraints);};}},{}],13:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimGetUserMedia(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var MediaStreamTrack=window&&window.MediaStreamTrack;navigator.getUserMedia=function(constraints,onSuccess,onError){utils.deprecated('navigator.getUserMedia','navigator.mediaDevices.getUserMedia');navigator.mediaDevices.getUserMedia(constraints).then(onSuccess,onError);};if(!(browserDetails.version>55&&'autoGainControl'in navigator.mediaDevices.getSupportedConstraints())){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};var nativeGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){if((typeof c==='undefined'?'undefined':_typeof(c))==='object'&&_typeof(c.audio)==='object'){c=JSON.parse(JSON.stringify(c));remap(c.audio,'autoGainControl','mozAutoGainControl');remap(c.audio,'noiseSuppression','mozNoiseSuppression');} +return nativeGetUserMedia(c);};if(MediaStreamTrack&&MediaStreamTrack.prototype.getSettings){var nativeGetSettings=MediaStreamTrack.prototype.getSettings;MediaStreamTrack.prototype.getSettings=function(){var obj=nativeGetSettings.apply(this,arguments);remap(obj,'mozAutoGainControl','autoGainControl');remap(obj,'mozNoiseSuppression','noiseSuppression');return obj;};} +if(MediaStreamTrack&&MediaStreamTrack.prototype.applyConstraints){var nativeApplyConstraints=MediaStreamTrack.prototype.applyConstraints;MediaStreamTrack.prototype.applyConstraints=function(c){if(this.kind==='audio'&&(typeof c==='undefined'?'undefined':_typeof(c))==='object'){c=JSON.parse(JSON.stringify(c));remap(c,'autoGainControl','mozAutoGainControl');remap(c,'noiseSuppression','mozNoiseSuppression');} +return nativeApplyConstraints.apply(this,[c]);};}}}},{"../utils":15}],14:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimLocalStreamsAPI=shimLocalStreamsAPI;exports.shimRemoteStreamsAPI=shimRemoteStreamsAPI;exports.shimCallbacksAPI=shimCallbacksAPI;exports.shimGetUserMedia=shimGetUserMedia;exports.shimConstraints=shimConstraints;exports.shimRTCIceServerUrls=shimRTCIceServerUrls;exports.shimTrackEventTransceiver=shimTrackEventTransceiver;exports.shimCreateOfferLegacy=shimCreateOfferLegacy;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimLocalStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getLocalStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getLocalStreams=function(){if(!this._localStreams){this._localStreams=[];} +return this._localStreams;};} +if(!('addStream'in window.RTCPeerConnection.prototype)){var _addTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addStream=function(stream){var _this=this;if(!this._localStreams){this._localStreams=[];} +if(!this._localStreams.includes(stream)){this._localStreams.push(stream);} +stream.getTracks().forEach(function(track){return _addTrack.call(_this,track,stream);});};window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(stream){if(!this._localStreams){this._localStreams=[stream];}else if(!this._localStreams.includes(stream)){this._localStreams.push(stream);}} +return _addTrack.call(this,track,stream);};} +if(!('removeStream'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.removeStream=function(stream){var _this2=this;if(!this._localStreams){this._localStreams=[];} +var index=this._localStreams.indexOf(stream);if(index===-1){return;} +this._localStreams.splice(index,1);var tracks=stream.getTracks();this.getSenders().forEach(function(sender){if(tracks.includes(sender.track)){_this2.removeTrack(sender);}});};}} +function shimRemoteStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getRemoteStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[];};} +if(!('onaddstream'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'onaddstream',{get:function get(){return this._onaddstream;},set:function set(f){var _this3=this;if(this._onaddstream){this.removeEventListener('addstream',this._onaddstream);this.removeEventListener('track',this._onaddstreampoly);} +this.addEventListener('addstream',this._onaddstream=f);this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!_this3._remoteStreams){_this3._remoteStreams=[];} +if(_this3._remoteStreams.includes(stream)){return;} +_this3._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;_this3.dispatchEvent(event);});});}});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var pc=this;if(!this._onaddstreampoly){this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!pc._remoteStreams){pc._remoteStreams=[];} +if(pc._remoteStreams.indexOf(stream)>=0){return;} +pc._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;pc.dispatchEvent(event);});});} +return origSetRemoteDescription.apply(pc,arguments);};}} +function shimCallbacksAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +var prototype=window.RTCPeerConnection.prototype;var createOffer=prototype.createOffer;var createAnswer=prototype.createAnswer;var setLocalDescription=prototype.setLocalDescription;var setRemoteDescription=prototype.setRemoteDescription;var addIceCandidate=prototype.addIceCandidate;prototype.createOffer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createOffer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.createAnswer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createAnswer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};var withCallback=function withCallback(description,successCallback,failureCallback){var promise=setLocalDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setLocalDescription=withCallback;withCallback=function withCallback(description,successCallback,failureCallback){var promise=setRemoteDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setRemoteDescription=withCallback;withCallback=function withCallback(candidate,successCallback,failureCallback){var promise=addIceCandidate.apply(this,[candidate]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.addIceCandidate=withCallback;} +function shimGetUserMedia(window){var navigator=window&&window.navigator;if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){var mediaDevices=navigator.mediaDevices;var _getUserMedia=mediaDevices.getUserMedia.bind(mediaDevices);navigator.mediaDevices.getUserMedia=function(constraints){return _getUserMedia(shimConstraints(constraints));};} +if(!navigator.getUserMedia&&navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){navigator.getUserMedia=function(constraints,cb,errcb){navigator.mediaDevices.getUserMedia(constraints).then(cb,errcb);}.bind(navigator);}} +function shimConstraints(constraints){if(constraints&&constraints.video!==undefined){return Object.assign({},constraints,{video:utils.compactObject(constraints.video)});} +return constraints;} +function shimRTCIceServerUrls(window){var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i=pos&&parseInt(match[pos],10);} +function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(!window.RTCPeerConnection){return;} +var proto=window.RTCPeerConnection.prototype;var nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap){return nativeAddEventListener.apply(this,arguments);} +var wrappedCallback=function wrappedCallback(e){var modifiedEvent=wrapper(e);if(modifiedEvent){cb(modifiedEvent);}};this._eventMap=this._eventMap||{};this._eventMap[cb]=wrappedCallback;return nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback]);};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb]){return nativeRemoveEventListener.apply(this,arguments);} +var unwrappedCb=this._eventMap[cb];delete this._eventMap[cb];return nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb]);};Object.defineProperty(proto,'on'+eventNameToWrap,{get:function get(){return this['_on'+eventNameToWrap];},set:function set(cb){if(this['_on'+eventNameToWrap]){this.removeEventListener(eventNameToWrap,this['_on'+eventNameToWrap]);delete this['_on'+eventNameToWrap];} +if(cb){this.addEventListener(eventNameToWrap,this['_on'+eventNameToWrap]=cb);}},enumerable:true,configurable:true});} +function disableLog(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +logDisabled_=bool;return bool?'adapter.js logging disabled':'adapter.js logging enabled';} +function disableWarnings(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +deprecationWarnings_=!bool;return'adapter.js deprecation warnings '+(bool?'disabled':'enabled');} +function log(){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'){if(logDisabled_){return;} +if(typeof console!=='undefined'&&typeof console.log==='function'){console.log.apply(console,arguments);}}} +function deprecated(oldMethod,newMethod){if(!deprecationWarnings_){return;} +console.warn(oldMethod+' is deprecated, please use '+newMethod+' instead.');} +function detectBrowser(window){var navigator=window.navigator;var result={browser:null,version:null};if(typeof window==='undefined'||!window.navigator){result.browser='Not a browser.';return result;} +if(navigator.mozGetUserMedia){result.browser='firefox';result.version=extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);}else if(navigator.webkitGetUserMedia){result.browser='chrome';result.version=extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)){result.browser='edge';result.version=extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);}else if(window.RTCPeerConnection&&navigator.userAgent.match(/AppleWebKit\/(\d+)\./)){result.browser='safari';result.version=extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Not a supported browser.';return result;} +return result;} +function compactObject(data){if((typeof data==='undefined'?'undefined':_typeof(data))!=='object'){return data;} +return Object.keys(data).reduce(function(accumulator,key){var isObject=_typeof(data[key])==='object';var value=isObject?compactObject(data[key]):data[key];var isEmptyObject=isObject&&!Object.keys(value).length;if(value===undefined||isEmptyObject){return accumulator;} +return Object.assign(accumulator,_defineProperty({},key,value));},{});}},{}],16:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');function fixStatsType(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;} +function writeMediaSection(transceiver,caps,type,stream,dtlsRole){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':dtlsRole||'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var trackId=transceiver.rtpSender._initialTrackId||transceiver.rtpSender.track.id;transceiver.rtpSender._initialTrackId=trackId;var msid='msid:'+(stream?stream.id:'-')+' '+ +trackId+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){console.warn('RTCIceServer.url is deprecated! Use urls instead.');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){var validTurn=url.indexOf('turn:')===0&&url.indexOf('transport=udp')!==-1&&url.indexOf('turn:[')===-1&&!hasTurn;if(validTurn){hasTurn=true;return true;} +return url.indexOf('stun:')===0&&edgeVersion>=14393&&url.indexOf('?transport=udp')===-1;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});} +function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;i--){this._iceGatherers.push(new window.RTCIceGatherer({iceServers:config.iceServers,gatherPolicy:config.iceTransportPolicy}));}}else{config.iceCandidatePoolSize=0;} +this._config=config;this.transceivers=[];this._sdpSessionId=SDPUtils.generateSessionId();this._sdpSessionVersion=0;this._dtlsRole=undefined;this._isClosed=false;};Object.defineProperty(RTCPeerConnection.prototype,'localDescription',{configurable:true,get:function(){return this._localDescription;}});Object.defineProperty(RTCPeerConnection.prototype,'remoteDescription',{configurable:true,get:function(){return this._remoteDescription;}});RTCPeerConnection.prototype.onicecandidate=null;RTCPeerConnection.prototype.onaddstream=null;RTCPeerConnection.prototype.ontrack=null;RTCPeerConnection.prototype.onremovestream=null;RTCPeerConnection.prototype.onsignalingstatechange=null;RTCPeerConnection.prototype.oniceconnectionstatechange=null;RTCPeerConnection.prototype.onconnectionstatechange=null;RTCPeerConnection.prototype.onicegatheringstatechange=null;RTCPeerConnection.prototype.onnegotiationneeded=null;RTCPeerConnection.prototype.ondatachannel=null;RTCPeerConnection.prototype._dispatchEvent=function(name,event){if(this._isClosed){return;} +this.dispatchEvent(event);if(typeof this['on'+name]==='function'){this['on'+name](event);}};RTCPeerConnection.prototype._emitGatheringStateChange=function(){var event=new Event('icegatheringstatechange');this._dispatchEvent('icegatheringstatechange',event);};RTCPeerConnection.prototype.getConfiguration=function(){return this._config;};RTCPeerConnection.prototype.getLocalStreams=function(){return this.localStreams;};RTCPeerConnection.prototype.getRemoteStreams=function(){return this.remoteStreams;};RTCPeerConnection.prototype._createTransceiver=function(kind,doNotAdd){var hasBundleTransport=this.transceivers.length>0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,associatedRemoteMediaStreams:[],wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} +if(!doNotAdd){this.transceivers.push(transceiver);} +return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call addTrack on a closed peerconnection.');} +var alreadyExists=this.transceivers.find(function(s){return s.track===track;});if(alreadyExists){throw makeError('InvalidAccessError','Track already exists.');} +var transceiver;for(var i=0;i=15025){stream.getTracks().forEach(function(track){pc.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){pc.addTrack(track,clonedStream);});}};RTCPeerConnection.prototype.removeTrack=function(sender){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call removeTrack on a closed peerconnection.');} +if(!(sender instanceof window.RTCRtpSender)){throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.');} +var transceiver=this.transceivers.find(function(t){return t.rtpSender===sender;});if(!transceiver){throw makeError('InvalidAccessError','Sender was not created by this connection.');} +var stream=transceiver.stream;transceiver.rtpSender.stop();transceiver.rtpSender=null;transceiver.track=null;transceiver.stream=null;var localStreams=this.transceivers.map(function(t){return t.stream;});if(localStreams.indexOf(stream)===-1&&this.localStreams.indexOf(stream)>-1){this.localStreams.splice(this.localStreams.indexOf(stream),1);} +this._maybeFireNegotiationNeeded();};RTCPeerConnection.prototype.removeStream=function(stream){var pc=this;stream.getTracks().forEach(function(track){var sender=pc.getSenders().find(function(s){return s.track===track;});if(sender){pc.removeTrack(sender);}});};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(sdpMLineIndex,usingBundle){var pc=this;if(usingBundle&&sdpMLineIndex>0){return this.transceivers[0].iceGatherer;}else if(this._iceGatherers.length){return this._iceGatherers.shift();} +var iceGatherer=new window.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});Object.defineProperty(iceGatherer,'state',{value:'new',writable:true});this.transceivers[sdpMLineIndex].bufferedCandidateEvents=[];this.transceivers[sdpMLineIndex].bufferCandidates=function(event){var end=!event.candidate||Object.keys(event.candidate).length===0;iceGatherer.state=end?'completed':'gathering';if(pc.transceivers[sdpMLineIndex].bufferedCandidateEvents!==null){pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event);}};iceGatherer.addEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);return iceGatherer;};RTCPeerConnection.prototype._gather=function(mid,sdpMLineIndex){var pc=this;var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer.onlocalcandidate){return;} +var bufferedCandidateEvents=this.transceivers[sdpMLineIndex].bufferedCandidateEvents;this.transceivers[sdpMLineIndex].bufferedCandidateEvents=null;iceGatherer.removeEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);iceGatherer.onlocalcandidate=function(evt){if(pc.usingBundle&&sdpMLineIndex>0){return;} +var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state==='new'||iceGatherer.state==='gathering'){iceGatherer.state='completed';}}else{if(iceGatherer.state==='new'){iceGatherer.state='gathering';} +cand.component=1;cand.ufrag=iceGatherer.getLocalParameters().usernameFragment;var serializedCandidate=SDPUtils.writeCandidate(cand);event.candidate=Object.assign(event.candidate,SDPUtils.parseCandidate(serializedCandidate));event.candidate.candidate=serializedCandidate;event.candidate.toJSON=function(){return{candidate:event.candidate.candidate,sdpMid:event.candidate.sdpMid,sdpMLineIndex:event.candidate.sdpMLineIndex,usernameFragment:event.candidate.usernameFragment};};} +var sections=SDPUtils.getMediaSections(pc._localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex]+='a=end-of-candidates\r\n';} +pc._localDescription.sdp=SDPUtils.getDescription(pc._localDescription.sdp)+ +sections.join('');var complete=pc.transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});if(pc.iceGatheringState!=='gathering'){pc.iceGatheringState='gathering';pc._emitGatheringStateChange();} +if(!end){pc._dispatchEvent('icecandidate',event);} +if(complete){pc._dispatchEvent('icecandidate',new Event('icecandidate'));pc.iceGatheringState='complete';pc._emitGatheringStateChange();}};window.setTimeout(function(){bufferedCandidateEvents.forEach(function(e){iceGatherer.onlocalcandidate(e);});},0);};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var pc=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){pc._updateIceConnectionState();pc._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){pc._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});pc._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} +var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} +var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlsstatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} +transceiver.rtpSender.send(params);} +if(recv&&transceiver.rtpReceiver&¶ms.codecs.length>0){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} +if(transceiver.recvEncodingParameters.length){params.encodings=transceiver.recvEncodingParameters;}else{params.encodings=[{}];} +params.rtcp={compound:transceiver.rtcpParameters.compound};if(transceiver.rtcpParameters.cname){params.rtcp.cname=transceiver.rtcpParameters.cname;} +if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} +transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setLocalDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set local '+description.type+' in state '+pc.signalingState));} +var sections;var sessionpart;if(description.type==='offer'){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);pc.transceivers[sdpMLineIndex].localCapabilities=caps;});pc.transceivers.forEach(function(transceiver,sdpMLineIndex){pc._gather(transceiver.mid,sdpMLineIndex);});}else if(description.type==='answer'){sections=SDPUtils.splitSections(pc._remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=pc.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;if(!rejected&&!transceiver.rejected){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} +if(!pc.usingBundle||sdpMLineIndex===0){pc._gather(transceiver.mid,sdpMLineIndex);if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var params=getCommonCapabilities(localCapabilities,remoteCapabilities);pc._transceive(transceiver,params.codecs.length>0,false);}});} +pc._localDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-local-offer');}else{pc._updateSignalingState('stable');} +return Promise.resolve();};RTCPeerConnection.prototype.setRemoteDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set remote '+description.type+' in state '+pc.signalingState));} +var streams={};pc.remoteStreams.forEach(function(stream){streams[stream.id]=stream;});var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;pc.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){pc.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{pc.canTrickleIceCandidates=false;} +sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(rejected||(kind==='application'&&(protocol==='DTLS/SCTP'||protocol==='UDP/DTLS/SCTP'))){pc.transceivers[sdpMLineIndex]={mid:mid,kind:kind,protocol:protocol,rejected:true};return;} +if(!rejected&&pc.transceivers[sdpMLineIndex]&&pc.transceivers[sdpMLineIndex].rejected){pc.transceivers[sdpMLineIndex]=pc._createTransceiver(kind,true);} +var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} +recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&pc.transceivers[sdpMLineIndex]){pc._disposeIceAndDtlsTransports(sdpMLineIndex);pc.transceivers[sdpMLineIndex].iceGatherer=pc.transceivers[0].iceGatherer;pc.transceivers[sdpMLineIndex].iceTransport=pc.transceivers[0].iceTransport;pc.transceivers[sdpMLineIndex].dtlsTransport=pc.transceivers[0].dtlsTransport;if(pc.transceivers[sdpMLineIndex].rtpSender){pc.transceivers[sdpMLineIndex].rtpSender.setTransport(pc.transceivers[0].dtlsTransport);} +if(pc.transceivers[sdpMLineIndex].rtpReceiver){pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(pc.transceivers[0].dtlsTransport);}} +if(description.type==='offer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex]||pc._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,usingBundle);} +if(cands.length&&transceiver.iceTransport.state==='new'){if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+2)*1001}];var isNewTrack=false;if(direction==='sendrecv'||direction==='sendonly'){isNewTrack=!transceiver.rtpReceiver;rtpReceiver=transceiver.rtpReceiver||new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);if(isNewTrack){var stream;track=rtpReceiver.track;if(remoteMsid&&remoteMsid.stream==='-'){}else if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} +Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});stream=streams[remoteMsid.stream];}else{if(!streams.default){streams.default=new window.MediaStream();} +stream=streams.default;} +if(stream){addTrackToStreamAndFireEvent(track,stream);transceiver.associatedRemoteMediaStreams.push(stream);} +receiverList.push([track,rtpReceiver,stream]);}}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track){transceiver.associatedRemoteMediaStreams.forEach(function(s){var nativeTrack=s.getTracks().find(function(t){return t.id===transceiver.rtpReceiver.track.id;});if(nativeTrack){removeTrackFromStreamAndFireEvent(nativeTrack,s);}});transceiver.associatedRemoteMediaStreams=[];} +transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;pc._transceive(pc.transceivers[sdpMLineIndex],false,isNewTrack);}else if(description.type==='answer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;pc.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;pc.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;pc.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if(cands.length&&iceTransport.state==='new'){if((isIceLite||isComplete)&&(!usingBundle||sdpMLineIndex===0)){iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +if(!usingBundle||sdpMLineIndex===0){if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +pc._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams[remoteMsid.stream]);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams.default);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});if(pc._dtlsRole===undefined){pc._dtlsRole=description.type==='offer'?'active':'passive';} +pc._remoteDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-remote-offer');}else{pc._updateSignalingState('stable');} +Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){if(pc.remoteStreams.indexOf(stream)===-1){pc.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;window.setTimeout(function(){pc._dispatchEvent('addstream',event);});} +receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} +fireAddTrack(pc,track,receiver,[stream]);});}});receiverList.forEach(function(item){if(item[2]){return;} +fireAddTrack(pc,item[0],item[1],[]);});window.setTimeout(function(){if(!(pc&&pc.transceivers)){return;} +pc.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);return Promise.resolve();};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} +if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} +if(transceiver.rtpSender){transceiver.rtpSender.stop();} +if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._isClosed=true;this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this._dispatchEvent('signalingstatechange',event);};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var pc=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} +this.needNegotiation=true;window.setTimeout(function(){if(pc.needNegotiation){pc.needNegotiation=false;var event=new Event('negotiationneeded');pc._dispatchEvent('negotiationneeded',event);}},0);};RTCPeerConnection.prototype._updateIceConnectionState=function(){var newState;var states={'new':0,closed:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;}});newState='new';if(states.failed>0){newState='failed';}else if(states.checking>0){newState='checking';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';}else if(states.completed>0){newState='completed';} +if(newState!==this.iceConnectionState){this.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this._dispatchEvent('iceconnectionstatechange',event);}};RTCPeerConnection.prototype._updateConnectionState=function(){var newState;var states={'new':0,closed:0,connecting:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.dtlsTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;}});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';} +if(newState!==this.connectionState){this.connectionState=newState;var event=new Event('connectionstatechange');this._dispatchEvent('connectionstatechange',event);}};RTCPeerConnection.prototype.createOffer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createOffer after close'));} +var numAudioTracks=pc.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=pc.transceivers.filter(function(t){return t.kind==='video';}).length;var offerOptions=arguments[0];if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} +if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} +if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} +pc.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){pc._createTransceiver('audio');numAudioTracks--;} +if(numVideoTracks>0){pc._createTransceiver('video');numVideoTracks--;}} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);pc.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=transceiver.mid||SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,pc.usingBundle);} +var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';} +if(transceiver.remoteCapabilities&&transceiver.remoteCapabilities.codecs){transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec){if(codec.name.toLowerCase()===remoteCodec.name.toLowerCase()&&codec.clockRate===remoteCodec.clockRate){codec.preferredPayloadType=remoteCodec.payloadType;}});}});localCapabilities.headerExtensions.forEach(function(hdrExt){var remoteExtensions=transceiver.remoteCapabilities&&transceiver.remoteCapabilities.headerExtensions||[];remoteExtensions.forEach(function(rHdrExt){if(hdrExt.uri===rHdrExt.uri){hdrExt.id=rHdrExt.id;}});});var sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'&&!sendEncodingParameters[0].rtx){sendEncodingParameters[0].rtx={ssrc:sendEncodingParameters[0].ssrc+1};}} +if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} +transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(pc._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';pc.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream,pc._dtlsRole);sdp+='a=rtcp-rsize\r\n';if(transceiver.iceGatherer&&pc.iceGatheringState!=='new'&&(sdpMLineIndex===0||!pc.usingBundle)){transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1;sdp+='a='+SDPUtils.writeCandidate(cand)+'\r\n';});if(transceiver.iceGatherer.state==='completed'){sdp+='a=end-of-candidates\r\n';}}});var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.createAnswer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer after close'));} +if(!(pc.signalingState==='have-remote-offer'||pc.signalingState==='have-local-pranswer')){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer in signalingState '+pc.signalingState));} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);if(pc.usingBundle){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';var mediaSectionsInOffer=SDPUtils.getMediaSections(pc._remoteDescription.sdp).length;pc.transceivers.forEach(function(transceiver,sdpMLineIndex){if(sdpMLineIndex+1>mediaSectionsInOffer){return;} +if(transceiver.rejected){if(transceiver.kind==='application'){if(transceiver.protocol==='DTLS/SCTP'){sdp+='m=application 0 DTLS/SCTP 5000\r\n';}else{sdp+='m=application 0 '+transceiver.protocol+' webrtc-datachannel\r\n';}}else if(transceiver.kind==='audio'){sdp+='m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n'+'a=rtpmap:0 PCMU/8000\r\n';}else if(transceiver.kind==='video'){sdp+='m=video 0 UDP/TLS/RTP/SAVPF 120\r\n'+'a=rtpmap:120 VP8/90000\r\n';} +sdp+='c=IN IP4 0.0.0.0\r\n'+'a=inactive\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} +if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} +if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'&&!transceiver.sendEncodingParameters[0].rtx){transceiver.sendEncodingParameters[0].rtx={ssrc:transceiver.sendEncodingParameters[0].ssrc+1};}}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +sdp+=writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream,pc._dtlsRole);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.addIceCandidate=function(candidate){var pc=this;var sections;if(candidate&&!(candidate.sdpMLineIndex!==undefined||candidate.sdpMid)){return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required'));} +return new Promise(function(resolve,reject){if(!pc._remoteDescription){return reject(makeError('InvalidStateError','Can not add ICE candidate without a remote description'));}else if(!candidate||candidate.candidate===''){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return resolve();} +if(cand.component&&cand.component!==1){return resolve();} +if(sdpMLineIndex===0||(sdpMLineIndex>0&&transceiver.iceTransport!==pc.transceivers[0].iceTransport)){if(!maybeAddCandidate(transceiver.iceTransport,cand)){return reject(makeError('OperationError','Can not add ICE candidate'));}} +var candidateString=candidate.candidate.trim();if(candidateString.indexOf('a=')===0){candidateString=candidateString.substr(2);} +sections=SDPUtils.getMediaSections(pc._remoteDescription.sdp);sections[sdpMLineIndex]+='a='+ +(cand.type?candidateString:'end-of-candidates') ++'\r\n';pc._remoteDescription.sdp=SDPUtils.getDescription(pc._remoteDescription.sdp)+ +sections.join('');}else{return reject(makeError('OperationError','Can not add ICE candidate'));}} +resolve();});};RTCPeerConnection.prototype.getStats=function(selector){if(selector&&selector instanceof window.MediaStreamTrack){var senderOrReceiver=null;this.transceivers.forEach(function(transceiver){if(transceiver.rtpSender&&transceiver.rtpSender.track===selector){senderOrReceiver=transceiver.rtpSender;}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track===selector){senderOrReceiver=transceiver.rtpReceiver;}});if(!senderOrReceiver){throw makeError('InvalidAccessError','Invalid selector.');} +return senderOrReceiver.getStats();} +var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});return Promise.all(promises).then(function(allStats){var results=new Map();allStats.forEach(function(stats){stats.forEach(function(stat){results.set(stat.id,stat);});});return results;});};var ortcObjects=['RTCRtpSender','RTCRtpReceiver','RTCIceGatherer','RTCIceTransport','RTCDtlsTransport'];ortcObjects.forEach(function(ortcObjectName){var obj=window[ortcObjectName];if(obj&&obj.prototype&&obj.prototype.getStats){var nativeGetstats=obj.prototype.getStats;obj.prototype.getStats=function(){return nativeGetstats.apply(this).then(function(nativeStats){var mapStats=new Map();Object.keys(nativeStats).forEach(function(id){nativeStats[id].type=fixStatsType(nativeStats[id]);mapStats.set(id,nativeStats[id]);});return mapStats;});};}});var methods=['createOffer','createAnswer'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[0]==='function'||typeof args[1]==='function'){return nativeMethod.apply(this,[arguments[2]]).then(function(description){if(typeof args[0]==='function'){args[0].apply(null,[description]);}},function(error){if(typeof args[1]==='function'){args[1].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});methods=['setLocalDescription','setRemoteDescription','addIceCandidate'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'||typeof args[2]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}},function(error){if(typeof args[2]==='function'){args[2].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});['getStats'].forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}});} +return nativeMethod.apply(this,arguments);};});return RTCPeerConnection;};},{"sdp":17}],17:[function(require,module,exports){'use strict';var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10);};SDPUtils.localCName=SDPUtils.generateIdentifier();SDPUtils.splitLines=function(blob){return blob.trim().split('\n').map(function(line){return line.trim();});};SDPUtils.splitSections=function(blob){var parts=blob.split('\nm=');return parts.map(function(part,index){return(index>0?'m='+part:part).trim()+'\r\n';});};SDPUtils.getDescription=function(blob){var sections=SDPUtils.splitSections(blob);return sections&§ions[0];};SDPUtils.getMediaSections=function(blob){var sections=SDPUtils.splitSections(blob);sections.shift();return sections;};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} +var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],address:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i0?parts[0].split('/')[1]:'sendrecv',uri:parts[1]};};SDPUtils.writeExtmap=function(headerExtension){return'a=extmap:'+(headerExtension.id||headerExtension.preferredId)+ +(headerExtension.direction&&headerExtension.direction!=='sendrecv'?'/'+headerExtension.direction:'')+' '+headerExtension.uri+'\r\n';};SDPUtils.parseFmtp=function(line){var parsed={};var kv;var parts=line.substr(line.indexOf(' ')+1).split(';');for(var j=0;j-1){parts.attribute=line.substr(sp+1,colon-sp-1);parts.value=line.substr(colon+1);}else{parts.attribute=line.substr(sp+1);} +return parts;};SDPUtils.parseSsrcGroup=function(line){var parts=line.substr(13).split(' ');return{semantics:parts.shift(),ssrcs:parts.map(function(ssrc){return parseInt(ssrc,10);})};};SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,'a=mid:')[0];if(mid){return mid.substr(6);}};SDPUtils.parseFingerprint=function(line){var parts=line.substr(14).split(' ');return{algorithm:parts[0].toLowerCase(),value:parts[1]};};SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.matchPrefix(mediaSection+sessionpart,'a=fingerprint:');return{role:'auto',fingerprints:lines.map(SDPUtils.parseFingerprint)};};SDPUtils.writeDtlsParameters=function(params,setupType){var sdp='a=setup:'+setupType+'\r\n';params.fingerprints.forEach(function(fp){sdp+='a=fingerprint:'+fp.algorithm+' '+fp.value+'\r\n';});return sdp;};SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var iceParameters={usernameFragment:lines.filter(function(line){return line.indexOf('a=ice-ufrag:')===0;})[0].substr(12),password:lines.filter(function(line){return line.indexOf('a=ice-pwd:')===0;})[0].substr(10)};return iceParameters;};SDPUtils.writeIceParameters=function(params){return'a=ice-ufrag:'+params.usernameFragment+'\r\n'+'a=ice-pwd:'+params.password+'\r\n';};SDPUtils.parseRtpParameters=function(mediaSection){var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]};var lines=SDPUtils.splitLines(mediaSection);var mline=lines[0].split(' ');for(var i=3;i0?'9':'0';sdp+=' UDP/TLS/RTP/SAVPF ';sdp+=caps.codecs.map(function(codec){if(codec.preferredPayloadType!==undefined){return codec.preferredPayloadType;} +return codec.payloadType;}).join(' ')+'\r\n';sdp+='c=IN IP4 0.0.0.0\r\n';sdp+='a=rtcp:9 IN IP4 0.0.0.0\r\n';caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec);sdp+=SDPUtils.writeFmtp(codec);sdp+=SDPUtils.writeRtcpFb(codec);});var maxptime=0;caps.codecs.forEach(function(codec){if(codec.maxptime>maxptime){maxptime=codec.maxptime;}});if(maxptime>0){sdp+='a=maxptime:'+maxptime+'\r\n';} +sdp+='a=rtcp-mux\r\n';if(caps.headerExtensions){caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension);});} +return sdp;};SDPUtils.parseRtpEncodingParameters=function(mediaSection){var encodingParameters=[];var description=SDPUtils.parseRtpParameters(mediaSection);var hasRed=description.fecMechanisms.indexOf('RED')!==-1;var hasUlpfec=description.fecMechanisms.indexOf('ULPFEC')!==-1;var ssrcs=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='cname';});var primarySsrc=ssrcs.length>0&&ssrcs[0].ssrc;var secondarySsrc;var flows=SDPUtils.matchPrefix(mediaSection,'a=ssrc-group:FID').map(function(line){var parts=line.substr(17).split(' ');return parts.map(function(part){return parseInt(part,10);});});if(flows.length>0&&flows[0].length>1&&flows[0][0]===primarySsrc){secondarySsrc=flows[0][1];} +description.codecs.forEach(function(codec){if(codec.name.toUpperCase()==='RTX'&&codec.parameters.apt){var encParam={ssrc:primarySsrc,codecPayloadType:parseInt(codec.parameters.apt,10)};if(primarySsrc&&secondarySsrc){encParam.rtx={ssrc:secondarySsrc};} +encodingParameters.push(encParam);if(hasRed){encParam=JSON.parse(JSON.stringify(encParam));encParam.fec={ssrc:primarySsrc,mechanism:hasUlpfec?'red+ulpfec':'red'};encodingParameters.push(encParam);}}});if(encodingParameters.length===0&&primarySsrc){encodingParameters.push({ssrc:primarySsrc});} +var bandwidth=SDPUtils.matchPrefix(mediaSection,'b=');if(bandwidth.length){if(bandwidth[0].indexOf('b=TIAS:')===0){bandwidth=parseInt(bandwidth[0].substr(7),10);}else if(bandwidth[0].indexOf('b=AS:')===0){bandwidth=parseInt(bandwidth[0].substr(5),10)*1000*0.95 +-(50*40*8);}else{bandwidth=undefined;} +encodingParameters.forEach(function(params){params.maxBitrate=bandwidth;});} +return encodingParameters;};SDPUtils.parseRtcpParameters=function(mediaSection){var rtcpParameters={};var remoteSsrc=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(obj){return obj.attribute==='cname';})[0];if(remoteSsrc){rtcpParameters.cname=remoteSsrc.value;rtcpParameters.ssrc=remoteSsrc.ssrc;} +var rsize=SDPUtils.matchPrefix(mediaSection,'a=rtcp-rsize');rtcpParameters.reducedSize=rsize.length>0;rtcpParameters.compound=rsize.length===0;var mux=SDPUtils.matchPrefix(mediaSection,'a=rtcp-mux');rtcpParameters.mux=mux.length>0;return rtcpParameters;};SDPUtils.parseMsid=function(mediaSection){var parts;var spec=SDPUtils.matchPrefix(mediaSection,'a=msid:');if(spec.length===1){parts=spec[0].substr(7).split(' ');return{stream:parts[0],track:parts[1]};} +var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(msidParts){return msidParts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId,sessVer,sessUser){var sessionId;var version=sessVer!==undefined?sessVer:2;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} +var user=sessUser||'thisisadapterortc';return'v=0\r\n'+'o='+user+' '+sessionId+' '+version+' IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var msid='msid:'+stream.id+' '+ +transceiver.rtpSender.track.id+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;};SDPUtils.getDirection=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);for(var i=0;i 0 && arguments[0] !== undefined ? arguments[0] : {}, + window = _ref.window; + + var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : { + shimChrome: true, + shimFirefox: true, + shimEdge: true, + shimSafari: true + }; + + // Utils. + var logging = utils.log; + var browserDetails = utils.detectBrowser(window); + + var adapter = { + browserDetails: browserDetails, + commonShim: commonShim, + extractVersion: utils.extractVersion, + disableLog: utils.disableLog, + disableWarnings: utils.disableWarnings + }; + + // Shim browser if found. + switch (browserDetails.browser) { + case 'chrome': + if (!chromeShim || !chromeShim.shimPeerConnection || !options.shimChrome) { + logging('Chrome shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming chrome.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = chromeShim; + + chromeShim.shimGetUserMedia(window); + chromeShim.shimMediaStream(window); + chromeShim.shimPeerConnection(window); + chromeShim.shimOnTrack(window); + chromeShim.shimAddTrackRemoveTrack(window); + chromeShim.shimGetSendersWithDtmf(window); + chromeShim.shimSenderReceiverGetStats(window); + chromeShim.fixNegotiationNeeded(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + case 'firefox': + if (!firefoxShim || !firefoxShim.shimPeerConnection || !options.shimFirefox) { + logging('Firefox shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming firefox.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = firefoxShim; + + firefoxShim.shimGetUserMedia(window); + firefoxShim.shimPeerConnection(window); + firefoxShim.shimOnTrack(window); + firefoxShim.shimRemoveStream(window); + firefoxShim.shimSenderGetStats(window); + firefoxShim.shimReceiverGetStats(window); + firefoxShim.shimRTCDataChannel(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimConnectionState(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'edge': + if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { + logging('MS edge shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming edge.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = edgeShim; + + edgeShim.shimGetUserMedia(window); + edgeShim.shimGetDisplayMedia(window); + edgeShim.shimPeerConnection(window); + edgeShim.shimReplaceTrack(window); + + // the edge shim implements the full RTCIceCandidate object. + + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + break; + case 'safari': + if (!safariShim || !options.shimSafari) { + logging('Safari shim is not included in this adapter release.'); + return adapter; + } + logging('adapter.js shimming safari.'); + // Export to the adapter global object visible in the browser. + adapter.browserShim = safariShim; + + safariShim.shimRTCIceServerUrls(window); + safariShim.shimCreateOfferLegacy(window); + safariShim.shimCallbacksAPI(window); + safariShim.shimLocalStreamsAPI(window); + safariShim.shimRemoteStreamsAPI(window); + safariShim.shimTrackEventTransceiver(window); + safariShim.shimGetUserMedia(window); + + commonShim.shimRTCIceCandidate(window); + commonShim.shimMaxMessageSize(window); + commonShim.shimSendThrowTypeError(window); + commonShim.removeAllowExtmapMixed(window); + break; + default: + logging('Unsupported browser!'); + break; + } + + return adapter; +} + +// Browser shims. + +},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){ + +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimMediaStream = shimMediaStream; +exports.shimOnTrack = shimOnTrack; +exports.shimGetSendersWithDtmf = shimGetSendersWithDtmf; +exports.shimSenderReceiverGetStats = shimSenderReceiverGetStats; +exports.shimAddTrackRemoveTrackWithNative = shimAddTrackRemoveTrackWithNative; +exports.shimAddTrackRemoveTrack = shimAddTrackRemoveTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.fixNegotiationNeeded = fixNegotiationNeeded; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +/* iterates the stats graph recursively. */ +function walkStats(stats, base, resultSet) { + if (!base || resultSet.has(base.id)) { + return; + } + resultSet.set(base.id, base); + Object.keys(base).forEach(function (name) { + if (name.endsWith('Id')) { + walkStats(stats, stats.get(base[name]), resultSet); + } else if (name.endsWith('Ids')) { + base[name].forEach(function (id) { + walkStats(stats, stats.get(id), resultSet); + }); + } + }); +} + +/* filter getStats for a sender/receiver track. */ +function filterStats(result, track, outbound) { + var streamStatsType = outbound ? 'outbound-rtp' : 'inbound-rtp'; + var filteredResult = new Map(); + if (track === null) { + return filteredResult; + } + var trackStats = []; + result.forEach(function (value) { + if (value.type === 'track' && value.trackIdentifier === track.id) { + trackStats.push(value); + } + }); + trackStats.forEach(function (trackStat) { + result.forEach(function (stats) { + if (stats.type === streamStatsType && stats.trackId === trackStat.id) { + walkStats(result, stats, filteredResult); + } + }); + }); + return filteredResult; +} + +function shimMediaStream(window) { + window.MediaStream = window.MediaStream || window.webkitMediaStream; +} + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('ontrack' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { + get: function get() { + return this._ontrack; + }, + set: function set(f) { + if (this._ontrack) { + this.removeEventListener('track', this._ontrack); + } + this.addEventListener('track', this._ontrack = f); + }, + + enumerable: true, + configurable: true + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function () { + var _this = this; + + if (!this._ontrackpoly) { + this._ontrackpoly = function (e) { + // onaddstream does not fire when a track is added to an existing + // stream. But stream.onaddtrack is implemented so we use that. + e.stream.addEventListener('addtrack', function (te) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === te.track.id; + }); + } else { + receiver = { track: te.track }; + } + + var event = new Event('track'); + event.track = te.track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + e.stream.getTracks().forEach(function (track) { + var receiver = void 0; + if (window.RTCPeerConnection.prototype.getReceivers) { + receiver = _this.getReceivers().find(function (r) { + return r.track && r.track.id === track.id; + }); + } else { + receiver = { track: track }; + } + var event = new Event('track'); + event.track = track; + event.receiver = receiver; + event.transceiver = { receiver: receiver }; + event.streams = [e.stream]; + _this.dispatchEvent(event); + }); + }; + this.addEventListener('addstream', this._ontrackpoly); + } + return origSetRemoteDescription.apply(this, arguments); + }; + } else { + // even if RTCRtpTransceiver is in window, it is only used and + // emitted in unified-plan. Unfortunately this means we need + // to unconditionally wrap the event. + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + if (!e.transceiver) { + Object.defineProperty(e, 'transceiver', { value: { receiver: e.receiver } }); + } + return e; + }); + } +} + +function shimGetSendersWithDtmf(window) { + // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && !('getSenders' in window.RTCPeerConnection.prototype) && 'createDTMFSender' in window.RTCPeerConnection.prototype) { + var shimSenderWithDtmf = function shimSenderWithDtmf(pc, track) { + return { + track: track, + get dtmf() { + if (this._dtmf === undefined) { + if (track.kind === 'audio') { + this._dtmf = pc.createDTMFSender(track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + }, + _pc: pc + }; + }; + + // augment addTrack when getSenders is not available. + if (!window.RTCPeerConnection.prototype.getSenders) { + window.RTCPeerConnection.prototype.getSenders = function () { + this._senders = this._senders || []; + return this._senders.slice(); // return a copy of the internal state. + }; + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function (track, stream) { + var sender = origAddTrack.apply(this, arguments); + if (!sender) { + sender = shimSenderWithDtmf(this, track); + this._senders.push(sender); + } + return sender; + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function (sender) { + origRemoveTrack.apply(this, arguments); + var idx = this._senders.indexOf(sender); + if (idx !== -1) { + this._senders.splice(idx, 1); + } + }; + } + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function (stream) { + var _this2 = this; + + this._senders = this._senders || []; + origAddStream.apply(this, [stream]); + stream.getTracks().forEach(function (track) { + _this2._senders.push(shimSenderWithDtmf(_this2, track)); + }); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function (stream) { + var _this3 = this; + + this._senders = this._senders || []; + origRemoveStream.apply(this, [stream]); + + stream.getTracks().forEach(function (track) { + var sender = _this3._senders.find(function (s) { + return s.track === track; + }); + if (sender) { + // remove sender + _this3._senders.splice(_this3._senders.indexOf(sender), 1); + } + }); + }; + } else if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'getSenders' in window.RTCPeerConnection.prototype && 'createDTMFSender' in window.RTCPeerConnection.prototype && window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + window.RTCPeerConnection.prototype.getSenders = function () { + var _this4 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this4; + }); + return senders; + }; + + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = this._pc.createDTMFSender(this.track); + } else { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } +} + +function shimSenderReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender && window.RTCRtpReceiver)) { + return; + } + + // shim sender stats. + if (!('getStats' in window.RTCRtpSender.prototype)) { + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function () { + var _this5 = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this5; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function () { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function () { + var sender = this; + return this._pc.getStats().then(function (result) { + return ( + /* Note: this will include stats of all senders that + * send a track with the same id as sender.track as + * it is not possible to identify the RTCRtpSender. + */ + filterStats(result, sender.track, true) + ); + }); + }; + } + + // shim receiver stats. + if (!('getStats' in window.RTCRtpReceiver.prototype)) { + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function () { + var _this6 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this6; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function () { + var receiver = this; + return this._pc.getStats().then(function (result) { + return filterStats(result, receiver.track, false); + }); + }; + } + + if (!('getStats' in window.RTCRtpSender.prototype && 'getStats' in window.RTCRtpReceiver.prototype)) { + return; + } + + // shim RTCPeerConnection.getStats(track). + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function () { + if (arguments.length > 0 && arguments[0] instanceof window.MediaStreamTrack) { + var track = arguments[0]; + var sender = void 0; + var receiver = void 0; + var err = void 0; + this.getSenders().forEach(function (s) { + if (s.track === track) { + if (sender) { + err = true; + } else { + sender = s; + } + } + }); + this.getReceivers().forEach(function (r) { + if (r.track === track) { + if (receiver) { + err = true; + } else { + receiver = r; + } + } + return r.track === track; + }); + if (err || sender && receiver) { + return Promise.reject(new DOMException('There are more than one sender or receiver for the track.', 'InvalidAccessError')); + } else if (sender) { + return sender.getStats(); + } else if (receiver) { + return receiver.getStats(); + } + return Promise.reject(new DOMException('There is no sender or receiver for the track.', 'InvalidAccessError')); + } + return origGetStats.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrackWithNative(window) { + // shim addTrack/removeTrack with native variants in order to make + // the interactions with legacy getLocalStreams behave as in other browsers. + // Keeps a mapping stream.id => [stream, rtpsenders...] + window.RTCPeerConnection.prototype.getLocalStreams = function () { + var _this7 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + return Object.keys(this._shimmedLocalStreams).map(function (streamId) { + return _this7._shimmedLocalStreams[streamId][0]; + }); + }; + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addTrack = function (track, stream) { + if (!stream) { + return origAddTrack.apply(this, arguments); + } + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + var sender = origAddTrack.apply(this, arguments); + if (!this._shimmedLocalStreams[stream.id]) { + this._shimmedLocalStreams[stream.id] = [stream, sender]; + } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { + this._shimmedLocalStreams[stream.id].push(sender); + } + return sender; + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function (stream) { + var _this8 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this8.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + var existingSenders = this.getSenders(); + origAddStream.apply(this, arguments); + var newSenders = this.getSenders().filter(function (newSender) { + return existingSenders.indexOf(newSender) === -1; + }); + this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function (stream) { + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + delete this._shimmedLocalStreams[stream.id]; + return origRemoveStream.apply(this, arguments); + }; + + var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; + window.RTCPeerConnection.prototype.removeTrack = function (sender) { + var _this9 = this; + + this._shimmedLocalStreams = this._shimmedLocalStreams || {}; + if (sender) { + Object.keys(this._shimmedLocalStreams).forEach(function (streamId) { + var idx = _this9._shimmedLocalStreams[streamId].indexOf(sender); + if (idx !== -1) { + _this9._shimmedLocalStreams[streamId].splice(idx, 1); + } + if (_this9._shimmedLocalStreams[streamId].length === 1) { + delete _this9._shimmedLocalStreams[streamId]; + } + }); + } + return origRemoveTrack.apply(this, arguments); + }; +} + +function shimAddTrackRemoveTrack(window) { + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + // shim addTrack and removeTrack. + if (window.RTCPeerConnection.prototype.addTrack && browserDetails.version >= 65) { + return shimAddTrackRemoveTrackWithNative(window); + } + + // also shim pc.getLocalStreams when addTrack is shimmed + // to return the original streams. + var origGetLocalStreams = window.RTCPeerConnection.prototype.getLocalStreams; + window.RTCPeerConnection.prototype.getLocalStreams = function () { + var _this10 = this; + + var nativeStreams = origGetLocalStreams.apply(this); + this._reverseStreams = this._reverseStreams || {}; + return nativeStreams.map(function (stream) { + return _this10._reverseStreams[stream.id]; + }); + }; + + var origAddStream = window.RTCPeerConnection.prototype.addStream; + window.RTCPeerConnection.prototype.addStream = function (stream) { + var _this11 = this; + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + stream.getTracks().forEach(function (track) { + var alreadyExists = _this11.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + }); + // Add identity mapping for consistency with addTrack. + // Unless this is being used with a stream from addTrack. + if (!this._reverseStreams[stream.id]) { + var newStream = new window.MediaStream(stream.getTracks()); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + stream = newStream; + } + origAddStream.apply(this, [stream]); + }; + + var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; + window.RTCPeerConnection.prototype.removeStream = function (stream) { + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + + origRemoveStream.apply(this, [this._streams[stream.id] || stream]); + delete this._reverseStreams[this._streams[stream.id] ? this._streams[stream.id].id : stream.id]; + delete this._streams[stream.id]; + }; + + window.RTCPeerConnection.prototype.addTrack = function (track, stream) { + var _this12 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + var streams = [].slice.call(arguments, 1); + if (streams.length !== 1 || !streams[0].getTracks().find(function (t) { + return t === track; + })) { + // this is not fully correct but all we can manage without + // [[associated MediaStreams]] internal slot. + throw new DOMException('The adapter.js addTrack polyfill only supports a single ' + ' stream which is associated with the specified track.', 'NotSupportedError'); + } + + var alreadyExists = this.getSenders().find(function (s) { + return s.track === track; + }); + if (alreadyExists) { + throw new DOMException('Track already exists.', 'InvalidAccessError'); + } + + this._streams = this._streams || {}; + this._reverseStreams = this._reverseStreams || {}; + var oldStream = this._streams[stream.id]; + if (oldStream) { + // this is using odd Chrome behaviour, use with caution: + // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 + // Note: we rely on the high-level addTrack/dtmf shim to + // create the sender with a dtmf sender. + oldStream.addTrack(track); + + // Trigger ONN async. + Promise.resolve().then(function () { + _this12.dispatchEvent(new Event('negotiationneeded')); + }); + } else { + var newStream = new window.MediaStream([track]); + this._streams[stream.id] = newStream; + this._reverseStreams[newStream.id] = stream; + this.addStream(newStream); + } + return this.getSenders().find(function (s) { + return s.track === track; + }); + }; + + // replace the internal stream id with the external one and + // vice versa. + function replaceInternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(internalStream.id, 'g'), externalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + function replaceExternalStreamId(pc, description) { + var sdp = description.sdp; + Object.keys(pc._reverseStreams || []).forEach(function (internalId) { + var externalStream = pc._reverseStreams[internalId]; + var internalStream = pc._streams[externalStream.id]; + sdp = sdp.replace(new RegExp(externalStream.id, 'g'), internalStream.id); + }); + return new RTCSessionDescription({ + type: description.type, + sdp: sdp + }); + } + ['createOffer', 'createAnswer'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function () { + var _this13 = this; + + var args = arguments; + var isLegacyCall = arguments.length && typeof arguments[0] === 'function'; + if (isLegacyCall) { + return nativeMethod.apply(this, [function (description) { + var desc = replaceInternalStreamId(_this13, description); + args[0].apply(null, [desc]); + }, function (err) { + if (args[1]) { + args[1].apply(null, err); + } + }, arguments[2]]); + } + return nativeMethod.apply(this, arguments).then(function (description) { + return replaceInternalStreamId(_this13, description); + }); + }; + }); + + var origSetLocalDescription = window.RTCPeerConnection.prototype.setLocalDescription; + window.RTCPeerConnection.prototype.setLocalDescription = function () { + if (!arguments.length || !arguments[0].type) { + return origSetLocalDescription.apply(this, arguments); + } + arguments[0] = replaceExternalStreamId(this, arguments[0]); + return origSetLocalDescription.apply(this, arguments); + }; + + // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier + + var origLocalDescription = Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype, 'localDescription'); + Object.defineProperty(window.RTCPeerConnection.prototype, 'localDescription', { + get: function get() { + var description = origLocalDescription.get.apply(this); + if (description.type === '') { + return description; + } + return replaceInternalStreamId(this, description); + } + }); + + window.RTCPeerConnection.prototype.removeTrack = function (sender) { + var _this14 = this; + + if (this.signalingState === 'closed') { + throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.', 'InvalidStateError'); + } + // We can not yet check for sender instanceof RTCRtpSender + // since we shim RTPSender. So we check if sender._pc is set. + if (!sender._pc) { + throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.', 'TypeError'); + } + var isLocal = sender._pc === this; + if (!isLocal) { + throw new DOMException('Sender was not created by this connection.', 'InvalidAccessError'); + } + + // Search for the native stream the senders track belongs to. + this._streams = this._streams || {}; + var stream = void 0; + Object.keys(this._streams).forEach(function (streamid) { + var hasTrack = _this14._streams[streamid].getTracks().find(function (track) { + return sender.track === track; + }); + if (hasTrack) { + stream = _this14._streams[streamid]; + } + }); + + if (stream) { + if (stream.getTracks().length === 1) { + // if this is the last track of the stream, remove the stream. This + // takes care of any shimmed _senders. + this.removeStream(this._reverseStreams[stream.id]); + } else { + // relying on the same odd chrome behaviour as above. + stream.removeTrack(sender.track); + } + this.dispatchEvent(new Event('negotiationneeded')); + } + }; +} + +function shimPeerConnection(window) { + if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.webkitRTCPeerConnection; + } + if (!window.RTCPeerConnection) { + return; + } + + var origGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function (selector, successCallback, errorCallback) { + var _this15 = this; + + var args = arguments; + + // If selector is a function then we are in the old style stats so just + // pass back the original getStats format to avoid breaking old users. + if (arguments.length > 0 && typeof selector === 'function') { + return origGetStats.apply(this, arguments); + } + + // When spec-style getStats is supported, return those when called with + // either no arguments or the selector argument is null. + if (origGetStats.length === 0 && (arguments.length === 0 || typeof arguments[0] !== 'function')) { + return origGetStats.apply(this, []); + } + + var fixChromeStats_ = function fixChromeStats_(response) { + var standardReport = {}; + var reports = response.result(); + reports.forEach(function (report) { + var standardStats = { + id: report.id, + timestamp: report.timestamp, + type: { + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[report.type] || report.type + }; + report.names().forEach(function (name) { + standardStats[name] = report.stat(name); + }); + standardReport[standardStats.id] = standardStats; + }); + + return standardReport; + }; + + // shim getStats with maplike support + var makeMapStats = function makeMapStats(stats) { + return new Map(Object.keys(stats).map(function (key) { + return [key, stats[key]]; + })); + }; + + if (arguments.length >= 2) { + var successCallbackWrapper_ = function successCallbackWrapper_(response) { + args[1](makeMapStats(fixChromeStats_(response))); + }; + + return origGetStats.apply(this, [successCallbackWrapper_, arguments[0]]); + } + + // promise-support + return new Promise(function (resolve, reject) { + origGetStats.apply(_this15, [function (response) { + resolve(makeMapStats(fixChromeStats_(response))); + }, reject]); + }).then(successCallback, errorCallback); + }; + + // shim implicit creation of RTCSessionDescription/RTCIceCandidate + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }; + }); + + // support for addIceCandidate(null or undefined) + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function () { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; +} + +function fixNegotiationNeeded(window) { + utils.wrapPeerConnectionEvent(window, 'negotiationneeded', function (e) { + var pc = e.target; + if (pc.signalingState !== 'stable') { + return; + } + return e; + }); +} + +},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, getSourceId) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + // getSourceId is a function that returns a promise resolving with + // the sourceId of the screen/window/tab to be shared. + if (typeof getSourceId !== 'function') { + console.error('shimGetDisplayMedia: getSourceId argument is not ' + 'a function'); + return; + } + window.navigator.mediaDevices.getDisplayMedia = function (constraints) { + return getSourceId(constraints).then(function (sourceId) { + var widthSpecified = constraints.video && constraints.video.width; + var heightSpecified = constraints.video && constraints.video.height; + var frameRateSpecified = constraints.video && constraints.video.frameRate; + constraints.video = { + mandatory: { + chromeMediaSource: 'desktop', + chromeMediaSourceId: sourceId, + maxFrameRate: frameRateSpecified || 3 + } + }; + if (widthSpecified) { + constraints.video.mandatory.maxWidth = widthSpecified; + } + if (heightSpecified) { + constraints.video.mandatory.maxHeight = heightSpecified; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }); + }; +} + +},{}],5:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils.js'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +var logging = utils.log; + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (!navigator.mediaDevices) { + return; + } + + var browserDetails = utils.detectBrowser(window); + + var constraintsToChrome_ = function constraintsToChrome_(c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) !== 'object' || c.mandatory || c.optional) { + return c; + } + var cc = {}; + Object.keys(c).forEach(function (key) { + if (key === 'require' || key === 'advanced' || key === 'mediaSource') { + return; + } + var r = _typeof(c[key]) === 'object' ? c[key] : { ideal: c[key] }; + if (r.exact !== undefined && typeof r.exact === 'number') { + r.min = r.max = r.exact; + } + var oldname_ = function oldname_(prefix, name) { + if (prefix) { + return prefix + name.charAt(0).toUpperCase() + name.slice(1); + } + return name === 'deviceId' ? 'sourceId' : name; + }; + if (r.ideal !== undefined) { + cc.optional = cc.optional || []; + var oc = {}; + if (typeof r.ideal === 'number') { + oc[oldname_('min', key)] = r.ideal; + cc.optional.push(oc); + oc = {}; + oc[oldname_('max', key)] = r.ideal; + cc.optional.push(oc); + } else { + oc[oldname_('', key)] = r.ideal; + cc.optional.push(oc); + } + } + if (r.exact !== undefined && typeof r.exact !== 'number') { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_('', key)] = r.exact; + } else { + ['min', 'max'].forEach(function (mix) { + if (r[mix] !== undefined) { + cc.mandatory = cc.mandatory || {}; + cc.mandatory[oldname_(mix, key)] = r[mix]; + } + }); + } + }); + if (c.advanced) { + cc.optional = (cc.optional || []).concat(c.advanced); + } + return cc; + }; + + var shimConstraints_ = function shimConstraints_(constraints, func) { + if (browserDetails.version >= 61) { + return func(constraints); + } + constraints = JSON.parse(JSON.stringify(constraints)); + if (constraints && _typeof(constraints.audio) === 'object') { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + constraints = JSON.parse(JSON.stringify(constraints)); + remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); + remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); + constraints.audio = constraintsToChrome_(constraints.audio); + } + if (constraints && _typeof(constraints.video) === 'object') { + // Shim facingMode for mobile & surface pro. + var face = constraints.video.facingMode; + face = face && ((typeof face === 'undefined' ? 'undefined' : _typeof(face)) === 'object' ? face : { ideal: face }); + var getSupportedFacingModeLies = browserDetails.version < 66; + + if (face && (face.exact === 'user' || face.exact === 'environment' || face.ideal === 'user' || face.ideal === 'environment') && !(navigator.mediaDevices.getSupportedConstraints && navigator.mediaDevices.getSupportedConstraints().facingMode && !getSupportedFacingModeLies)) { + delete constraints.video.facingMode; + var matches = void 0; + if (face.exact === 'environment' || face.ideal === 'environment') { + matches = ['back', 'rear']; + } else if (face.exact === 'user' || face.ideal === 'user') { + matches = ['front']; + } + if (matches) { + // Look for matches in label, or use last cam for back (typical). + return navigator.mediaDevices.enumerateDevices().then(function (devices) { + devices = devices.filter(function (d) { + return d.kind === 'videoinput'; + }); + var dev = devices.find(function (d) { + return matches.some(function (match) { + return d.label.toLowerCase().includes(match); + }); + }); + if (!dev && devices.length && matches.includes('back')) { + dev = devices[devices.length - 1]; // more likely the back cam + } + if (dev) { + constraints.video.deviceId = face.exact ? { exact: dev.deviceId } : { ideal: dev.deviceId }; + } + constraints.video = constraintsToChrome_(constraints.video); + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }); + } + } + constraints.video = constraintsToChrome_(constraints.video); + } + logging('chrome: ' + JSON.stringify(constraints)); + return func(constraints); + }; + + var shimError_ = function shimError_(e) { + if (browserDetails.version >= 64) { + return e; + } + return { + name: { + PermissionDeniedError: 'NotAllowedError', + PermissionDismissedError: 'NotAllowedError', + InvalidStateError: 'NotAllowedError', + DevicesNotFoundError: 'NotFoundError', + ConstraintNotSatisfiedError: 'OverconstrainedError', + TrackStartError: 'NotReadableError', + MediaDeviceFailedDueToShutdown: 'NotAllowedError', + MediaDeviceKillSwitchOn: 'NotAllowedError', + TabCaptureError: 'AbortError', + ScreenCaptureError: 'AbortError', + DeviceCaptureError: 'AbortError' + }[e.name] || e.name, + message: e.message, + constraint: e.constraint || e.constraintName, + toString: function toString() { + return this.name + (this.message && ': ') + this.message; + } + }; + }; + + var getUserMedia_ = function getUserMedia_(constraints, onSuccess, onError) { + shimConstraints_(constraints, function (c) { + navigator.webkitGetUserMedia(c, onSuccess, function (e) { + if (onError) { + onError(shimError_(e)); + } + }); + }); + }; + navigator.getUserMedia = getUserMedia_.bind(navigator); + + // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia + // function which returns a Promise, it does not accept spec-style + // constraints. + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (cs) { + return shimConstraints_(cs, function (c) { + return origGetUserMedia(c).then(function (stream) { + if (c.audio && !stream.getAudioTracks().length || c.video && !stream.getVideoTracks().length) { + stream.getTracks().forEach(function (track) { + track.stop(); + }); + throw new DOMException('', 'NotFoundError'); + } + return stream; + }, function (e) { + return Promise.reject(shimError_(e)); + }); + }); + }; +} + +},{"../utils.js":15}],6:[function(require,module,exports){ +/* + * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimRTCIceCandidate = shimRTCIceCandidate; +exports.shimMaxMessageSize = shimMaxMessageSize; +exports.shimSendThrowTypeError = shimSendThrowTypeError; +exports.shimConnectionState = shimConnectionState; +exports.removeAllowExtmapMixed = removeAllowExtmapMixed; + +var _sdp = require('sdp'); + +var _sdp2 = _interopRequireDefault(_sdp); + +var _utils = require('./utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function shimRTCIceCandidate(window) { + // foundation is arbitrarily chosen as an indicator for full support for + // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface + if (!window.RTCIceCandidate || window.RTCIceCandidate && 'foundation' in window.RTCIceCandidate.prototype) { + return; + } + + var NativeRTCIceCandidate = window.RTCIceCandidate; + window.RTCIceCandidate = function (args) { + // Remove the a= which shouldn't be part of the candidate string. + if ((typeof args === 'undefined' ? 'undefined' : _typeof(args)) === 'object' && args.candidate && args.candidate.indexOf('a=') === 0) { + args = JSON.parse(JSON.stringify(args)); + args.candidate = args.candidate.substr(2); + } + + if (args.candidate && args.candidate.length) { + // Augment the native candidate with the parsed fields. + var nativeCandidate = new NativeRTCIceCandidate(args); + var parsedCandidate = _sdp2.default.parseCandidate(args.candidate); + var augmentedCandidate = Object.assign(nativeCandidate, parsedCandidate); + + // Add a serializer that does not serialize the extra attributes. + augmentedCandidate.toJSON = function () { + return { + candidate: augmentedCandidate.candidate, + sdpMid: augmentedCandidate.sdpMid, + sdpMLineIndex: augmentedCandidate.sdpMLineIndex, + usernameFragment: augmentedCandidate.usernameFragment + }; + }; + return augmentedCandidate; + } + return new NativeRTCIceCandidate(args); + }; + window.RTCIceCandidate.prototype = NativeRTCIceCandidate.prototype; + + // Hook up the augmented candidate in onicecandidate and + // addEventListener('icecandidate', ...) + utils.wrapPeerConnectionEvent(window, 'icecandidate', function (e) { + if (e.candidate) { + Object.defineProperty(e, 'candidate', { + value: new window.RTCIceCandidate(e.candidate), + writable: 'false' + }); + } + return e; + }); +} + +function shimMaxMessageSize(window) { + if (window.RTCSctpTransport || !window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + + if (!('sctp' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { + get: function get() { + return typeof this._sctp === 'undefined' ? null : this._sctp; + } + }); + } + + var sctpInDescription = function sctpInDescription(description) { + var sections = _sdp2.default.splitSections(description.sdp); + sections.shift(); + return sections.some(function (mediaSection) { + var mLine = _sdp2.default.parseMLine(mediaSection); + return mLine && mLine.kind === 'application' && mLine.protocol.indexOf('SCTP') !== -1; + }); + }; + + var getRemoteFirefoxVersion = function getRemoteFirefoxVersion(description) { + // TODO: Is there a better solution for detecting Firefox? + var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); + if (match === null || match.length < 2) { + return -1; + } + var version = parseInt(match[1], 10); + // Test for NaN (yes, this is ugly) + return version !== version ? -1 : version; + }; + + var getCanSendMaxMessageSize = function getCanSendMaxMessageSize(remoteIsFirefox) { + // Every implementation we know can send at least 64 KiB. + // Note: Although Chrome is technically able to send up to 256 KiB, the + // data does not reach the other peer reliably. + // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 + var canSendMaxMessageSize = 65536; + if (browserDetails.browser === 'firefox') { + if (browserDetails.version < 57) { + if (remoteIsFirefox === -1) { + // FF < 57 will send in 16 KiB chunks using the deprecated PPID + // fragmentation. + canSendMaxMessageSize = 16384; + } else { + // However, other FF (and RAWRTC) can reassemble PPID-fragmented + // messages. Thus, supporting ~2 GiB when sending. + canSendMaxMessageSize = 2147483637; + } + } else if (browserDetails.version < 60) { + // Currently, all FF >= 57 will reset the remote maximum message size + // to the default value when a data channel is created at a later + // stage. :( + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + canSendMaxMessageSize = browserDetails.version === 57 ? 65535 : 65536; + } else { + // FF >= 60 supports sending ~2 GiB + canSendMaxMessageSize = 2147483637; + } + } + return canSendMaxMessageSize; + }; + + var getMaxMessageSize = function getMaxMessageSize(description, remoteIsFirefox) { + // Note: 65536 bytes is the default value from the SDP spec. Also, + // every implementation we know supports receiving 65536 bytes. + var maxMessageSize = 65536; + + // FF 57 has a slightly incorrect default remote max message size, so + // we need to adjust it here to avoid a failure when sending. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 + if (browserDetails.browser === 'firefox' && browserDetails.version === 57) { + maxMessageSize = 65535; + } + + var match = _sdp2.default.matchPrefix(description.sdp, 'a=max-message-size:'); + if (match.length > 0) { + maxMessageSize = parseInt(match[0].substr(19), 10); + } else if (browserDetails.browser === 'firefox' && remoteIsFirefox !== -1) { + // If the maximum message size is not present in the remote SDP and + // both local and remote are Firefox, the remote peer can receive + // ~2 GiB. + maxMessageSize = 2147483637; + } + return maxMessageSize; + }; + + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function () { + this._sctp = null; + + if (sctpInDescription(arguments[0])) { + // Check if the remote is FF. + var isFirefox = getRemoteFirefoxVersion(arguments[0]); + + // Get the maximum message size the local peer is capable of sending + var canSendMMS = getCanSendMaxMessageSize(isFirefox); + + // Get the maximum message size of the remote peer. + var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); + + // Determine final maximum message size + var maxMessageSize = void 0; + if (canSendMMS === 0 && remoteMMS === 0) { + maxMessageSize = Number.POSITIVE_INFINITY; + } else if (canSendMMS === 0 || remoteMMS === 0) { + maxMessageSize = Math.max(canSendMMS, remoteMMS); + } else { + maxMessageSize = Math.min(canSendMMS, remoteMMS); + } + + // Create a dummy RTCSctpTransport object and the 'maxMessageSize' + // attribute. + var sctp = {}; + Object.defineProperty(sctp, 'maxMessageSize', { + get: function get() { + return maxMessageSize; + } + }); + this._sctp = sctp; + } + + return origSetRemoteDescription.apply(this, arguments); + }; +} + +function shimSendThrowTypeError(window) { + if (!(window.RTCPeerConnection && 'createDataChannel' in window.RTCPeerConnection.prototype)) { + return; + } + + // Note: Although Firefox >= 57 has a native implementation, the maximum + // message size can be reset for all data channels at a later stage. + // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 + + function wrapDcSend(dc, pc) { + var origDataChannelSend = dc.send; + dc.send = function () { + var data = arguments[0]; + var length = data.length || data.size || data.byteLength; + if (dc.readyState === 'open' && pc.sctp && length > pc.sctp.maxMessageSize) { + throw new TypeError('Message too large (can send a maximum of ' + pc.sctp.maxMessageSize + ' bytes)'); + } + return origDataChannelSend.apply(dc, arguments); + }; + } + var origCreateDataChannel = window.RTCPeerConnection.prototype.createDataChannel; + window.RTCPeerConnection.prototype.createDataChannel = function () { + var dataChannel = origCreateDataChannel.apply(this, arguments); + wrapDcSend(dataChannel, this); + return dataChannel; + }; + utils.wrapPeerConnectionEvent(window, 'datachannel', function (e) { + wrapDcSend(e.channel, e.target); + return e; + }); +} + +/* shims RTCConnectionState by pretending it is the same as iceConnectionState. + * See https://bugs.chromium.org/p/webrtc/issues/detail?id=6145#c12 + * for why this is a valid hack in Chrome. In Firefox it is slightly incorrect + * since DTLS failures would be hidden. See + * https://bugzilla.mozilla.org/show_bug.cgi?id=1265827 + * for the Firefox tracking bug. + */ +function shimConnectionState(window) { + if (!window.RTCPeerConnection || 'connectionState' in window.RTCPeerConnection.prototype) { + return; + } + var proto = window.RTCPeerConnection.prototype; + Object.defineProperty(proto, 'connectionState', { + get: function get() { + return { + completed: 'connected', + checking: 'connecting' + }[this.iceConnectionState] || this.iceConnectionState; + }, + + enumerable: true, + configurable: true + }); + Object.defineProperty(proto, 'onconnectionstatechange', { + get: function get() { + return this._onconnectionstatechange || null; + }, + set: function set(cb) { + if (this._onconnectionstatechange) { + this.removeEventListener('connectionstatechange', this._onconnectionstatechange); + delete this._onconnectionstatechange; + } + if (cb) { + this.addEventListener('connectionstatechange', this._onconnectionstatechange = cb); + } + }, + + enumerable: true, + configurable: true + }); + + ['setLocalDescription', 'setRemoteDescription'].forEach(function (method) { + var origMethod = proto[method]; + proto[method] = function () { + if (!this._connectionstatechangepoly) { + this._connectionstatechangepoly = function (e) { + var pc = e.target; + if (pc._lastConnectionState !== pc.connectionState) { + pc._lastConnectionState = pc.connectionState; + var newEvent = new Event('connectionstatechange', e); + pc.dispatchEvent(newEvent); + } + return e; + }; + this.addEventListener('iceconnectionstatechange', this._connectionstatechangepoly); + } + return origMethod.apply(this, arguments); + }; + }); +} + +function removeAllowExtmapMixed(window) { + /* remove a=extmap-allow-mixed for Chrome < M71 */ + if (!window.RTCPeerConnection) { + return; + } + var browserDetails = utils.detectBrowser(window); + if (browserDetails.browser === 'chrome' && browserDetails.version >= 71) { + return; + } + var nativeSRD = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function (desc) { + if (desc && desc.sdp && desc.sdp.indexOf('\na=extmap-allow-mixed') !== -1) { + desc.sdp = desc.sdp.split('\n').filter(function (line) { + return line.trim() !== 'a=extmap-allow-mixed'; + }).join('\n'); + } + return nativeSRD.apply(this, arguments); + }; +} + +},{"./utils":15,"sdp":17}],7:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimPeerConnection = shimPeerConnection; +exports.shimReplaceTrack = shimReplaceTrack; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +var _filtericeservers = require('./filtericeservers'); + +var _rtcpeerconnectionShim = require('rtcpeerconnection-shim'); + +var _rtcpeerconnectionShim2 = _interopRequireDefault(_rtcpeerconnectionShim); + +function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if (window.RTCIceGatherer) { + if (!window.RTCIceCandidate) { + window.RTCIceCandidate = function (args) { + return args; + }; + } + if (!window.RTCSessionDescription) { + window.RTCSessionDescription = function (args) { + return args; + }; + } + // this adds an additional event listener to MediaStrackTrack that signals + // when a tracks enabled property was changed. Workaround for a bug in + // addStream, see below. No longer required in 15025+ + if (browserDetails.version < 15025) { + var origMSTEnabled = Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype, 'enabled'); + Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { + set: function set(value) { + origMSTEnabled.set.call(this, value); + var ev = new Event('enabled'); + ev.enabled = value; + this.dispatchEvent(ev); + } + }); + } + } + + // ORTC defines the DTMF sender a bit different. + // https://github.com/w3c/ortc/issues/714 + if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { + Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { + get: function get() { + if (this._dtmf === undefined) { + if (this.track.kind === 'audio') { + this._dtmf = new window.RTCDtmfSender(this); + } else if (this.track.kind === 'video') { + this._dtmf = null; + } + } + return this._dtmf; + } + }); + } + // Edge currently only implements the RTCDtmfSender, not the + // RTCDTMFSender alias. See http://draft.ortc.org/#rtcdtmfsender2* + if (window.RTCDtmfSender && !window.RTCDTMFSender) { + window.RTCDTMFSender = window.RTCDtmfSender; + } + + var RTCPeerConnectionShim = (0, _rtcpeerconnectionShim2.default)(window, browserDetails.version); + window.RTCPeerConnection = function (config) { + if (config && config.iceServers) { + config.iceServers = (0, _filtericeservers.filterIceServers)(config.iceServers, browserDetails.version); + utils.log('ICE servers after filtering:', config.iceServers); + } + return new RTCPeerConnectionShim(config); + }; + window.RTCPeerConnection.prototype = RTCPeerConnectionShim.prototype; +} + +function shimReplaceTrack(window) { + // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 + if (window.RTCRtpSender && !('replaceTrack' in window.RTCRtpSender.prototype)) { + window.RTCRtpSender.prototype.replaceTrack = window.RTCRtpSender.prototype.setTrack; + } +} + +},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){ +/* + * Copyright (c) 2018 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.filterIceServers = filterIceServers; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +// Edge does not like +// 1) stun: filtered after 14393 unless ?transport=udp is present +// 2) turn: that does not have all of turn:host:port?transport=udp +// 3) turn: with ipv6 addresses +// 4) turn: occurring muliple times +function filterIceServers(iceServers, edgeVersion) { + var hasTurn = false; + iceServers = JSON.parse(JSON.stringify(iceServers)); + return iceServers.filter(function (server) { + if (server && (server.urls || server.url)) { + var urls = server.urls || server.url; + if (server.url && !server.urls) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + } + var isString = typeof urls === 'string'; + if (isString) { + urls = [urls]; + } + urls = urls.filter(function (url) { + // filter STUN unconditionally. + if (url.indexOf('stun:') === 0) { + return false; + } + + var validTurn = url.startsWith('turn') && !url.startsWith('turn:[') && url.includes('transport=udp'); + if (validTurn && !hasTurn) { + hasTurn = true; + return true; + } + return validTurn && !hasTurn; + }); + + delete server.url; + server.urls = isString ? urls[0] : urls; + return !!urls.length; + } + }); +} + +},{"../utils":15}],9:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window) { + if (!('getDisplayMedia' in window.navigator)) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = window.navigator.getDisplayMedia.bind(window.navigator.mediaDevices); +} + +},{}],10:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetUserMedia = shimGetUserMedia; +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + var shimError_ = function shimError_(e) { + return { + name: { PermissionDeniedError: 'NotAllowedError' }[e.name] || e.name, + message: e.message, + constraint: e.constraint, + toString: function toString() { + return this.name; + } + }; + }; + + // getUserMedia error shim. + var origGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + return origGetUserMedia(c).catch(function (e) { + return Promise.reject(shimError_(e)); + }); + }; +} + +},{}],11:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = exports.shimGetUserMedia = undefined; + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +var _getusermedia = require('./getusermedia'); + +Object.defineProperty(exports, 'shimGetUserMedia', { + enumerable: true, + get: function get() { + return _getusermedia.shimGetUserMedia; + } +}); + +var _getdisplaymedia = require('./getdisplaymedia'); + +Object.defineProperty(exports, 'shimGetDisplayMedia', { + enumerable: true, + get: function get() { + return _getdisplaymedia.shimGetDisplayMedia; + } +}); +exports.shimOnTrack = shimOnTrack; +exports.shimPeerConnection = shimPeerConnection; +exports.shimSenderGetStats = shimSenderGetStats; +exports.shimReceiverGetStats = shimReceiverGetStats; +exports.shimRemoveStream = shimRemoveStream; +exports.shimRTCDataChannel = shimRTCDataChannel; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimOnTrack(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCTrackEvent && 'receiver' in window.RTCTrackEvent.prototype && !('transceiver' in window.RTCTrackEvent.prototype)) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimPeerConnection(window) { + var browserDetails = utils.detectBrowser(window); + + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !(window.RTCPeerConnection || window.mozRTCPeerConnection)) { + return; // probably media.peerconnection.enabled=false in about:config + } + if (!window.RTCPeerConnection && window.mozRTCPeerConnection) { + // very basic support for old versions. + window.RTCPeerConnection = window.mozRTCPeerConnection; + } + + // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. + ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'].forEach(function (method) { + var nativeMethod = window.RTCPeerConnection.prototype[method]; + window.RTCPeerConnection.prototype[method] = function () { + arguments[0] = new (method === 'addIceCandidate' ? window.RTCIceCandidate : window.RTCSessionDescription)(arguments[0]); + return nativeMethod.apply(this, arguments); + }; + }); + + // support for addIceCandidate(null or undefined) + var nativeAddIceCandidate = window.RTCPeerConnection.prototype.addIceCandidate; + window.RTCPeerConnection.prototype.addIceCandidate = function () { + if (!arguments[0]) { + if (arguments[1]) { + arguments[1].apply(null); + } + return Promise.resolve(); + } + return nativeAddIceCandidate.apply(this, arguments); + }; + + var modernStatsTypes = { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }; + + var nativeGetStats = window.RTCPeerConnection.prototype.getStats; + window.RTCPeerConnection.prototype.getStats = function (selector, onSucc, onErr) { + return nativeGetStats.apply(this, [selector || null]).then(function (stats) { + if (browserDetails.version < 53 && !onSucc) { + // Shim only promise getStats with spec-hyphens in type names + // Leave callback version alone; misc old uses of forEach before Map + try { + stats.forEach(function (stat) { + stat.type = modernStatsTypes[stat.type] || stat.type; + }); + } catch (e) { + if (e.name !== 'TypeError') { + throw e; + } + // Avoid TypeError: "type" is read-only, in old versions. 34-43ish + stats.forEach(function (stat, i) { + stats.set(i, Object.assign({}, stat, { + type: modernStatsTypes[stat.type] || stat.type + })); + }); + } + } + return stats; + }).then(onSucc, onErr); + }; +} + +function shimSenderGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpSender.prototype) { + return; + } + var origGetSenders = window.RTCPeerConnection.prototype.getSenders; + if (origGetSenders) { + window.RTCPeerConnection.prototype.getSenders = function () { + var _this = this; + + var senders = origGetSenders.apply(this, []); + senders.forEach(function (sender) { + return sender._pc = _this; + }); + return senders; + }; + } + + var origAddTrack = window.RTCPeerConnection.prototype.addTrack; + if (origAddTrack) { + window.RTCPeerConnection.prototype.addTrack = function () { + var sender = origAddTrack.apply(this, arguments); + sender._pc = this; + return sender; + }; + } + window.RTCRtpSender.prototype.getStats = function () { + return this.track ? this._pc.getStats(this.track) : Promise.resolve(new Map()); + }; +} + +function shimReceiverGetStats(window) { + if (!((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && window.RTCRtpSender)) { + return; + } + if (window.RTCRtpSender && 'getStats' in window.RTCRtpReceiver.prototype) { + return; + } + var origGetReceivers = window.RTCPeerConnection.prototype.getReceivers; + if (origGetReceivers) { + window.RTCPeerConnection.prototype.getReceivers = function () { + var _this2 = this; + + var receivers = origGetReceivers.apply(this, []); + receivers.forEach(function (receiver) { + return receiver._pc = _this2; + }); + return receivers; + }; + } + utils.wrapPeerConnectionEvent(window, 'track', function (e) { + e.receiver._pc = e.srcElement; + return e; + }); + window.RTCRtpReceiver.prototype.getStats = function () { + return this._pc.getStats(this.track); + }; +} + +function shimRemoveStream(window) { + if (!window.RTCPeerConnection || 'removeStream' in window.RTCPeerConnection.prototype) { + return; + } + window.RTCPeerConnection.prototype.removeStream = function (stream) { + var _this3 = this; + + utils.deprecated('removeStream', 'removeTrack'); + this.getSenders().forEach(function (sender) { + if (sender.track && stream.getTracks().includes(sender.track)) { + _this3.removeTrack(sender); + } + }); + }; +} + +function shimRTCDataChannel(window) { + // rename DataChannel to RTCDataChannel (native fix in FF60): + // https://bugzilla.mozilla.org/show_bug.cgi?id=1173851 + if (window.DataChannel && !window.RTCDataChannel) { + window.RTCDataChannel = window.DataChannel; + } +} + +},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){ +/* + * Copyright (c) 2018 The adapter.js project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); +exports.shimGetDisplayMedia = shimGetDisplayMedia; +function shimGetDisplayMedia(window, preferredMediaSource) { + if (window.navigator.mediaDevices && 'getDisplayMedia' in window.navigator.mediaDevices) { + return; + } + if (!window.navigator.mediaDevices) { + return; + } + window.navigator.mediaDevices.getDisplayMedia = function (constraints) { + if (!(constraints && constraints.video)) { + var err = new DOMException('getDisplayMedia without video ' + 'constraints is undefined'); + err.name = 'NotFoundError'; + // from https://heycam.github.io/webidl/#idl-DOMException-error-names + err.code = 8; + return Promise.reject(err); + } + if (constraints.video === true) { + constraints.video = { mediaSource: preferredMediaSource }; + } else { + constraints.video.mediaSource = preferredMediaSource; + } + return window.navigator.mediaDevices.getUserMedia(constraints); + }; +} + +},{}],13:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimGetUserMedia = shimGetUserMedia; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimGetUserMedia(window) { + var browserDetails = utils.detectBrowser(window); + var navigator = window && window.navigator; + var MediaStreamTrack = window && window.MediaStreamTrack; + + navigator.getUserMedia = function (constraints, onSuccess, onError) { + // Replace Firefox 44+'s deprecation warning with unprefixed version. + utils.deprecated('navigator.getUserMedia', 'navigator.mediaDevices.getUserMedia'); + navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); + }; + + if (!(browserDetails.version > 55 && 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { + var remap = function remap(obj, a, b) { + if (a in obj && !(b in obj)) { + obj[b] = obj[a]; + delete obj[a]; + } + }; + + var nativeGetUserMedia = navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices); + navigator.mediaDevices.getUserMedia = function (c) { + if ((typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object' && _typeof(c.audio) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); + remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeGetUserMedia(c); + }; + + if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { + var nativeGetSettings = MediaStreamTrack.prototype.getSettings; + MediaStreamTrack.prototype.getSettings = function () { + var obj = nativeGetSettings.apply(this, arguments); + remap(obj, 'mozAutoGainControl', 'autoGainControl'); + remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); + return obj; + }; + } + + if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { + var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; + MediaStreamTrack.prototype.applyConstraints = function (c) { + if (this.kind === 'audio' && (typeof c === 'undefined' ? 'undefined' : _typeof(c)) === 'object') { + c = JSON.parse(JSON.stringify(c)); + remap(c, 'autoGainControl', 'mozAutoGainControl'); + remap(c, 'noiseSuppression', 'mozNoiseSuppression'); + } + return nativeApplyConstraints.apply(this, [c]); + }; + } + } +} + +},{"../utils":15}],14:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.shimLocalStreamsAPI = shimLocalStreamsAPI; +exports.shimRemoteStreamsAPI = shimRemoteStreamsAPI; +exports.shimCallbacksAPI = shimCallbacksAPI; +exports.shimGetUserMedia = shimGetUserMedia; +exports.shimConstraints = shimConstraints; +exports.shimRTCIceServerUrls = shimRTCIceServerUrls; +exports.shimTrackEventTransceiver = shimTrackEventTransceiver; +exports.shimCreateOfferLegacy = shimCreateOfferLegacy; + +var _utils = require('../utils'); + +var utils = _interopRequireWildcard(_utils); + +function _interopRequireWildcard(obj) { if (obj && obj.__esModule) { return obj; } else { var newObj = {}; if (obj != null) { for (var key in obj) { if (Object.prototype.hasOwnProperty.call(obj, key)) newObj[key] = obj[key]; } } newObj.default = obj; return newObj; } } + +function shimLocalStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getLocalStreams = function () { + if (!this._localStreams) { + this._localStreams = []; + } + return this._localStreams; + }; + } + if (!('addStream' in window.RTCPeerConnection.prototype)) { + var _addTrack = window.RTCPeerConnection.prototype.addTrack; + window.RTCPeerConnection.prototype.addStream = function (stream) { + var _this = this; + + if (!this._localStreams) { + this._localStreams = []; + } + if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + stream.getTracks().forEach(function (track) { + return _addTrack.call(_this, track, stream); + }); + }; + + window.RTCPeerConnection.prototype.addTrack = function (track, stream) { + if (stream) { + if (!this._localStreams) { + this._localStreams = [stream]; + } else if (!this._localStreams.includes(stream)) { + this._localStreams.push(stream); + } + } + return _addTrack.call(this, track, stream); + }; + } + if (!('removeStream' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.removeStream = function (stream) { + var _this2 = this; + + if (!this._localStreams) { + this._localStreams = []; + } + var index = this._localStreams.indexOf(stream); + if (index === -1) { + return; + } + this._localStreams.splice(index, 1); + var tracks = stream.getTracks(); + this.getSenders().forEach(function (sender) { + if (tracks.includes(sender.track)) { + _this2.removeTrack(sender); + } + }); + }; + } +} + +function shimRemoteStreamsAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { + window.RTCPeerConnection.prototype.getRemoteStreams = function () { + return this._remoteStreams ? this._remoteStreams : []; + }; + } + if (!('onaddstream' in window.RTCPeerConnection.prototype)) { + Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { + get: function get() { + return this._onaddstream; + }, + set: function set(f) { + var _this3 = this; + + if (this._onaddstream) { + this.removeEventListener('addstream', this._onaddstream); + this.removeEventListener('track', this._onaddstreampoly); + } + this.addEventListener('addstream', this._onaddstream = f); + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!_this3._remoteStreams) { + _this3._remoteStreams = []; + } + if (_this3._remoteStreams.includes(stream)) { + return; + } + _this3._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + _this3.dispatchEvent(event); + }); + }); + } + }); + var origSetRemoteDescription = window.RTCPeerConnection.prototype.setRemoteDescription; + window.RTCPeerConnection.prototype.setRemoteDescription = function () { + var pc = this; + if (!this._onaddstreampoly) { + this.addEventListener('track', this._onaddstreampoly = function (e) { + e.streams.forEach(function (stream) { + if (!pc._remoteStreams) { + pc._remoteStreams = []; + } + if (pc._remoteStreams.indexOf(stream) >= 0) { + return; + } + pc._remoteStreams.push(stream); + var event = new Event('addstream'); + event.stream = stream; + pc.dispatchEvent(event); + }); + }); + } + return origSetRemoteDescription.apply(pc, arguments); + }; + } +} + +function shimCallbacksAPI(window) { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) !== 'object' || !window.RTCPeerConnection) { + return; + } + var prototype = window.RTCPeerConnection.prototype; + var createOffer = prototype.createOffer; + var createAnswer = prototype.createAnswer; + var setLocalDescription = prototype.setLocalDescription; + var setRemoteDescription = prototype.setRemoteDescription; + var addIceCandidate = prototype.addIceCandidate; + + prototype.createOffer = function (successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = createOffer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + prototype.createAnswer = function (successCallback, failureCallback) { + var options = arguments.length >= 2 ? arguments[2] : arguments[0]; + var promise = createAnswer.apply(this, [options]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + + var withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setLocalDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setLocalDescription = withCallback; + + withCallback = function withCallback(description, successCallback, failureCallback) { + var promise = setRemoteDescription.apply(this, [description]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.setRemoteDescription = withCallback; + + withCallback = function withCallback(candidate, successCallback, failureCallback) { + var promise = addIceCandidate.apply(this, [candidate]); + if (!failureCallback) { + return promise; + } + promise.then(successCallback, failureCallback); + return Promise.resolve(); + }; + prototype.addIceCandidate = withCallback; +} + +function shimGetUserMedia(window) { + var navigator = window && window.navigator; + + if (navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + // shim not needed in Safari 12.1 + var mediaDevices = navigator.mediaDevices; + var _getUserMedia = mediaDevices.getUserMedia.bind(mediaDevices); + navigator.mediaDevices.getUserMedia = function (constraints) { + return _getUserMedia(shimConstraints(constraints)); + }; + } + + if (!navigator.getUserMedia && navigator.mediaDevices && navigator.mediaDevices.getUserMedia) { + navigator.getUserMedia = function (constraints, cb, errcb) { + navigator.mediaDevices.getUserMedia(constraints).then(cb, errcb); + }.bind(navigator); + } +} + +function shimConstraints(constraints) { + if (constraints && constraints.video !== undefined) { + return Object.assign({}, constraints, { video: utils.compactObject(constraints.video) }); + } + + return constraints; +} + +function shimRTCIceServerUrls(window) { + // migrate from non-spec RTCIceServer.url to RTCIceServer.urls + var OrigPeerConnection = window.RTCPeerConnection; + window.RTCPeerConnection = function (pcConfig, pcConstraints) { + if (pcConfig && pcConfig.iceServers) { + var newIceServers = []; + for (var i = 0; i < pcConfig.iceServers.length; i++) { + var server = pcConfig.iceServers[i]; + if (!server.hasOwnProperty('urls') && server.hasOwnProperty('url')) { + utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); + server = JSON.parse(JSON.stringify(server)); + server.urls = server.url; + delete server.url; + newIceServers.push(server); + } else { + newIceServers.push(pcConfig.iceServers[i]); + } + } + pcConfig.iceServers = newIceServers; + } + return new OrigPeerConnection(pcConfig, pcConstraints); + }; + window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; + // wrap static methods. Currently just generateCertificate. + if ('generateCertificate' in window.RTCPeerConnection) { + Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { + get: function get() { + return OrigPeerConnection.generateCertificate; + } + }); + } +} + +function shimTrackEventTransceiver(window) { + // Add event.transceiver member over deprecated event.receiver + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object' && window.RTCPeerConnection && 'receiver' in window.RTCTrackEvent.prototype && + // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is + // defined for some reason even when window.RTCTransceiver is not. + !window.RTCTransceiver) { + Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { + get: function get() { + return { receiver: this.receiver }; + } + }); + } +} + +function shimCreateOfferLegacy(window) { + var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; + window.RTCPeerConnection.prototype.createOffer = function (offerOptions) { + if (offerOptions) { + if (typeof offerOptions.offerToReceiveAudio !== 'undefined') { + // support bit values + offerOptions.offerToReceiveAudio = !!offerOptions.offerToReceiveAudio; + } + var audioTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.sender.track && transceiver.sender.track.kind === 'audio'; + }); + if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { + if (audioTransceiver.direction === 'sendrecv') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('sendonly'); + } else { + audioTransceiver.direction = 'sendonly'; + } + } else if (audioTransceiver.direction === 'recvonly') { + if (audioTransceiver.setDirection) { + audioTransceiver.setDirection('inactive'); + } else { + audioTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveAudio === true && !audioTransceiver) { + this.addTransceiver('audio'); + } + + if (typeof offerOptions.offerToReceiveVideo !== 'undefined') { + // support bit values + offerOptions.offerToReceiveVideo = !!offerOptions.offerToReceiveVideo; + } + var videoTransceiver = this.getTransceivers().find(function (transceiver) { + return transceiver.sender.track && transceiver.sender.track.kind === 'video'; + }); + if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { + if (videoTransceiver.direction === 'sendrecv') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('sendonly'); + } else { + videoTransceiver.direction = 'sendonly'; + } + } else if (videoTransceiver.direction === 'recvonly') { + if (videoTransceiver.setDirection) { + videoTransceiver.setDirection('inactive'); + } else { + videoTransceiver.direction = 'inactive'; + } + } + } else if (offerOptions.offerToReceiveVideo === true && !videoTransceiver) { + this.addTransceiver('video'); + } + } + return origCreateOffer.apply(this, arguments); + }; +} + +},{"../utils":15}],15:[function(require,module,exports){ +/* + * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. + * + * Use of this source code is governed by a BSD-style license + * that can be found in the LICENSE file in the root of the source + * tree. + */ +/* eslint-env node */ +'use strict'; + +Object.defineProperty(exports, "__esModule", { + value: true +}); + +var _typeof = typeof Symbol === "function" && typeof Symbol.iterator === "symbol" ? function (obj) { return typeof obj; } : function (obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; + +exports.extractVersion = extractVersion; +exports.wrapPeerConnectionEvent = wrapPeerConnectionEvent; +exports.disableLog = disableLog; +exports.disableWarnings = disableWarnings; +exports.log = log; +exports.deprecated = deprecated; +exports.detectBrowser = detectBrowser; +exports.compactObject = compactObject; + +function _defineProperty(obj, key, value) { if (key in obj) { Object.defineProperty(obj, key, { value: value, enumerable: true, configurable: true, writable: true }); } else { obj[key] = value; } return obj; } + +var logDisabled_ = true; +var deprecationWarnings_ = true; + +/** + * Extract browser version out of the provided user agent string. + * + * @param {!string} uastring userAgent string. + * @param {!string} expr Regular expression used as match criteria. + * @param {!number} pos position in the version string to be returned. + * @return {!number} browser version. + */ +function extractVersion(uastring, expr, pos) { + var match = uastring.match(expr); + return match && match.length >= pos && parseInt(match[pos], 10); +} + +// Wraps the peerconnection event eventNameToWrap in a function +// which returns the modified event object (or false to prevent +// the event). +function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { + if (!window.RTCPeerConnection) { + return; + } + var proto = window.RTCPeerConnection.prototype; + var nativeAddEventListener = proto.addEventListener; + proto.addEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap) { + return nativeAddEventListener.apply(this, arguments); + } + var wrappedCallback = function wrappedCallback(e) { + var modifiedEvent = wrapper(e); + if (modifiedEvent) { + cb(modifiedEvent); + } + }; + this._eventMap = this._eventMap || {}; + this._eventMap[cb] = wrappedCallback; + return nativeAddEventListener.apply(this, [nativeEventName, wrappedCallback]); + }; + + var nativeRemoveEventListener = proto.removeEventListener; + proto.removeEventListener = function (nativeEventName, cb) { + if (nativeEventName !== eventNameToWrap || !this._eventMap || !this._eventMap[cb]) { + return nativeRemoveEventListener.apply(this, arguments); + } + var unwrappedCb = this._eventMap[cb]; + delete this._eventMap[cb]; + return nativeRemoveEventListener.apply(this, [nativeEventName, unwrappedCb]); + }; + + Object.defineProperty(proto, 'on' + eventNameToWrap, { + get: function get() { + return this['_on' + eventNameToWrap]; + }, + set: function set(cb) { + if (this['_on' + eventNameToWrap]) { + this.removeEventListener(eventNameToWrap, this['_on' + eventNameToWrap]); + delete this['_on' + eventNameToWrap]; + } + if (cb) { + this.addEventListener(eventNameToWrap, this['_on' + eventNameToWrap] = cb); + } + }, + + enumerable: true, + configurable: true + }); +} + +function disableLog(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + logDisabled_ = bool; + return bool ? 'adapter.js logging disabled' : 'adapter.js logging enabled'; +} + +/** + * Disable or enable deprecation warnings + * @param {!boolean} bool set to true to disable warnings. + */ +function disableWarnings(bool) { + if (typeof bool !== 'boolean') { + return new Error('Argument type: ' + (typeof bool === 'undefined' ? 'undefined' : _typeof(bool)) + '. Please use a boolean.'); + } + deprecationWarnings_ = !bool; + return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); +} + +function log() { + if ((typeof window === 'undefined' ? 'undefined' : _typeof(window)) === 'object') { + if (logDisabled_) { + return; + } + if (typeof console !== 'undefined' && typeof console.log === 'function') { + console.log.apply(console, arguments); + } + } +} + +/** + * Shows a deprecation warning suggesting the modern and spec-compatible API. + */ +function deprecated(oldMethod, newMethod) { + if (!deprecationWarnings_) { + return; + } + console.warn(oldMethod + ' is deprecated, please use ' + newMethod + ' instead.'); +} + +/** + * Browser detector. + * + * @return {object} result containing browser and version + * properties. + */ +function detectBrowser(window) { + var navigator = window.navigator; + + // Returned result object. + + var result = { browser: null, version: null }; + + // Fail early if it's not a browser + if (typeof window === 'undefined' || !window.navigator) { + result.browser = 'Not a browser.'; + return result; + } + + if (navigator.mozGetUserMedia) { + // Firefox. + result.browser = 'firefox'; + result.version = extractVersion(navigator.userAgent, /Firefox\/(\d+)\./, 1); + } else if (navigator.webkitGetUserMedia) { + // Chrome, Chromium, Webview, Opera. + // Version matches Chrome/WebRTC version. + result.browser = 'chrome'; + result.version = extractVersion(navigator.userAgent, /Chrom(e|ium)\/(\d+)\./, 2); + } else if (navigator.mediaDevices && navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { + // Edge. + result.browser = 'edge'; + result.version = extractVersion(navigator.userAgent, /Edge\/(\d+).(\d+)$/, 2); + } else if (window.RTCPeerConnection && navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { + // Safari. + result.browser = 'safari'; + result.version = extractVersion(navigator.userAgent, /AppleWebKit\/(\d+)\./, 1); + } else { + // Default fallthrough: not supported. + result.browser = 'Not a supported browser.'; + return result; + } + + return result; +} + +/** + * Remove all empty objects and undefined values + * from a nested object -- an enhanced and vanilla version + * of Lodash's `compact`. + */ +function compactObject(data) { + if ((typeof data === 'undefined' ? 'undefined' : _typeof(data)) !== 'object') { + return data; + } + + return Object.keys(data).reduce(function (accumulator, key) { + var isObject = _typeof(data[key]) === 'object'; + var value = isObject ? compactObject(data[key]) : data[key]; + var isEmptyObject = isObject && !Object.keys(value).length; + if (value === undefined || isEmptyObject) { + return accumulator; + } + + return Object.assign(accumulator, _defineProperty({}, key, value)); + }, {}); +} + +},{}],16:[function(require,module,exports){ /* * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. * @@ -11,6 +2682,16 @@ var SDPUtils = require('sdp'); +function fixStatsType(stat) { + return { + inboundrtp: 'inbound-rtp', + outboundrtp: 'outbound-rtp', + candidatepair: 'candidate-pair', + localcandidate: 'local-candidate', + remotecandidate: 'remote-candidate' + }[stat.type] || stat.type; +} + function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); @@ -36,14 +2717,18 @@ function writeMediaSection(transceiver, caps, type, stream, dtlsRole) { } if (transceiver.rtpSender) { + var trackId = transceiver.rtpSender._initialTrackId || + transceiver.rtpSender.track.id; + transceiver.rtpSender._initialTrackId = trackId; // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; + var msid = 'msid:' + (stream ? stream.id : '-') + ' ' + + trackId + '\r\n'; sdp += 'a=' + msid; - - // for Chrome. + // for Chrome. Legacy should no longer be required. sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + ' ' + msid; + + // RTX if (transceiver.sendEncodingParameters[0].rtx) { sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + ' ' + msid; @@ -213,41 +2898,47 @@ function maybeAddCandidate(iceTransport, candidate) { } -// https://w3c.github.io/mediacapture-main/#mediastream -// Helper function to add the track to the stream and -// dispatch the event ourselves. -function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); -} - function makeError(name, description) { var e = new Error(description); e.name = name; + // legacy error codes from https://heycam.github.io/webidl/#idl-DOMException-error-names + e.code = { + NotSupportedError: 9, + InvalidStateError: 11, + InvalidAccessError: 15, + TypeError: undefined, + OperationError: undefined + }[name]; return e; } module.exports = function(window, edgeVersion) { + // https://w3c.github.io/mediacapture-main/#mediastream + // Helper function to add the track to the stream and + // dispatch the event ourselves. + function addTrackToStreamAndFireEvent(track, stream) { + stream.addTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('addtrack', + {track: track})); + } + + function removeTrackFromStreamAndFireEvent(track, stream) { + stream.removeTrack(track); + stream.dispatchEvent(new window.MediaStreamTrackEvent('removetrack', + {track: track})); + } + + function fireAddTrack(pc, track, receiver, streams) { + var trackEvent = new Event('track'); + trackEvent.track = track; + trackEvent.receiver = receiver; + trackEvent.transceiver = {receiver: receiver}; + trackEvent.streams = streams; + window.setTimeout(function() { + pc._dispatchEvent('track', trackEvent); + }); + } + var RTCPeerConnection = function(config) { var pc = this; @@ -264,11 +2955,12 @@ module.exports = function(window, edgeVersion) { this.localStreams = []; this.remoteStreams = []; - this.localDescription = null; - this.remoteDescription = null; + this._localDescription = null; + this._remoteDescription = null; this.signalingState = 'stable'; this.iceConnectionState = 'new'; + this.connectionState = 'new'; this.iceGatheringState = 'new'; config = JSON.parse(JSON.stringify(config || {})); @@ -305,10 +2997,10 @@ module.exports = function(window, edgeVersion) { this._iceGatherers = []; if (config.iceCandidatePoolSize) { for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers = new window.RTCIceGatherer({ + this._iceGatherers.push(new window.RTCIceGatherer({ iceServers: config.iceServers, gatherPolicy: config.iceTransportPolicy - }); + })); } } else { config.iceCandidatePoolSize = 0; @@ -328,6 +3020,19 @@ module.exports = function(window, edgeVersion) { this._isClosed = false; }; + Object.defineProperty(RTCPeerConnection.prototype, 'localDescription', { + configurable: true, + get: function() { + return this._localDescription; + } + }); + Object.defineProperty(RTCPeerConnection.prototype, 'remoteDescription', { + configurable: true, + get: function() { + return this._remoteDescription; + } + }); + // set up event handlers on prototype RTCPeerConnection.prototype.onicecandidate = null; RTCPeerConnection.prototype.onaddstream = null; @@ -335,6 +3040,7 @@ module.exports = function(window, edgeVersion) { RTCPeerConnection.prototype.onremovestream = null; RTCPeerConnection.prototype.onsignalingstatechange = null; RTCPeerConnection.prototype.oniceconnectionstatechange = null; + RTCPeerConnection.prototype.onconnectionstatechange = null; RTCPeerConnection.prototype.onicegatheringstatechange = null; RTCPeerConnection.prototype.onnegotiationneeded = null; RTCPeerConnection.prototype.ondatachannel = null; @@ -367,8 +3073,8 @@ module.exports = function(window, edgeVersion) { }; // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { + // (which is not yet the same as the WebRTC 1.0 transceiver) + RTCPeerConnection.prototype._createTransceiver = function(kind, doNotAdd) { var hasBundleTransport = this.transceivers.length > 0; var transceiver = { track: null, @@ -395,11 +3101,18 @@ module.exports = function(window, edgeVersion) { transceiver.iceTransport = transports.iceTransport; transceiver.dtlsTransport = transports.dtlsTransport; } - this.transceivers.push(transceiver); + if (!doNotAdd) { + this.transceivers.push(transceiver); + } return transceiver; }; RTCPeerConnection.prototype.addTrack = function(track, stream) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call addTrack on a closed peerconnection.'); + } + var alreadyExists = this.transceivers.find(function(s) { return s.track === track; }); @@ -408,11 +3121,6 @@ module.exports = function(window, edgeVersion) { throw makeError('InvalidAccessError', 'Track already exists.'); } - if (this.signalingState === 'closed') { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - var transceiver; for (var i = 0; i < this.transceivers.length; i++) { if (!this.transceivers[i].track && @@ -461,6 +3169,11 @@ module.exports = function(window, edgeVersion) { }; RTCPeerConnection.prototype.removeTrack = function(sender) { + if (this._isClosed) { + throw makeError('InvalidStateError', + 'Attempted to call removeTrack on a closed peerconnection.'); + } + if (!(sender instanceof window.RTCRtpSender)) { throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + 'does not implement interface RTCRtpSender.'); @@ -540,14 +3253,14 @@ module.exports = function(window, edgeVersion) { {value: 'new', writable: true} ); - this.transceivers[sdpMLineIndex].candidates = []; + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = []; this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { var end = !event.candidate || Object.keys(event.candidate).length === 0; // polyfill since RTCIceGatherer.state is not implemented in // Edge 10547 yet. iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].candidates !== null) { - pc.transceivers[sdpMLineIndex].candidates.push(event.candidate); + if (pc.transceivers[sdpMLineIndex].bufferedCandidateEvents !== null) { + pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event); } }; iceGatherer.addEventListener('localcandidate', @@ -562,8 +3275,9 @@ module.exports = function(window, edgeVersion) { if (iceGatherer.onlocalcandidate) { return; } - var candidates = this.transceivers[sdpMLineIndex].candidates; - this.transceivers[sdpMLineIndex].candidates = null; + var bufferedCandidateEvents = + this.transceivers[sdpMLineIndex].bufferedCandidateEvents; + this.transceivers[sdpMLineIndex].bufferedCandidateEvents = null; iceGatherer.removeEventListener('localcandidate', this.transceivers[sdpMLineIndex].bufferCandidates); iceGatherer.onlocalcandidate = function(evt) { @@ -591,19 +3305,36 @@ module.exports = function(window, edgeVersion) { } // RTCIceCandidate doesn't have a component, needs to be added cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); + // also the usernameFragment. TODO: update SDP to take both variants. + cand.ufrag = iceGatherer.getLocalParameters().usernameFragment; + + var serializedCandidate = SDPUtils.writeCandidate(cand); + event.candidate = Object.assign(event.candidate, + SDPUtils.parseCandidate(serializedCandidate)); + + event.candidate.candidate = serializedCandidate; + event.candidate.toJSON = function() { + return { + candidate: event.candidate.candidate, + sdpMid: event.candidate.sdpMid, + sdpMLineIndex: event.candidate.sdpMLineIndex, + usernameFragment: event.candidate.usernameFragment + }; + }; } // update local description. - var sections = SDPUtils.splitSections(pc.localDescription.sdp); + var sections = SDPUtils.getMediaSections(pc._localDescription.sdp); if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += + sections[event.candidate.sdpMLineIndex] += 'a=' + event.candidate.candidate + '\r\n'; } else { - sections[event.candidate.sdpMLineIndex + 1] += + sections[event.candidate.sdpMLineIndex] += 'a=end-of-candidates\r\n'; } - pc.localDescription.sdp = sections.join(''); + pc._localDescription.sdp = + SDPUtils.getDescription(pc._localDescription.sdp) + + sections.join(''); var complete = pc.transceivers.every(function(transceiver) { return transceiver.iceGatherer && transceiver.iceGatherer.state === 'completed'; @@ -628,9 +3359,7 @@ module.exports = function(window, edgeVersion) { // emit already gathered candidates. window.setTimeout(function() { - candidates.forEach(function(candidate) { - var e = new Event('RTCIceGatherEvent'); - e.candidate = candidate; + bufferedCandidateEvents.forEach(function(e) { iceGatherer.onlocalcandidate(e); }); }, 0); @@ -641,6 +3370,7 @@ module.exports = function(window, edgeVersion) { var pc = this; var iceTransport = new window.RTCIceTransport(null); iceTransport.onicestatechange = function() { + pc._updateIceConnectionState(); pc._updateConnectionState(); }; @@ -649,7 +3379,7 @@ module.exports = function(window, edgeVersion) { pc._updateConnectionState(); }; dtlsTransport.onerror = function() { - // onerror does not set state to failed by itpc. + // onerror does not set state to failed by itself. Object.defineProperty(dtlsTransport, 'state', {value: 'failed', writable: true}); pc._updateConnectionState(); @@ -710,6 +3440,8 @@ module.exports = function(window, edgeVersion) { } if (transceiver.recvEncodingParameters.length) { params.encodings = transceiver.recvEncodingParameters; + } else { + params.encodings = [{}]; } params.rtcp = { compound: transceiver.rtcpParameters.compound @@ -727,8 +3459,14 @@ module.exports = function(window, edgeVersion) { RTCPeerConnection.prototype.setLocalDescription = function(description) { var pc = this; + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState) || this._isClosed) { + description.type, pc.signalingState) || pc._isClosed) { return Promise.reject(makeError('InvalidStateError', 'Can not set local ' + description.type + ' in state ' + pc.signalingState)); @@ -746,11 +3484,11 @@ module.exports = function(window, edgeVersion) { pc.transceivers[sdpMLineIndex].localCapabilities = caps; }); - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { pc._gather(transceiver.mid, sdpMLineIndex); }); } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc.remoteDescription.sdp); + sections = SDPUtils.splitSections(pc._remoteDescription.sdp); sessionpart = sections.shift(); var isIceLite = SDPUtils.matchPrefix(sessionpart, 'a=ice-lite').length > 0; @@ -766,7 +3504,7 @@ module.exports = function(window, edgeVersion) { var rejected = SDPUtils.isRejected(mediaSection) && SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - if (!rejected && !transceiver.isDatachannel) { + if (!rejected && !transceiver.rejected) { var remoteIceParameters = SDPUtils.getIceParameters( mediaSection, sessionpart); var remoteDtlsParameters = SDPUtils.getDtlsParameters( @@ -799,20 +3537,14 @@ module.exports = function(window, edgeVersion) { }); } - this.localDescription = { + pc._localDescription = { type: description.type, sdp: description.sdp }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); + if (description.type === 'offer') { + pc._updateSignalingState('have-local-offer'); + } else { + pc._updateSignalingState('stable'); } return Promise.resolve(); @@ -821,15 +3553,21 @@ module.exports = function(window, edgeVersion) { RTCPeerConnection.prototype.setRemoteDescription = function(description) { var pc = this; + // Note: pranswer is not supported. + if (['offer', 'answer'].indexOf(description.type) === -1) { + return Promise.reject(makeError('TypeError', + 'Unsupported type "' + description.type + '"')); + } + if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState) || this._isClosed) { + description.type, pc.signalingState) || pc._isClosed) { return Promise.reject(makeError('InvalidStateError', 'Can not set remote ' + description.type + ' in state ' + pc.signalingState)); } var streams = {}; - this.remoteStreams.forEach(function(stream) { + pc.remoteStreams.forEach(function(stream) { streams[stream.id] = stream; }); var receiverList = []; @@ -839,14 +3577,14 @@ module.exports = function(window, edgeVersion) { 'a=ice-lite').length > 0; var usingBundle = SDPUtils.matchPrefix(sessionpart, 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; + pc.usingBundle = usingBundle; var iceOptions = SDPUtils.matchPrefix(sessionpart, 'a=ice-options:')[0]; if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') + pc.canTrickleIceCandidates = iceOptions.substr(14).split(' ') .indexOf('trickle') >= 0; } else { - this.canTrickleIceCandidates = false; + pc.canTrickleIceCandidates = false; } sections.forEach(function(mediaSection, sdpMLineIndex) { @@ -863,14 +3601,25 @@ module.exports = function(window, edgeVersion) { var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { + if (rejected || (kind === 'application' && (protocol === 'DTLS/SCTP' || + protocol === 'UDP/DTLS/SCTP'))) { + // TODO: this is dangerous in the case where a non-rejected m-line + // becomes rejected. pc.transceivers[sdpMLineIndex] = { mid: mid, - isDatachannel: true + kind: kind, + protocol: protocol, + rejected: true }; return; } + if (!rejected && pc.transceivers[sdpMLineIndex] && + pc.transceivers[sdpMLineIndex].rejected) { + // recycle a rejected transceiver. + pc.transceivers[sdpMLineIndex] = pc._createTransceiver(kind, true); + } + var transceiver; var iceGatherer; var iceTransport; @@ -1062,6 +3811,19 @@ module.exports = function(window, edgeVersion) { } } + // If the offer contained RTX but the answer did not, + // remove RTX from sendEncodingParameters. + var commonCapabilities = getCommonCapabilities( + transceiver.localCapabilities, + transceiver.remoteCapabilities); + + var hasRtx = commonCapabilities.codecs.filter(function(c) { + return c.name.toLowerCase() === 'rtx'; + }).length; + if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { + delete transceiver.sendEncodingParameters[0].rtx; + } + pc._transceive(transceiver, direction === 'sendrecv' || direction === 'recvonly', direction === 'sendrecv' || direction === 'sendonly'); @@ -1090,24 +3852,18 @@ module.exports = function(window, edgeVersion) { } }); - if (this._dtlsRole === undefined) { - this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; + if (pc._dtlsRole === undefined) { + pc._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; } - this.remoteDescription = { + pc._remoteDescription = { type: description.type, sdp: description.sdp }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); + if (description.type === 'offer') { + pc._updateSignalingState('have-remote-offer'); + } else { + pc._updateSignalingState('stable'); } Object.keys(streams).forEach(function(sid) { var stream = streams[sid]; @@ -1198,22 +3954,20 @@ module.exports = function(window, edgeVersion) { } this.needNegotiation = true; window.setTimeout(function() { - if (pc.needNegotiation === false) { - return; + if (pc.needNegotiation) { + pc.needNegotiation = false; + var event = new Event('negotiationneeded'); + pc._dispatchEvent('negotiationneeded', event); } - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); }, 0); }; - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { + // Update the ice connection state. + RTCPeerConnection.prototype._updateIceConnectionState = function() { var newState; var states = { 'new': 0, closed: 0, - connecting: 0, checking: 0, connected: 0, completed: 0, @@ -1221,23 +3975,24 @@ module.exports = function(window, edgeVersion) { failed: 0 }; this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; + if (transceiver.iceTransport && !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + } }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; newState = 'new'; if (states.failed > 0) { newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; + } else if (states.checking > 0) { + newState = 'checking'; } else if (states.disconnected > 0) { newState = 'disconnected'; } else if (states.new > 0) { newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { + } else if (states.connected > 0) { newState = 'connected'; + } else if (states.completed > 0) { + newState = 'completed'; } if (newState !== this.iceConnectionState) { @@ -1247,18 +4002,60 @@ module.exports = function(window, edgeVersion) { } }; + // Update the connection state. + RTCPeerConnection.prototype._updateConnectionState = function() { + var newState; + var states = { + 'new': 0, + closed: 0, + connecting: 0, + connected: 0, + completed: 0, + disconnected: 0, + failed: 0 + }; + this.transceivers.forEach(function(transceiver) { + if (transceiver.iceTransport && transceiver.dtlsTransport && + !transceiver.rejected) { + states[transceiver.iceTransport.state]++; + states[transceiver.dtlsTransport.state]++; + } + }); + // ICETransport.completed and connected are the same for this purpose. + states.connected += states.completed; + + newState = 'new'; + if (states.failed > 0) { + newState = 'failed'; + } else if (states.connecting > 0) { + newState = 'connecting'; + } else if (states.disconnected > 0) { + newState = 'disconnected'; + } else if (states.new > 0) { + newState = 'new'; + } else if (states.connected > 0) { + newState = 'connected'; + } + + if (newState !== this.connectionState) { + this.connectionState = newState; + var event = new Event('connectionstatechange'); + this._dispatchEvent('connectionstatechange', event); + } + }; + RTCPeerConnection.prototype.createOffer = function() { var pc = this; - if (this._isClosed) { + if (pc._isClosed) { return Promise.reject(makeError('InvalidStateError', 'Can not call createOffer after close')); } - var numAudioTracks = this.transceivers.filter(function(t) { + var numAudioTracks = pc.transceivers.filter(function(t) { return t.kind === 'audio'; }).length; - var numVideoTracks = this.transceivers.filter(function(t) { + var numVideoTracks = pc.transceivers.filter(function(t) { return t.kind === 'video'; }).length; @@ -1290,7 +4087,7 @@ module.exports = function(window, edgeVersion) { } } - this.transceivers.forEach(function(transceiver) { + pc.transceivers.forEach(function(transceiver) { if (transceiver.kind === 'audio') { numAudioTracks--; if (numAudioTracks < 0) { @@ -1307,23 +4104,23 @@ module.exports = function(window, edgeVersion) { // Create M-lines for recvonly streams. while (numAudioTracks > 0 || numVideoTracks > 0) { if (numAudioTracks > 0) { - this._createTransceiver('audio'); + pc._createTransceiver('audio'); numAudioTracks--; } if (numVideoTracks > 0) { - this._createTransceiver('video'); + pc._createTransceiver('video'); numVideoTracks--; } } - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { // For each track, create an ice gatherer, ice transport, // dtls transport, potentially rtpsender and rtpreceiver. var track = transceiver.track; var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); + var mid = transceiver.mid || SDPUtils.generateIdentifier(); transceiver.mid = mid; if (!transceiver.iceGatherer) { @@ -1347,6 +4144,27 @@ module.exports = function(window, edgeVersion) { codec.parameters['level-asymmetry-allowed'] === undefined) { codec.parameters['level-asymmetry-allowed'] = '1'; } + + // for subsequent offers, we might have to re-use the payload + // type of the last offer. + if (transceiver.remoteCapabilities && + transceiver.remoteCapabilities.codecs) { + transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec) { + if (codec.name.toLowerCase() === remoteCodec.name.toLowerCase() && + codec.clockRate === remoteCodec.clockRate) { + codec.preferredPayloadType = remoteCodec.payloadType; + } + }); + } + }); + localCapabilities.headerExtensions.forEach(function(hdrExt) { + var remoteExtensions = transceiver.remoteCapabilities && + transceiver.remoteCapabilities.headerExtensions || []; + remoteExtensions.forEach(function(rHdrExt) { + if (hdrExt.uri === rHdrExt.uri) { + hdrExt.id = rHdrExt.id; + } + }); }); // generate an ssrc now, to be used later in rtpSender.send @@ -1373,14 +4191,14 @@ module.exports = function(window, edgeVersion) { }); // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { + if (pc._config.bundlePolicy !== 'max-compat') { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { return t.mid; }).join(' ') + '\r\n'; } sdp += 'a=ice-options:trickle\r\n'; - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { sdp += writeMediaSection(transceiver, transceiver.localCapabilities, 'offer', transceiver.stream, pc._dtlsRole); sdp += 'a=rtcp-rsize\r\n'; @@ -1408,27 +4226,49 @@ module.exports = function(window, edgeVersion) { RTCPeerConnection.prototype.createAnswer = function() { var pc = this; - if (this._isClosed) { + if (pc._isClosed) { return Promise.reject(makeError('InvalidStateError', 'Can not call createAnswer after close')); } - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { + if (!(pc.signalingState === 'have-remote-offer' || + pc.signalingState === 'have-local-pranswer')) { + return Promise.reject(makeError('InvalidStateError', + 'Can not call createAnswer in signalingState ' + pc.signalingState)); + } + + var sdp = SDPUtils.writeSessionBoilerplate(pc._sdpSessionId, + pc._sdpSessionVersion++); + if (pc.usingBundle) { + sdp += 'a=group:BUNDLE ' + pc.transceivers.map(function(t) { return t.mid; }).join(' ') + '\r\n'; } - var mediaSectionsInOffer = SDPUtils.splitSections( - this.remoteDescription.sdp).length - 1; - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { + sdp += 'a=ice-options:trickle\r\n'; + + var mediaSectionsInOffer = SDPUtils.getMediaSections( + pc._remoteDescription.sdp).length; + pc.transceivers.forEach(function(transceiver, sdpMLineIndex) { if (sdpMLineIndex + 1 > mediaSectionsInOffer) { return; } - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + + if (transceiver.rejected) { + if (transceiver.kind === 'application') { + if (transceiver.protocol === 'DTLS/SCTP') { // legacy fmt + sdp += 'm=application 0 DTLS/SCTP 5000\r\n'; + } else { + sdp += 'm=application 0 ' + transceiver.protocol + + ' webrtc-datachannel\r\n'; + } + } else if (transceiver.kind === 'audio') { + sdp += 'm=audio 0 UDP/TLS/RTP/SAVPF 0\r\n' + + 'a=rtpmap:0 PCMU/8000\r\n'; + } else if (transceiver.kind === 'video') { + sdp += 'm=video 0 UDP/TLS/RTP/SAVPF 120\r\n' + + 'a=rtpmap:120 VP8/90000\r\n'; + } + sdp += 'c=IN IP4 0.0.0.0\r\n' + + 'a=inactive\r\n' + 'a=mid:' + transceiver.mid + '\r\n'; return; } @@ -1480,79 +4320,107 @@ module.exports = function(window, edgeVersion) { }; RTCPeerConnection.prototype.addIceCandidate = function(candidate) { + var pc = this; var sections; - if (!candidate || candidate.candidate === '') { - for (var j = 0; j < this.transceivers.length; j++) { - if (this.transceivers[j].isDatachannel) { - continue; - } - this.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[j + 1] += 'a=end-of-candidates\r\n'; - this.remoteDescription.sdp = sections.join(''); - if (this.usingBundle) { - break; - } - } - } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { - throw new TypeError('sdpMLineIndex or sdpMid required'); - } else if (!this.remoteDescription) { - return Promise.reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; + if (candidate && !(candidate.sdpMLineIndex !== undefined || + candidate.sdpMid)) { + return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required')); + } + + // TODO: needs to go into ops queue. + return new Promise(function(resolve, reject) { + if (!pc._remoteDescription) { + return reject(makeError('InvalidStateError', + 'Can not add ICE candidate without a remote description')); + } else if (!candidate || candidate.candidate === '') { + for (var j = 0; j < pc.transceivers.length; j++) { + if (pc.transceivers[j].rejected) { + continue; + } + pc.transceivers[j].iceTransport.addRemoteCandidate({}); + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[j] += 'a=end-of-candidates\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + if (pc.usingBundle) { break; } } - } - var transceiver = this.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.isDatachannel) { - return Promise.resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return Promise.resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== this.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); + } else { + var sdpMLineIndex = candidate.sdpMLineIndex; + if (candidate.sdpMid) { + for (var i = 0; i < pc.transceivers.length; i++) { + if (pc.transceivers[i].mid === candidate.sdpMid) { + sdpMLineIndex = i; + break; + } } } + var transceiver = pc.transceivers[sdpMLineIndex]; + if (transceiver) { + if (transceiver.rejected) { + return resolve(); + } + var cand = Object.keys(candidate.candidate).length > 0 ? + SDPUtils.parseCandidate(candidate.candidate) : {}; + // Ignore Chrome's invalid candidates since Edge does not like them. + if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { + return resolve(); + } + // Ignore RTCP candidates, we assume RTCP-MUX. + if (cand.component && cand.component !== 1) { + return resolve(); + } + // when using bundle, avoid adding candidates to the wrong + // ice transport. And avoid adding candidates added in the SDP. + if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && + transceiver.iceTransport !== pc.transceivers[0].iceTransport)) { + if (!maybeAddCandidate(transceiver.iceTransport, cand)) { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); + } + } - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); + // update the remoteDescription. + var candidateString = candidate.candidate.trim(); + if (candidateString.indexOf('a=') === 0) { + candidateString = candidateString.substr(2); + } + sections = SDPUtils.getMediaSections(pc._remoteDescription.sdp); + sections[sdpMLineIndex] += 'a=' + + (cand.type ? candidateString : 'end-of-candidates') + + '\r\n'; + pc._remoteDescription.sdp = + SDPUtils.getDescription(pc._remoteDescription.sdp) + + sections.join(''); + } else { + return reject(makeError('OperationError', + 'Can not add ICE candidate')); } - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[sdpMLineIndex + 1] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } else { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); } - } - return Promise.resolve(); + resolve(); + }); }; - RTCPeerConnection.prototype.getStats = function() { + RTCPeerConnection.prototype.getStats = function(selector) { + if (selector && selector instanceof window.MediaStreamTrack) { + var senderOrReceiver = null; + this.transceivers.forEach(function(transceiver) { + if (transceiver.rtpSender && + transceiver.rtpSender.track === selector) { + senderOrReceiver = transceiver.rtpSender; + } else if (transceiver.rtpReceiver && + transceiver.rtpReceiver.track === selector) { + senderOrReceiver = transceiver.rtpReceiver; + } + }); + if (!senderOrReceiver) { + throw makeError('InvalidAccessError', 'Invalid selector.'); + } + return senderOrReceiver.getStats(); + } + var promises = []; this.transceivers.forEach(function(transceiver) { ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', @@ -1562,30 +4430,38 @@ module.exports = function(window, edgeVersion) { } }); }); - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support + return Promise.all(promises).then(function(allStats) { var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); + allStats.forEach(function(stats) { + stats.forEach(function(stat) { + results.set(stat.id, stat); }); - resolve(results); }); + return results; }); }; + // fix low-level stat names and return Map instead of object. + var ortcObjects = ['RTCRtpSender', 'RTCRtpReceiver', 'RTCIceGatherer', + 'RTCIceTransport', 'RTCDtlsTransport']; + ortcObjects.forEach(function(ortcObjectName) { + var obj = window[ortcObjectName]; + if (obj && obj.prototype && obj.prototype.getStats) { + var nativeGetstats = obj.prototype.getStats; + obj.prototype.getStats = function() { + return nativeGetstats.apply(this) + .then(function(nativeStats) { + var mapStats = new Map(); + Object.keys(nativeStats).forEach(function(id) { + nativeStats[id].type = fixStatsType(nativeStats[id]); + mapStats.set(id, nativeStats[id]); + }); + return mapStats; + }); + }; + } + }); + // legacy callback shims. Should be moved to adapter.js some days. var methods = ['createOffer', 'createAnswer']; methods.forEach(function(method) { @@ -1652,7 +4528,7 @@ module.exports = function(window, edgeVersion) { return RTCPeerConnection; }; -},{"sdp":2}],2:[function(require,module,exports){ +},{"sdp":17}],17:[function(require,module,exports){ /* eslint-env node */ 'use strict'; @@ -1682,6 +4558,19 @@ SDPUtils.splitSections = function(blob) { }); }; +// returns the session description. +SDPUtils.getDescription = function(blob) { + var sections = SDPUtils.splitSections(blob); + return sections && sections[0]; +}; + +// returns the individual media sections. +SDPUtils.getMediaSections = function(blob) { + var sections = SDPUtils.splitSections(blob); + sections.shift(); + return sections; +}; + // Returns lines that start with a certain prefix. SDPUtils.matchPrefix = function(blob, prefix) { return SDPUtils.splitLines(blob).filter(function(line) { @@ -1707,6 +4596,7 @@ SDPUtils.parseCandidate = function(line) { protocol: parts[2].toLowerCase(), priority: parseInt(parts[3], 10), ip: parts[4], + address: parts[4], // address is an alias for ip. port: parseInt(parts[5], 10), // skip parts[6] == 'typ' type: parts[7] @@ -1742,7 +4632,7 @@ SDPUtils.writeCandidate = function(candidate) { sdp.push(candidate.component); sdp.push(candidate.protocol.toUpperCase()); sdp.push(candidate.priority); - sdp.push(candidate.ip); + sdp.push(candidate.address || candidate.ip); sdp.push(candidate.port); var type = candidate.type; @@ -1751,17 +4641,17 @@ SDPUtils.writeCandidate = function(candidate) { if (type !== 'host' && candidate.relatedAddress && candidate.relatedPort) { sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr + sdp.push(candidate.relatedAddress); sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort + sdp.push(candidate.relatedPort); } if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { sdp.push('tcptype'); sdp.push(candidate.tcpType); } - if (candidate.ufrag) { + if (candidate.usernameFragment || candidate.ufrag) { sdp.push('ufrag'); - sdp.push(candidate.ufrag); + sdp.push(candidate.usernameFragment || candidate.ufrag); } return 'candidate:' + sdp.join(' '); }; @@ -1770,7 +4660,7 @@ SDPUtils.writeCandidate = function(candidate) { // a=ice-options:foo bar SDPUtils.parseIceOptions = function(line) { return line.substr(14).split(' '); -} +}; // Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: // a=rtpmap:111 opus/48000/2 @@ -1784,8 +4674,9 @@ SDPUtils.parseRtpMap = function(line) { parsed.name = parts[0]; parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; + parsed.channels = parts.length === 3 ? parseInt(parts[2], 10) : 1; + // legacy alias, got renamed back to channels in ORTC. + parsed.numChannels = parsed.channels; return parsed; }; @@ -1796,8 +4687,9 @@ SDPUtils.writeRtpMap = function(codec) { if (codec.preferredPayloadType !== undefined) { pt = codec.preferredPayloadType; } + var channels = codec.channels || codec.numChannels || 1; return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; + (channels !== 1 ? '/' + channels : '') + '\r\n'; }; // Parses an a=extmap line (headerextension from RFC 5285). Sample input: @@ -1846,7 +4738,11 @@ SDPUtils.writeFmtp = function(codec) { if (codec.parameters && Object.keys(codec.parameters).length) { var params = []; Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); + if (codec.parameters[param]) { + params.push(param + '=' + codec.parameters[param]); + } else { + params.push(param); + } }); line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; } @@ -1897,6 +4793,16 @@ SDPUtils.parseSsrcMedia = function(line) { return parts; }; +SDPUtils.parseSsrcGroup = function(line) { + var parts = line.substr(13).split(' '); + return { + semantics: parts.shift(), + ssrcs: parts.map(function(ssrc) { + return parseInt(ssrc, 10); + }) + }; +}; + // Extracts the MID (RFC 5888) from a media section. // returns the MID or undefined if no mid line was found. SDPUtils.getMid = function(mediaSection) { @@ -1904,7 +4810,7 @@ SDPUtils.getMid = function(mediaSection) { if (mid) { return mid.substr(6); } -} +}; SDPUtils.parseFingerprint = function(line) { var parts = line.substr(14).split(' '); @@ -2038,9 +4944,11 @@ SDPUtils.writeRtpDescription = function(kind, caps) { } sdp += 'a=rtcp-mux\r\n'; - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); + if (caps.headerExtensions) { + caps.headerExtensions.forEach(function(extension) { + sdp += SDPUtils.writeExtmap(extension); + }); + } // FIXME: write fecMechanisms. return sdp; }; @@ -2066,8 +4974,7 @@ SDPUtils.parseRtpEncodingParameters = function(mediaSection) { var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') .map(function(line) { - var parts = line.split(' '); - parts.shift(); + var parts = line.substr(17).split(' '); return parts.map(function(part) { return parseInt(part, 10); }); @@ -2080,16 +4987,16 @@ SDPUtils.parseRtpEncodingParameters = function(mediaSection) { if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { var encParam = { ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } + codecPayloadType: parseInt(codec.parameters.apt, 10) }; + if (primarySsrc && secondarySsrc) { + encParam.rtx = {ssrc: secondarySsrc}; + } encodingParameters.push(encParam); if (hasRed) { encParam = JSON.parse(JSON.stringify(encParam)); encParam.fec = { - ssrc: secondarySsrc, + ssrc: primarySsrc, mechanism: hasUlpfec ? 'red+ulpfec' : 'red' }; encodingParameters.push(encParam); @@ -2125,8 +5032,7 @@ SDPUtils.parseRtpEncodingParameters = function(mediaSection) { SDPUtils.parseRtcpParameters = function(mediaSection) { var rtcpParameters = {}; - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple + // Gets the first SSRC. Note tha with RTX there might be multiple // SSRCs. var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') .map(function(line) { @@ -2167,8 +5073,8 @@ SDPUtils.parseMsid = function(mediaSection) { .map(function(line) { return SDPUtils.parseSsrcMedia(line); }) - .filter(function(parts) { - return parts.attribute === 'msid'; + .filter(function(msidParts) { + return msidParts.attribute === 'msid'; }); if (planB.length > 0) { parts = planB[0].value.split(' '); @@ -2188,7 +5094,8 @@ SDPUtils.generateSessionId = function() { // sessId argument is optional - if not supplied it will // be generated randomly // sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { +// sessUser is optional and defaults to 'thisisadapterortc' +SDPUtils.writeSessionBoilerplate = function(sessId, sessVer, sessUser) { var sessionId; var version = sessVer !== undefined ? sessVer : 2; if (sessId) { @@ -2196,9 +5103,11 @@ SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { } else { sessionId = SDPUtils.generateSessionId(); } + var user = sessUser || 'thisisadapterortc'; // FIXME: sess-id should be an NTP timestamp. return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + + 'o=' + user + ' ' + sessionId + ' ' + version + + ' IN IP4 127.0.0.1\r\n' + 's=-\r\n' + 't=0 0\r\n'; }; @@ -2290,2477 +5199,47 @@ SDPUtils.isRejected = function(mediaSection) { SDPUtils.parseMLine = function(mediaSection) { var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); + var parts = lines[0].substr(2).split(' '); return { - kind: mline[0].substr(2), - port: parseInt(mline[1], 10), - protocol: mline[2], - fmt: mline.slice(3).join(' ') + kind: parts[0], + port: parseInt(parts[1], 10), + protocol: parts[2], + fmt: parts.slice(3).join(' ') }; }; +SDPUtils.parseOLine = function(mediaSection) { + var line = SDPUtils.matchPrefix(mediaSection, 'o=')[0]; + var parts = line.substr(2).split(' '); + return { + username: parts[0], + sessionId: parts[1], + sessionVersion: parseInt(parts[2], 10), + netType: parts[3], + addressType: parts[4], + address: parts[5] + }; +}; + +// a very naive interpretation of a valid SDP. +SDPUtils.isValidSDP = function(blob) { + if (typeof blob !== 'string' || blob.length === 0) { + return false; + } + var lines = SDPUtils.splitLines(blob); + for (var i = 0; i < lines.length; i++) { + if (lines[i].length < 2 || lines[i].charAt(1) !== '=') { + return false; + } + // TODO: check the modifier a bit more. + } + return true; +}; + // Expose public methods. if (typeof module === 'object') { module.exports = SDPUtils; } -},{}],3:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":4}],4:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var utils = require('./utils'); -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - var commonShim = require('./common_shim') || null; - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - commonShim.shimCreateObjectURL(window); - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - commonShim.shimCreateObjectURL(window); - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - commonShim.shimCreateObjectURL(window); - - edgeShim.shimGetUserMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - commonShim.shimCreateObjectURL(window); - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimCreateOfferLegacy(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){ - -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - } - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } else if (!('RTCRtpTransceiver' in window)) { - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - if (!e.transceiver) { - e.transceiver = {receiver: e.receiver}; - } - return e; - }); - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrackWithNative: function(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function(streamId) { - return pc._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - var existingSenders = pc.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = pc.getSenders().filter(function(newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function(streamId) { - var idx = pc._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - pc._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (pc._shimmedLocalStreams[streamId].length === 1) { - delete pc._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; - }, - - shimAddTrackRemoveTrack: function(window) { - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && - browserDetails.version >= 65) { - return this.shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - var nativeStreams = origGetLocalStreams.apply(this); - pc._reverseStreams = pc._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return pc._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function() { - pc.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), - externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), - internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - var args = arguments; - var isLegacyCall = arguments.length && - typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(pc, [ - function(description) { - var desc = replaceInternalStreamId(pc, description); - args[0].apply(null, [desc]); - }, - function(err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2] - ]); - } - return nativeMethod.apply(pc, arguments) - .then(function(description) { - return replaceInternalStreamId(pc, description); - }); - }; - }); - - var origSetLocalDescription = - window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function() { - var pc = this; - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(pc, arguments); - } - arguments[0] = replaceExternalStreamId(pc, arguments[0]); - return origSetLocalDescription.apply(pc, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor( - window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, - 'localDescription', { - get: function() { - var pc = this; - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(pc, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(pc._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var pc = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(pc, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var pc = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof arguments[0] === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - -},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - var constraintsToChrome_ = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - InvalidStateError: 'NotReadableError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotReadableError', - MediaDeviceKillSwitchOn: 'NotReadableError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return getUserMediaPromise_(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":13}],7:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var utils = require('./utils'); - -module.exports = { - shimRTCIceCandidate: function(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (window.RTCIceCandidate && 'foundation' in - window.RTCIceCandidate.prototype) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function(args) { - // Remove the a= which shouldn't be part of the candidate string. - if (typeof args === 'object' && args.candidate && - args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = SDPUtils.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, - parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment, - }; - }; - return augmentedCandidate; - }; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype && - URL.createObjectURL && URL.revokeObjectURL)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - }, - - shimMaxMessageSize: function(window) { - if (window.RTCSctpTransport || !window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function(description) { - var sections = SDPUtils.splitSections(description.sdp); - sections.shift(); - return sections.some(function(mediaSection) { - var mLine = SDPUtils.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' - && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = - browserDetails.version === 57 ? 65535 : 65536; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' - && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && - remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - pc._sctp = null; - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function() { - return maxMessageSize; - } - }); - pc._sctp = sctp; - } - - return origSetRemoteDescription.apply(pc, arguments); - }; - }, - - shimSendThrowTypeError: function(window) { - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - var origCreateDataChannel = - window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function() { - var pc = this; - var dataChannel = origCreateDataChannel.apply(pc, arguments); - var origDataChannelSend = dataChannel.send; - - // Patch 'send' method - dataChannel.send = function() { - var dc = this; - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (length > pc.sctp.maxMessageSize) { - throw new DOMException('Message too large (can send a maximum of ' + - pc.sctp.maxMessageSize + ' bytes)', 'TypeError'); - } - return origDataChannelSend.apply(dc, arguments); - }; - - return dataChannel; - }; - } -}; - -},{"./utils":13,"sdp":2}],8:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var shimRTCPeerConnection = require('rtcpeerconnection-shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - - window.RTCPeerConnection = - shimRTCPeerConnection(window, browserDetails.version); - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.transceiver = {receiver: event.receiver}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - if (typeof window === 'object' && window.RTCTrackEvent && - ('receiver' in window.RTCTrackEvent.prototype) && - !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - }, - - shimRemoveStream: function(window) { - if (!window.RTCPeerConnection || - 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function(sender) { - if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } -}; - -},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var getUserMedia_ = function(constraints, onSuccess, onError) { - var constraintsToFF37_ = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r. min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":13}],12:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; -var utils = require('../utils'); - -module.exports = { - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var pc = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(pc, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - return _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var pc = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - var pc = this; - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - e.streams.forEach(function(stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in window.RTCPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - }, - shimTrackEventTransceiver: function(window) { - // Add event.transceiver member over deprecated event.receiver - if (typeof window === 'object' && window.RTCPeerConnection && - ('receiver' in window.RTCTrackEvent.prototype) && - // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is - // defined for some reason even when window.RTCTransceiver is not. - !window.RTCTransceiver) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimCreateOfferLegacy: function(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { - var pc = this; - if (offerOptions) { - var audioTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && - !audioTransceiver) { - pc.addTransceiver('audio'); - } - - var videoTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - videoTransceiver.setDirection('sendonly'); - } else if (videoTransceiver.direction === 'recvonly') { - videoTransceiver.setDirection('inactive'); - } - } else if (offerOptions.offerToReceiveVideo === true && - !videoTransceiver) { - pc.addTransceiver('video'); - } - } - return origCreateOffer.apply(pc, arguments); - }; - } -}; - -},{"../utils":13}],13:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object. -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function(e) { - cb(wrapper(e)); - }; - this._eventMap = this._eventMap || {}; - this._eventMap[cb] = wrappedCallback; - return nativeAddEventListener.apply(this, [nativeEventName, - wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap - || !this._eventMap[cb]) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[cb]; - delete this._eventMap[cb]; - return nativeRemoveEventListener.apply(this, [nativeEventName, - unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function() { - return this['_on' + eventNameToWrap]; - }, - set: function(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, - this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, - this['_on' + eventNameToWrap] = cb); - } - } - }); -} - -// Utility methods. -module.exports = { - extractVersion: extractVersion, - wrapPeerConnectionEvent: wrapPeerConnectionEvent, - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - if (navigator.mozGetUserMedia) { // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -},{}]},{},[3])(3) -}); \ No newline at end of file +},{}]},{},[1])(1) +}); diff --git a/html5/verto/js/src/vendor/media-device-id.min.js b/html5/verto/js/src/vendor/media-device-id.min.js new file mode 100644 index 0000000000..16df327236 --- /dev/null +++ b/html5/verto/js/src/vendor/media-device-id.min.js @@ -0,0 +1 @@ +/* Under MIT License by Mazuh. Original source code at: https://github.com/Mazuh/media-device-id */ !function(t){var r={};function e(n){if(r[n])return r[n].exports;var o=r[n]={i:n,l:!1,exports:{}};return t[n].call(o.exports,o,o.exports,e),o.l=!0,o.exports}e.m=t,e.c=r,e.d=function(t,r,n){e.o(t,r)||Object.defineProperty(t,r,{enumerable:!0,get:n})},e.r=function(t){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(t,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(t,"__esModule",{value:!0})},e.t=function(t,r){if(1&r&&(t=e(t)),8&r)return t;if(4&r&&"object"==typeof t&&t&&t.__esModule)return t;var n=Object.create(null);if(e.r(n),Object.defineProperty(n,"default",{enumerable:!0,value:t}),2&r&&"string"!=typeof t)for(var o in t)e.d(n,o,function(r){return t[r]}.bind(null,o));return n},e.n=function(t){var r=t&&t.__esModule?function(){return t.default}:function(){return t};return e.d(r,"a",r),r},e.o=function(t,r){return Object.prototype.hasOwnProperty.call(t,r)},e.p="",e(e.s=2)}([function(t,r,e){t.exports=e(3)},function(t,r){function e(t,r,e,n,o,i,a){try{var u=t[i](a),c=u.value}catch(t){return void e(t)}u.done?r(c):Promise.resolve(c).then(n,o)}t.exports=function(t){return function(){var r=this,n=arguments;return new Promise(function(o,i){var a=t.apply(r,n);function u(t){e(a,o,i,u,c,"next",t)}function c(t){e(a,o,i,u,c,"throw",t)}u(void 0)})}}},function(t,r,e){"use strict";e.r(r),e.d(r,"assureMediaInputId",function(){return u});var n=e(0),o=e.n(n),i=e(1),a=e.n(i);function u(t,r,e){return c.apply(this,arguments)}function c(){return(c=a()(o.a.mark(function t(r,e,n){var i,a,u,c,f,s,l,h,p,v,d;return o.a.wrap(function(t){for(;;)switch(t.prev=t.next){case 0:return i=function(t){return t.kind.indexOf("input")>-1},t.next=3,navigator.mediaDevices.enumerateDevices().then(function(t){return{ok:t.filter(i)}}).catch(function(t){return{err:t}});case 3:if(!(a=t.sent).err){t.next=6;break}throw String(a.err);case 6:if(u=a.ok,c=function(t){return t&&t.label},f=u.every(c),s=function(t){return t.label&&t.label==r},l=function(t){return t.deviceId==e},h=function(t){return l(t)},p=u.find(h),v=function(t){return l(t)||s(t)},d=u.find(v),p||f){t.next=19;break}if(void 0===n){t.next=18;break}return t.abrupt("return",n);case 18:throw"Could not assure device, id is wrong and labels are unavailable";case 19:if(p||d){t.next=23;break}if(void 0===n){t.next=22;break}return t.abrupt("return",n);case 22:throw"Could not assure device, not found by label nor id";case 23:return t.abrupt("return",p?p.deviceId:d.deviceId);case 24:case"end":return t.stop()}},t,this)}))).apply(this,arguments)}void 0!==window&&(window.assureMediaInputId=u)},function(t,r,e){var n=function(){return this||"object"==typeof self&&self}()||Function("return this")(),o=n.regeneratorRuntime&&Object.getOwnPropertyNames(n).indexOf("regeneratorRuntime")>=0,i=o&&n.regeneratorRuntime;if(n.regeneratorRuntime=void 0,t.exports=e(4),o)n.regeneratorRuntime=i;else try{delete n.regeneratorRuntime}catch(t){n.regeneratorRuntime=void 0}},function(t,r){!function(r){"use strict";var e,n=Object.prototype,o=n.hasOwnProperty,i="function"==typeof Symbol?Symbol:{},a=i.iterator||"@@iterator",u=i.asyncIterator||"@@asyncIterator",c=i.toStringTag||"@@toStringTag",f="object"==typeof t,s=r.regeneratorRuntime;if(s)f&&(t.exports=s);else{(s=r.regeneratorRuntime=f?t.exports:{}).wrap=b;var l="suspendedStart",h="suspendedYield",p="executing",v="completed",d={},y={};y[a]=function(){return this};var g=Object.getPrototypeOf,m=g&&g(g(F([])));m&&m!==n&&o.call(m,a)&&(y=m);var w=O.prototype=L.prototype=Object.create(y);E.prototype=w.constructor=O,O.constructor=E,O[c]=E.displayName="GeneratorFunction",s.isGeneratorFunction=function(t){var r="function"==typeof t&&t.constructor;return!!r&&(r===E||"GeneratorFunction"===(r.displayName||r.name))},s.mark=function(t){return Object.setPrototypeOf?Object.setPrototypeOf(t,O):(t.__proto__=O,c in t||(t[c]="GeneratorFunction")),t.prototype=Object.create(w),t},s.awrap=function(t){return{__await:t}},j(_.prototype),_.prototype[u]=function(){return this},s.AsyncIterator=_,s.async=function(t,r,e,n){var o=new _(b(t,r,e,n));return s.isGeneratorFunction(r)?o:o.next().then(function(t){return t.done?t.value:o.next()})},j(w),w[c]="Generator",w[a]=function(){return this},w.toString=function(){return"[object Generator]"},s.keys=function(t){var r=[];for(var e in t)r.push(e);return r.reverse(),function e(){for(;r.length;){var n=r.pop();if(n in t)return e.value=n,e.done=!1,e}return e.done=!0,e}},s.values=F,N.prototype={constructor:N,reset:function(t){if(this.prev=0,this.next=0,this.sent=this._sent=e,this.done=!1,this.delegate=null,this.method="next",this.arg=e,this.tryEntries.forEach(I),!t)for(var r in this)"t"===r.charAt(0)&&o.call(this,r)&&!isNaN(+r.slice(1))&&(this[r]=e)},stop:function(){this.done=!0;var t=this.tryEntries[0].completion;if("throw"===t.type)throw t.arg;return this.rval},dispatchException:function(t){if(this.done)throw t;var r=this;function n(n,o){return u.type="throw",u.arg=t,r.next=n,o&&(r.method="next",r.arg=e),!!o}for(var i=this.tryEntries.length-1;i>=0;--i){var a=this.tryEntries[i],u=a.completion;if("root"===a.tryLoc)return n("end");if(a.tryLoc<=this.prev){var c=o.call(a,"catchLoc"),f=o.call(a,"finallyLoc");if(c&&f){if(this.prev=0;--e){var n=this.tryEntries[e];if(n.tryLoc<=this.prev&&o.call(n,"finallyLoc")&&this.prev=0;--r){var e=this.tryEntries[r];if(e.finallyLoc===t)return this.complete(e.completion,e.afterLoc),I(e),d}},catch:function(t){for(var r=this.tryEntries.length-1;r>=0;--r){var e=this.tryEntries[r];if(e.tryLoc===t){var n=e.completion;if("throw"===n.type){var o=n.arg;I(e)}return o}}throw new Error("illegal catch attempt")},delegateYield:function(t,r,n){return this.delegate={iterator:F(t),resultName:r,nextLoc:n},"next"===this.method&&(this.arg=e),d}}}function b(t,r,e,n){var o=r&&r.prototype instanceof L?r:L,i=Object.create(o.prototype),a=new N(n||[]);return i._invoke=function(t,r,e){var n=l;return function(o,i){if(n===p)throw new Error("Generator is already running");if(n===v){if("throw"===o)throw i;return R()}for(e.method=o,e.arg=i;;){var a=e.delegate;if(a){var u=k(a,e);if(u){if(u===d)continue;return u}}if("next"===e.method)e.sent=e._sent=e.arg;else if("throw"===e.method){if(n===l)throw n=v,e.arg;e.dispatchException(e.arg)}else"return"===e.method&&e.abrupt("return",e.arg);n=p;var c=x(t,r,e);if("normal"===c.type){if(n=e.done?v:h,c.arg===d)continue;return{value:c.arg,done:e.done}}"throw"===c.type&&(n=v,e.method="throw",e.arg=c.arg)}}}(t,e,a),i}function x(t,r,e){try{return{type:"normal",arg:t.call(r,e)}}catch(t){return{type:"throw",arg:t}}}function L(){}function E(){}function O(){}function j(t){["next","throw","return"].forEach(function(r){t[r]=function(t){return this._invoke(r,t)}})}function _(t){var r;this._invoke=function(e,n){function i(){return new Promise(function(r,i){!function r(e,n,i,a){var u=x(t[e],t,n);if("throw"!==u.type){var c=u.arg,f=c.value;return f&&"object"==typeof f&&o.call(f,"__await")?Promise.resolve(f.__await).then(function(t){r("next",t,i,a)},function(t){r("throw",t,i,a)}):Promise.resolve(f).then(function(t){c.value=t,i(c)},function(t){return r("throw",t,i,a)})}a(u.arg)}(e,n,r,i)})}return r=r?r.then(i,i):i()}}function k(t,r){var n=t.iterator[r.method];if(n===e){if(r.delegate=null,"throw"===r.method){if(t.iterator.return&&(r.method="return",r.arg=e,k(t,r),"throw"===r.method))return d;r.method="throw",r.arg=new TypeError("The iterator does not provide a 'throw' method")}return d}var o=x(n,t.iterator,r.arg);if("throw"===o.type)return r.method="throw",r.arg=o.arg,r.delegate=null,d;var i=o.arg;return i?i.done?(r[t.resultName]=i.value,r.next=t.nextLoc,"return"!==r.method&&(r.method="next",r.arg=e),r.delegate=null,d):i:(r.method="throw",r.arg=new TypeError("iterator result is not an object"),r.delegate=null,d)}function P(t){var r={tryLoc:t[0]};1 in t&&(r.catchLoc=t[1]),2 in t&&(r.finallyLoc=t[2],r.afterLoc=t[3]),this.tryEntries.push(r)}function I(t){var r=t.completion||{};r.type="normal",delete r.arg,t.completion=r}function N(t){this.tryEntries=[{tryLoc:"root"}],t.forEach(P,this),this.reset(!0)}function F(t){if(t){var r=t[a];if(r)return r.call(t);if("function"==typeof t.next)return t;if(!isNaN(t.length)){var n=-1,i=function r(){for(;++n - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.FSRTC.js - WebRTC Glue code - * - */ -(function($) { - - // Find the line in sdpLines that starts with |prefix|, and, if specified, - // contains |substr| (case-insensitive search). - function findLine(sdpLines, prefix, substr) { - return findLineInRange(sdpLines, 0, -1, prefix, substr); - } - - // Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| - // and, if specified, contains |substr| (case-insensitive search). - function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { - var realEndLine = (endLine != -1) ? endLine : sdpLines.length; - for (var i = startLine; i < realEndLine; ++i) { - if (sdpLines[i].indexOf(prefix) === 0) { - if (!substr || sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { - return i; - } - } - } - return null; - } - - // Gets the codec payload type from an a=rtpmap:X line. - function getCodecPayloadType(sdpLine) { - var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); - var result = sdpLine.match(pattern); - return (result && result.length == 2) ? result[1] : null; - } - - // Returns a new m= line with the specified codec as the first one. - function setDefaultCodec(mLine, payload) { - var elements = mLine.split(' '); - var newLine = []; - var index = 0; - for (var i = 0; i < elements.length; i++) { - if (index === 3) { // Format of media starts from the fourth. - newLine[index++] = payload; // Put target payload to the first. - } - if (elements[i] !== payload) newLine[index++] = elements[i]; - } - return newLine.join(' '); - } - - $.FSRTC = function(options) { - this.options = $.extend({ - useVideo: null, - useStereo: false, - userData: null, - localVideo: null, - screenShare: false, - useCamera: "any", - iceServers: false, - videoParams: {}, - audioParams: {}, - callbacks: { - onICEComplete: function() {}, - onICE: function() {}, - onOfferSDP: function() {} - }, - useStream: null, - }, options); - - this.audioEnabled = true; - this.videoEnabled = true; - - - this.mediaData = { - SDP: null, - profile: {}, - candidateList: [] - }; - - this.constraints = { - offerToReceiveAudio: this.options.useSpeak === "none" ? false : true, - offerToReceiveVideo: this.options.useVideo ? true : false, - }; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - - setCompat(); - checkCompat(); - }; - - $.FSRTC.validRes = []; - - $.FSRTC.prototype.useVideo = function(obj, local) { - var self = this; - - if (obj) { - self.options.useVideo = obj; - self.options.localVideo = local; - self.constraints.offerToReceiveVideo = true; - } else { - self.options.useVideo = null; - self.options.localVideo = null; - self.constraints.offerToReceiveVideo = false; - } - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - }; - - $.FSRTC.prototype.useStereo = function(on) { - var self = this; - self.options.useStereo = on; - }; - - // Sets Opus in stereo if stereo is enabled, by adding the stereo=1 fmtp param. - $.FSRTC.prototype.stereoHack = function(sdp) { - var self = this; - - if (!self.options.useStereo) { - return sdp; - } - - var sdpLines = sdp.split('\r\n'); - - // Find opus payload. - var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'), opusPayload; - - if (!opusIndex) { - return sdp; - } else { - opusPayload = getCodecPayloadType(sdpLines[opusIndex]); - } - - // Find the payload in fmtp line. - var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString()); - - if (fmtpLineIndex === null) { - // create an fmtp line - sdpLines[opusIndex] = sdpLines[opusIndex] + '\r\na=fmtp:' + opusPayload.toString() + " stereo=1; sprop-stereo=1" - } else { - // Append stereo=1 to fmtp line. - sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1; sprop-stereo=1'); - } - - sdp = sdpLines.join('\r\n'); - return sdp; - }; - - function setCompat() { - } - - function checkCompat() { - return true; - } - - function onStreamError(self, e) { - console.log('There has been a problem retrieving the streams - did you allow access? Check Device Resolution', e); - doCallback(self, "onError", e); - } - - function onStreamSuccess(self, stream) { - console.log("Stream Success"); - doCallback(self, "onStream", stream); - } - - function onRemoteStreamSuccess(self, stream) { - console.log("Remote Stream Success"); - doCallback(self, "onRemoteStream", stream); - } - - function onICE(self, candidate) { - self.mediaData.candidate = candidate; - self.mediaData.candidateList.push(self.mediaData.candidate); - - doCallback(self, "onICE"); - } - - function doCallback(self, func, arg) { - if (func in self.options.callbacks) { - self.options.callbacks[func](self, arg); - } - } - - function onICEComplete(self, candidate) { - console.log("ICE Complete"); - doCallback(self, "onICEComplete"); - } - - function onChannelError(self, e) { - console.error("Channel Error", e); - doCallback(self, "onError", e); - } - - function onICESDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("ICE SDP"); - doCallback(self, "onICESDP"); - } - - function onAnswerSDP(self, sdp) { - self.answer.SDP = self.stereoHack(sdp.sdp); - console.log("ICE ANSWER SDP"); - doCallback(self, "onAnswerSDP", self.answer.SDP); - } - - function onMessage(self, msg) { - console.log("Message"); - doCallback(self, "onICESDP", msg); - } - - FSRTCattachMediaStream = function(element, stream) { - if (typeof element.srcObject !== 'undefined') { - element.srcObject = stream; - } else { - console.error('Error attaching stream to element.'); - } - } - - function onRemoteStream(self, stream) { - if (self.options.useVideo) { - self.options.useVideo.style.display = 'block'; - - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - - if (iOS) { - self.options.useVideo.setAttribute("playsinline", true); - } - } - - var element = self.options.useAudio; - console.log("REMOTE STREAM", stream, element); - - FSRTCattachMediaStream(element, stream); - - - - //self.options.useAudio.play(); - self.remoteStream = stream; - onRemoteStreamSuccess(self, stream); - } - - function onOfferSDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("Offer SDP"); - doCallback(self, "onOfferSDP"); - } - - $.FSRTC.prototype.answer = function(sdp, onSuccess, onError) { - this.peer.addAnswerSDP({ - type: "answer", - sdp: sdp - }, - onSuccess, onError); - }; - - $.FSRTC.prototype.stopPeer = function() { - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - } - - $.FSRTC.prototype.stop = function() { - var self = this; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - self.options.useVideo['src'] = ''; - } - - if (self.localStream && !self.options.useStream) { - if(typeof self.localStream.stop == 'function') { - self.localStream.stop(); - } else { - if (self.localStream.active){ - var tracks = self.localStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - self.localStream = null; - } - - if (self.options.localVideo) { - deactivateLocalVideo(self.options.localVideo); - } - - if (self.options.localVideoStream && !self.options.useStream) { - if(typeof self.options.localVideoStream.stop == 'function') { - self.options.localVideoStream.stop(); - } else { - if (self.options.localVideoStream.active){ - var tracks = self.options.localVideoStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - } - - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - }; - - $.FSRTC.prototype.getMute = function() { - var self = this; - return self.audioEnabled; - } - - $.FSRTC.prototype.setMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var audioTracks = self.localStream.getAudioTracks(); - - for (var i = 0, len = audioTracks.length; i < len; i++ ) { - switch(what) { - case "on": - audioTracks[i].enabled = true; - break; - case "off": - audioTracks[i].enabled = false; - break; - case "toggle": - audioTracks[i].enabled = !audioTracks[i].enabled; - default: - break; - } - - self.audioEnabled = audioTracks[i].enabled; - } - - return !self.audioEnabled; - } - - $.FSRTC.prototype.getVideoMute = function() { - var self = this; - return self.videoEnabled; - } - - $.FSRTC.prototype.setVideoMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var videoTracks = self.localStream.getVideoTracks(); - - for (var i = 0, len = videoTracks.length; i < len; i++ ) { - switch(what) { - case "on": - videoTracks[i].enabled = true; - break; - case "off": - videoTracks[i].enabled = false; - break; - case "toggle": - videoTracks[i].enabled = !videoTracks[i].enabled; - default: - break; - } - - self.videoEnabled = videoTracks[i].enabled; - } - - return !self.videoEnabled; - } - - $.FSRTC.prototype.createAnswer = function(params) { - var self = this; - self.type = "answer"; - self.remoteSDP = params.sdp; - console.debug("inbound sdp: ", params.sdp); - - function onSuccess(stream) { - self.localStream = stream; - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: function(stream) { - return onRemoteStream(self, stream); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - offerSDP: { - type: "offer", - sdp: self.remoteSDP - }, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useVideo && self.options.localVideo && !self.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: params.useCamera }, - }, - localVideo: self.options.localVideo, - onsuccess: function(e) {self.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else { - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - } - - }; - - function getMediaParams(obj) { - - var audio; - - if (obj.options.useMic && obj.options.useMic === "none") { - console.log("Microphone Disabled"); - audio = false; - } else if (obj.options.videoParams && obj.options.screenShare) {//obj.options.videoParams.chromeMediaSource == 'desktop') { - console.error("SCREEN SHARE", obj.options.videoParams); - audio = false; - } else { - audio = { - }; - - if (obj.options.audioParams) { - audio = obj.options.audioParams; - } - - if (obj.options.useMic !== "any") { - //audio.optional = [{sourceId: obj.options.useMic}]; - audio.deviceId = {exact: obj.options.useMic}; - } - } - - if (obj.options.useVideo && obj.options.localVideo && !obj.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: obj.options.useCamera }, - }, - localVideo: obj.options.localVideo, - onsuccess: function(e) {obj.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - var video = {}; - var bestFrameRate = obj.options.videoParams.vertoBestFrameRate; - var minFrameRate = obj.options.videoParams.minFrameRate || 15; - delete obj.options.videoParams.vertoBestFrameRate; - - if (obj.options.screenShare) { - if (!obj.options.useCamera && !!navigator.mozGetUserMedia) { - //This is an issue, only FireFox needs to ask this additional question if its screen or window we need a better way - var dowin = window.confirm("Do you want to share an application window? If not you can share an entire screen."); - - video = { - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight}, - mediaSource: dowin ? "window" : "screen" - } - } else { - var opt = []; - if (obj.options.useCamera) { - opt.push({sourceId: obj.options.useCamera}); - } - - if (bestFrameRate) { - opt.push({minFrameRate: bestFrameRate}); - opt.push({maxFrameRate: bestFrameRate}); - } - - video = { - mandatory: obj.options.videoParams, - optional: opt - }; - // NOTE: This is a workaround for - // https://bugs.chromium.org/p/chromium/issues/detail?id=862325 - if (!!navigator.userAgent.match(/Android/i)) { - delete video.frameRate.min; - } - } - } else { - - video = { - //mandatory: obj.options.videoParams, - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight} - }; - - - - var useVideo = obj.options.useVideo; - - if (useVideo && obj.options.useCamera && obj.options.useCamera !== "none") { - //if (!video.optional) { - //video.optional = []; - //} - - - if (obj.options.useCamera !== "any") { - //video.optional.push({sourceId: obj.options.useCamera}); - video.deviceId = { - exact: obj.options.useCamera, - }; - } - - if (bestFrameRate) { - //video.optional.push({minFrameRate: bestFrameRate}); - //video.optional.push({maxFrameRate: bestFrameRate}); - video.frameRate = {ideal: bestFrameRate, min: minFrameRate, max: 30}; - } - - } else { - console.log("Camera Disabled"); - video = false; - useVideo = false; - } - } - - return {audio: audio, video: video, useVideo: useVideo}; - } - - $.FSRTC.prototype.call = function(profile) { - checkCompat(); - - var self = this; - var screen = false; - - self.type = "offer"; - - if (self.options.videoParams && self.options.screenShare) { //self.options.videoParams.chromeMediaSource == 'desktop') { - screen = true; - } - - function onSuccess(stream) { - self.localStream = stream; - - if (screen) { - self.constraints.offerToReceiveVideo = false; - self.constraints.offerToReceiveAudio = false; - self.constraints.offerToSendAudio = false; - } - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: screen ? function(stream) {} : function(stream) { - return onRemoteStream(self, stream); - }, - onOfferSDP: function(sdp) { - return onOfferSDP(self, sdp); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else if (mediaParams.audio || mediaParams.video) { - - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - - } else { - onSuccess(null); - } - - - - /* - navigator.getUserMedia({ - video: self.options.useVideo, - audio: true - }, onSuccess, onError); - */ - - }; - - // DERIVED from RTCPeerConnection-v1.5 - // 2013, @muazkh - github.com/muaz-khan - // MIT License - https://www.webrtc-experiment.com/licence/ - // Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection - - function FSRTCPeerConnection(options) { - var gathering = false, done = false; - var config = {}; - var default_ice = [{ urls: ['stun:stun.l.google.com:19302'] }]; - - if (self.options.turnServer) { - default_ice.push(self.options.turnServer) - } - - if (options.iceServers) { - if (typeof(options.iceServers) === "boolean") { - config.iceServers = default_ice; - } else { - config.iceServers = options.iceServers; - } - } - - config.bundlePolicy = "max-compat"; - - var peer = new window.RTCPeerConnection(config); - - openOffererChannel(); - var x = 0; - - function ice_handler() { - - done = true; - gathering = null; - - if (options.onICEComplete) { - options.onICEComplete(); - } - - if (options.type == "offer") { - options.onICESDP(peer.localDescription); - } else { - if (!x && options.onICESDP) { - options.onICESDP(peer.localDescription); - } - } - } - - peer.onicecandidate = function(event) { - - if (done) { - return; - } - - if (!gathering) { - gathering = setTimeout(ice_handler, 1000); - } - - if (event) { - if (event.candidate) { - options.onICE(event.candidate); - } - } else { - done = true; - - if (gathering) { - clearTimeout(gathering); - gathering = null; - } - - ice_handler(); - } - }; - - // attachStream = MediaStream; - if (options.attachStream) peer.addStream(options.attachStream); - - // attachStreams[0] = audio-stream; - // attachStreams[1] = video-stream; - // attachStreams[2] = screen-capturing-stream; - if (options.attachStreams && options.attachStream.length) { - var streams = options.attachStreams; - for (var i = 0; i < streams.length; i++) { - peer.addStream(streams[i]); - } - } - - peer.onaddstream = function(event) { - var remoteMediaStream = event.stream; - - // onRemoteStreamEnded(MediaStream) - remoteMediaStream.oninactive = function () { - if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream); - }; - - // onRemoteStream(MediaStream) - if (options.onRemoteStream) options.onRemoteStream(remoteMediaStream); - - //console.debug('on:add:stream', remoteMediaStream); - }; - - //var constraints = options.constraints || { - // offerToReceiveAudio: true, - //offerToReceiveVideo: true - //}; - - // onOfferSDP(RTCSessionDescription) - function createOffer() { - if (!options.onOfferSDP) return; - - peer.createOffer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - options.onOfferSDP(sessionDescription); - }, - onSdpError, options.constraints); - } - - // onAnswerSDP(RTCSessionDescription) - function createAnswer() { - if (options.type != "answer") return; - - //options.offerSDP.sdp = addStereo(options.offerSDP.sdp); - peer.setRemoteDescription(new window.RTCSessionDescription(options.offerSDP), onSdpSuccess, onSdpError); - peer.createAnswer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onAnswerSDP) { - options.onAnswerSDP(sessionDescription); - } - }, - onSdpError); - } - - - if ((options.onChannelMessage) || !options.onChannelMessage) { - createOffer(); - createAnswer(); - } - - // DataChannel Bandwidth - function setBandwidth(sdp) { - // remove existing bandwidth lines - sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); - sdp = sdp.replace(/a=mid:data\r\n/g, 'a=mid:data\r\nb=AS:1638400\r\n'); - - return sdp; - } - - // old: FF<>Chrome interoperability management - function getInteropSDP(sdp) { - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), - extractedChars = ''; - - function getChars() { - extractedChars += chars[parseInt(Math.random() * 40)] || ''; - if (extractedChars.length < 40) getChars(); - - return extractedChars; - } - - // usually audio-only streaming failure occurs out of audio-specific crypto line - // a=crypto:1 AES_CM_128_HMAC_SHA1_32 --------- kAttributeCryptoVoice - if (options.onAnswerSDP) sdp = sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g, ''); - - // video-specific crypto line i.e. SHA1_80 - // a=crypto:1 AES_CM_128_HMAC_SHA1_80 --------- kAttributeCryptoVideo - var inline = getChars() + '\r\n' + (extractedChars = ''); - sdp = sdp.indexOf('a=crypto') == -1 ? sdp.replace(/c=IN/g, 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:' + inline + 'c=IN') : sdp; - - return sdp; - } - - function serializeSdp(sdp) { - return sdp; - } - - // DataChannel management - var channel; - - function openOffererChannel() { - if (!options.onChannelMessage) return; - - _openOffererChannel(); - - return; - } - - function _openOffererChannel() { - channel = peer.createDataChannel(options.channel || 'RTCDataChannel', { - reliable: false - }); - - setChannelEvents(); - } - - function setChannelEvents() { - channel.onmessage = function(event) { - if (options.onChannelMessage) options.onChannelMessage(event); - }; - - channel.onopen = function() { - if (options.onChannelOpened) options.onChannelOpened(channel); - }; - channel.onclose = function(event) { - if (options.onChannelClosed) options.onChannelClosed(event); - - console.warn('WebRTC DataChannel closed', event); - }; - channel.onerror = function(event) { - if (options.onChannelError) options.onChannelError(event); - - console.error('WebRTC DataChannel error', event); - }; - } - - function openAnswererChannel() { - peer.ondatachannel = function(event) { - channel = event.channel; - channel.binaryType = 'blob'; - setChannelEvents(); - }; - - return; - } - - // fake:true is also available on chrome under a flag! - function useless() { - log('Error in fake:true'); - } - - function onSdpSuccess() {} - - function onSdpError(e) { - if (options.onChannelError) { - options.onChannelError(e); - } - console.error('sdp error:', e); - } - - return { - addAnswerSDP: function(sdp, cbSuccess, cbError) { - - peer.setRemoteDescription(new window.RTCSessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError); - }, - addICE: function(candidate) { - peer.addIceCandidate(new window.RTCIceCandidate({ - sdpMLineIndex: candidate.sdpMLineIndex, - candidate: candidate.candidate - })); - }, - - peer: peer, - channel: channel, - sendData: function(message) { - if (channel) { - channel.send(message); - } - }, - - stop: function() { - peer.close(); - if (options.attachStream) { - if(typeof options.attachStream.stop == 'function') { - options.attachStream.stop(); - } else { - options.attachStream.active = false; - } - } - } - - }; - } - - // getUserMedia - var video_constraints = { - //mandatory: {}, - //optional: [] - }; - - function activateLocalVideo(el, stream) { - el.srcObject = stream; - el.style.display = 'block'; - } - - function deactivateLocalVideo(el) { - el.srcObject = null; - el.style.display = 'none'; - } - - function getUserMedia(options) { - var n = navigator, - media; - n.getMedia = n.getUserMedia; - n.getMedia(options.constraints || { - audio: true, - video: video_constraints - }, - streaming, options.onerror || - function(e) { - console.error(e); - }); - - function streaming(stream) { - if (options.localVideo) { - activateLocalVideo(options.localVideo, stream); - } - - if (options.onsuccess) { - options.onsuccess(stream); - } - - media = stream; - } - - return media; - } - - $.FSRTC.resSupported = function(w, h) { - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] == w && $.FSRTC.validRes[i][1] == h) { - return true; - } - } - - return false; - } - - $.FSRTC.bestResSupported = function() { - var w = 0, h = 0; - - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] >= w && $.FSRTC.validRes[i][1] >= h) { - w = $.FSRTC.validRes[i][0]; - h = $.FSRTC.validRes[i][1]; - } - } - - return [w, h]; - } - - var resList = [[160, 120], [320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; - var resI = 0; - var ttl = 0; - - var checkRes = function (cam, func) { - - if (resI >= resList.length) { - var res = { - 'validRes': $.FSRTC.validRes, - 'bestResSupported': $.FSRTC.bestResSupported() - }; - - localStorage.setItem("res_" + cam, $.toJSON(res)); - - if (func) return func(res); - return; - } - - w = resList[resI][0]; - h = resList[resI][1]; - resI++; - - var video = { - width: {exact: w}, - height: {exact: h} - }; - - if (cam !== "any") { - video.deviceId = { - exact: cam, - }; - } - - getUserMedia({ - constraints: { - audio: ttl++ == 0, - video: video - }, - onsuccess: function(e) { - e.getTracks().forEach(function(track) {track.stop();}); - console.info(w + "x" + h + " supported."); $.FSRTC.validRes.push([w, h]); checkRes(cam, func);}, - onerror: function(e) {console.warn( w + "x" + h + " not supported."); checkRes(cam, func);} - }); - } - - - $.FSRTC.getValidRes = function (cam, func) { - var used = []; - var cached = localStorage.getItem("res_" + cam); - - if (cached) { - var cache = $.parseJSON(cached); - - if (cache) { - $.FSRTC.validRes = cache.validRes; - console.log("CACHED RES FOR CAM " + cam, cache); - } else { - console.error("INVALID CACHE"); - } - return func ? func(cache) : null; - } - - - $.FSRTC.validRes = []; - resI = 0; - - checkRes(cam, func); - } - - $.FSRTC.checkPerms = function (runtime, check_audio, check_video) { - getUserMedia({ - constraints: { - audio: check_audio, - video: check_video, - }, - onsuccess: function(e) { - - e.getTracks().forEach(function(track) {track.stop();}); - - console.info("media perm init complete"); - if (runtime) { - setTimeout(runtime, 100, true); - } - }, - onerror: function(e) { - if (check_video && check_audio) { - console.error("error, retesting with audio params only"); - return $.FSRTC.checkPerms(runtime, check_audio, false); - } - - console.error("media perm init error"); - - if (runtime) { - runtime(false) - } - } - }); - } - -})(jQuery); -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Textalk AB http://textalk.se/ - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.jsonrpclient.js - JSON RPC client code - * - */ -/** - * This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and - * $.parseJSON. - * - * The plan is to make use of websockets if they are available, but work just as well with only - * http if not. - * - * Usage example: - * - * var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' }); - * foo.call( - * 'bar', [ 'A parameter', 'B parameter' ], - * function(result) { alert('Foo bar answered: ' + result.my_answer); }, - * function(error) { console.log('There was an error', error); } - * ); - * - * More examples are available in README.md - */ -(function($) { - /** - * @fn new - * @memberof $.JsonRpcClient - * - * @param options An object stating the backends: - * ajaxUrl A url (relative or absolute) to a http(s) backend. - * socketUrl A url (relative of absolute) to a ws(s) backend. - * onmessage A socket message handler for other messages (non-responses). - * getSocket A function returning a WebSocket or null. - * It must take an onmessage_cb and bind it to the onmessage event - * (or chain it before/after some other onmessage handler). - * Or, it could return null if no socket is available. - * The returned instance must have readyState <= 1, and if less than 1, - * react to onopen binding. - */ - $.JsonRpcClient = function(options) { - var self = this; - this.options = $.extend({ - ajaxUrl : null, - socketUrl : null, ///< The ws-url for default getSocket. - onmessage : null, ///< Other onmessage-handler. - login : null, /// auth login - passwd : null, /// auth passwd - sessid : null, - loginParams : null, - userVariables : null, - getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } - }, options); - - self.ws_cnt = 0; - - // Declare an instance version of the onmessage callback to wrap 'this'. - this.wsOnMessage = function(event) { self._wsOnMessage(event); }; - }; - - /// Holding the WebSocket on default getsocket. - $.JsonRpcClient.prototype._ws_socket = null; - - /// Object : { success_cb: cb, error_cb: cb } - $.JsonRpcClient.prototype._ws_callbacks = {}; - - /// The next JSON-RPC request id. - $.JsonRpcClient.prototype._current_id = 1; - - - $.JsonRpcClient.prototype.speedTest = function (bytes, cb) { - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this.speedCB = cb; - this.speedBytes = bytes; - socket.send("#SPU " + bytes); - - var loops = bytes / 1024; - var rem = bytes % 1024; - var i; - var data = new Array(1024).join("."); - for (i = 0; i < loops; i++) { - socket.send("#SPB " + data); - } - - if (rem) { - socket.send("#SPB " + data); - } - - socket.send("#SPE"); - } - }; - - - - /** - * @fn call - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - * @param success_cb A callback for successful request. - * @param error_cb A callback for error. - */ - $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { - // Construct the JSON-RPC 2.0 request. - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc : '2.0', - method : method, - params : params, - id : this._current_id++ // Increase the id counter to match request/response - }; - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request, success_cb, error_cb); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false, - - success : function(data) { - if ('error' in data) error_cb(data.error, this); - success_cb(data.result, this); - }, - - // JSON-RPC Server could return non-200 on error - error : function(jqXHR, textStatus, errorThrown) { - try { - var response = $.parseJSON(jqXHR.responseText); - - if ('console' in window) console.log(response); - - error_cb(response.error, this); - } catch (err) { - // Perhaps the responseText wasn't really a jsonrpc-error. - error_cb({ error: jqXHR.responseText }, this); - } - } - }); - }; - - /** - * Notify sends a command to the server that won't need a response. In http, there is probably - * an empty response - that will be dropped, but in ws there should be no response at all. - * - * This is very similar to call, but has no id and no handling of callbacks. - * - * @fn notify - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - */ - $.JsonRpcClient.prototype.notify = function(method, params) { - // Construct the JSON-RPC 2.0 request. - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc: '2.0', - method: method, - params: params - }; - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false - }); - }; - - /** - * Make a batch-call by using a callback. - * - * The callback will get an object "batch" as only argument. On batch, you can call the methods - * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be - * sent as a batch call then the callback is done. - * - * @fn batch - * @memberof $.JsonRpcClient - * - * @param callback The main function which will get a batch handler to run call and notify on. - * @param all_done_cb A callback function to call after all results have been handled. - * @param error_cb A callback function to call if there is an error from the server. - * Note, that batch calls should always get an overall success, and the - * only error - */ - $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { - var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); - callback(batch); - batch._execute(); - }; - - /** - * The default getSocket handler. - * - * @param onmessage_cb The callback to be bound to onmessage events on the socket. - * - * @fn _getSocket - * @memberof $.JsonRpcClient - */ - - $.JsonRpcClient.prototype.socketReady = function() { - if (this._ws_socket === null || this._ws_socket.readyState > 1) { - return false; - } - - return true; - }; - - $.JsonRpcClient.prototype.closeSocket = function() { - var self = this; - if (self.socketReady()) { - self._ws_socket.onclose = function (w) {console.log("Closing Socket");}; - self._ws_socket.close(); - } - }; - - $.JsonRpcClient.prototype.loginData = function(params) { - var self = this; - self.options.login = params.login; - self.options.passwd = params.passwd; - self.options.loginParams = params.loginParams; - self.options.userVariables = params.userVariables; - }; - - $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { - var self = this; - - if (self.to) { - clearTimeout(self.to); - } - - if (!self.socketReady()) { - self.authing = false; - - if (self._ws_socket) { - delete self._ws_socket; - } - - // No socket, or dying socket, let's get a new one. - self._ws_socket = new WebSocket(self.options.socketUrl); - - if (self._ws_socket) { - // Set up onmessage handler. - self._ws_socket.onmessage = onmessage_cb; - self._ws_socket.onclose = function (w) { - if (!self.ws_sleep) { - self.ws_sleep = 1000; - } - - if (self.options.onWSClose) { - self.options.onWSClose(self); - } - - if (self.ws_cnt > 10 && self.options.wsFallbackURL) { - self.options.socketUrl = self.options.wsFallbackURL; - } - - console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); - - self.to = setTimeout(function() { - console.log("Attempting Reconnection...."); - self.connectSocket(onmessage_cb); - }, self.ws_sleep); - - self.ws_cnt++; - - if (self.ws_sleep < 3000 && (self.ws_cnt % 10) === 0) { - self.ws_sleep += 1000; - } - }; - - // Set up sending of message for when the socket is open. - self._ws_socket.onopen = function() { - if (self.to) { - clearTimeout(self.to); - } - self.ws_sleep = 1000; - self.ws_cnt = 0; - if (self.options.onWSConnect) { - self.options.onWSConnect(self); - } - - var req; - // Send the requests. - while ((req = $.JsonRpcClient.q.pop())) { - self._ws_socket.send(req); - } - }; - } - } - - return self._ws_socket ? true : false; - }; - - $.JsonRpcClient.prototype.stopRetrying = function() { - if (self.to) - clearTimeout(self.to); - } - - $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { - // If there is no ws url set, we don't have a socket. - // Likewise, if there is no window.WebSocket. - if (this.options.socketUrl === null || !("WebSocket" in window)) return null; - - this.connectSocket(onmessage_cb); - - return this._ws_socket; - }; - - /** - * Queue to save messages delivered when websocket is not ready - */ - $.JsonRpcClient.q = []; - - /** - * Internal handler to dispatch a JRON-RPC request through a websocket. - * - * @fn _wsCall - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { - var request_json = $.toJSON(request); - - if (socket.readyState < 1) { - // The websocket is not open yet; we have to set sending of the message in onopen. - self = this; // In closure below, this is set to the WebSocket. Use self instead. - $.JsonRpcClient.q.push(request_json); - } else { - // We have a socket and it should be ready to send on. - socket.send(request_json); - } - - // Setup callbacks. If there is an id, this is a call and not a notify. - if ('id' in request && typeof success_cb !== 'undefined') { - this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; - } - }; - - /** - * Internal handler for the websocket messages. It determines if the message is a JSON-RPC - * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to - * given external onmessage-handler, if any. - * - * @param event The websocket onmessage-event. - */ - $.JsonRpcClient.prototype._wsOnMessage = function(event) { - // Check if this could be a JSON RPC message. - var response; - - // Special sub proto - if (event.data[0] == "#" && event.data[1] == "S" && event.data[2] == "P") { - if (event.data[3] == "U") { - this.up_dur = parseInt(event.data.substring(4)); - } else if (this.speedCB && event.data[3] == "D") { - this.down_dur = parseInt(event.data.substring(4)); - - var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0); - var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0); - - console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps); - var cb = this.speedCB; - this.speedCB = null; - cb(event, { - upDur: this.up_dur, - downDur: this.down_dur, - upKPS: up_kps, - downKPS: down_kps - }); - } - - return; - } - - - try { - response = $.parseJSON(event.data); - - /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. - - if (typeof response === 'object' && - 'jsonrpc' in response && - response.jsonrpc === '2.0') { - - /// @todo Handle bad response (without id). - - // If this is an object with result, it is a response. - if ('result' in response && this._ws_callbacks[response.id]) { - // Get the success callback. - var success_cb = this._ws_callbacks[response.id].success_cb; - - /* - // set the sessid if present - if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { - this.options.sessid = response.result.sessid; - if (this.options.sessid) { - console.log("setting session UUID to: " + this.options.sessid); - } - } - */ - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with result as parameter. - success_cb(response.result, this); - return; - } else if ('error' in response && this._ws_callbacks[response.id]) { - // If this is an object with error, it is an error response. - - // Get the error callback. - var error_cb = this._ws_callbacks[response.id].error_cb; - var orig_req = this._ws_callbacks[response.id].request; - - // if this is an auth request, send the credentials and resend the failed request - if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { - self.authing = true; - - this.call("login", { login: self.options.login, passwd: self.options.passwd, loginParams: self.options.loginParams, - userVariables: self.options.userVariables}, - this._ws_callbacks[response.id].request_obj.method == "login" ? - function(e) { - self.authing = false; - console.log("logged in"); - delete self._ws_callbacks[response.id]; - - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - } - - : - - function(e) { - self.authing = false; - console.log("logged in, resending request id: " + response.id); - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send(orig_req); - } - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - }, - - function(e) { - console.log("error logging in, request id:", response.id); - delete self._ws_callbacks[response.id]; - error_cb(response.error, this); - if (self.options.onWSLogin) { - self.options.onWSLogin(false, self); - } - }); - return; - } - - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with the error object as parameter. - error_cb(response.error, this); - return; - } - } - } catch (err) { - // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are - // handled above, and the fallback method is called below. - console.log("ERROR: "+ err); - return; - } - - // This is not a JSON-RPC response. Call the fallback message handler, if given. - if (typeof this.options.onmessage === 'function') { - event.eventData = response; - if (!event.eventData) { - event.eventData = {}; - } - - var reply = this.options.onmessage(event); - - if (reply && typeof reply === "object" && event.eventData.id) { - var msg = { - jsonrpc: "2.0", - id: event.eventData.id, - result: reply - }; - - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send($.toJSON(msg)); - } - } - } - }; - - - /************************************************************************************************ - * Batch object with methods - ************************************************************************************************/ - - /** - * Handling object for batch calls. - */ - $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { - // Array of objects to hold the call and notify requests. Each objects will have the request - // object, and unless it is a notify, success_cb and error_cb. - this._requests = []; - - this.jsonrpcclient = jsonrpcclient; - this.all_done_cb = all_done_cb; - this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; - - }; - - /** - * @sa $.JsonRpcClient.prototype.call - */ - $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params, - id : this.jsonrpcclient._current_id++ // Use the client's id series. - }, - success_cb : success_cb, - error_cb : error_cb - }); - }; - - /** - * @sa $.JsonRpcClient.prototype.notify - */ - $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params - } - }); - }; - - /** - * Executes the batched up calls. - */ - $.JsonRpcClient._batchObject.prototype._execute = function() { - var self = this; - - if (this._requests.length === 0) return; // All done :P - - // Collect all request data and sort handlers by request id. - var batch_request = []; - var handlers = {}; - var i = 0; - var call; - var success_cb; - var error_cb; - - // If we have a WebSocket, just send the requests individually like normal calls. - var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); - if (socket !== null) { - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - success_cb = ('success_cb' in call) ? call.success_cb : undefined; - error_cb = ('error_cb' in call) ? call.error_cb : undefined; - self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - return; - } - - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - batch_request.push(call.request); - - // If the request has an id, it should handle returns (otherwise it's a notify). - if ('id' in call.request) { - handlers[call.request.id] = { - success_cb : call.success_cb, - error_cb : call.error_cb - }; - } - } - - success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; - - // No WebSocket, and no HTTP backend? This won't work. - if (self.jsonrpcclient.options.ajaxUrl === null) { - throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; - } - - // Send request - $.ajax({ - url : self.jsonrpcclient.options.ajaxUrl, - data : $.toJSON(batch_request), - dataType : 'json', - cache : false, - type : 'POST', - - // Batch-requests should always return 200 - error : function(jqXHR, textStatus, errorThrown) { - self.error_cb(jqXHR, textStatus, errorThrown); - }, - success : success_cb - }); - }; - - /** - * Internal helper to match the result array from a batch call to their respective callbacks. - * - * @fn _batchCb - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { - for (var i = 0; i < result.length; i++) { - var response = result[i]; - - // Handle error - if ('error' in response) { - if (response.id === null || !(response.id in handlers)) { - // An error on a notify? Just log it to the console. - if ('console' in window) console.log(response); - } else { - handlers[response.id].error_cb(response.error, this); - } - } else { - // Here we should always have a correct id and no error. - if (!(response.id in handlers) && 'console' in window) { - console.log(response); - } else { - handlers[response.id].success_cb(response.result, this); - } - } - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - }; - -})(jQuery); - -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.verto.js - Main interface - * - */ - -(function($) { - var sources = []; - - var generateGUID = (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') ? - function() { - // If we have a cryptographically secure PRNG, use that - // http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript - var buf = new Uint16Array(8); - window.crypto.getRandomValues(buf); - var S4 = function(num) { - var ret = num.toString(16); - while (ret.length < 4) { - ret = "0" + ret; - } - return ret; - }; - return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7])); - } - - : - - function() { - // Otherwise, just use Math.random - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, - v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - }; - - /// MASTER OBJ - $.verto = function(options, callbacks) { - var verto = this; - - $.verto.saved.push(verto); - - verto.options = $.extend({ - login: null, - passwd: null, - socketUrl: null, - tag: null, - localTag: null, - videoParams: {}, - audioParams: {}, - loginParams: {}, - deviceParams: {onResCheck: null}, - userVariables: {}, - iceServers: false, - ringSleep: 6000, - sessid: null, - useStream: null - }, options); - - if (verto.options.deviceParams.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, verto.options.deviceParams.onResCheck); - } - - if (!verto.options.deviceParams.useMic) { - verto.options.deviceParams.useMic = "any"; - } - - if (!verto.options.deviceParams.useSpeak) { - verto.options.deviceParams.useSpeak = "any"; - } - - if (verto.options.sessid) { - verto.sessid = verto.options.sessid; - } else { - verto.sessid = localStorage.getItem("verto_session_uuid") || generateGUID(); - localStorage.setItem("verto_session_uuid", verto.sessid); - } - - verto.dialogs = {}; - verto.callbacks = callbacks || {}; - verto.eventSUBS = {}; - - verto.rpcClient = new $.JsonRpcClient({ - login: verto.options.login, - passwd: verto.options.passwd, - socketUrl: verto.options.socketUrl, - wsFallbackURL: verto.options.wsFallbackURL, - turnServer: verto.options.turnServer, - loginParams: verto.options.loginParams, - userVariables: verto.options.userVariables, - sessid: verto.sessid, - onmessage: function(e) { - return verto.handleMessage(e.eventData); - }, - onWSConnect: function(o) { - o.call('login', {}); - }, - onWSLogin: function(success) { - if (verto.callbacks.onWSLogin) { - verto.callbacks.onWSLogin(verto, success); - } - }, - onWSClose: function(success) { - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, success); - } - verto.purge(); - } - }); - - var tag = verto.options.tag; - if (typeof(tag) === "function") { - tag = tag(); - } - - if (verto.options.ringFile && verto.options.tag) { - verto.ringer = $("#" + tag); - } - - verto.rpcClient.call('login', {}); - - }; - - - $.verto.prototype.deviceParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.deviceParams[i] = obj[i]; - } - - if (obj.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, obj ? obj.onResCheck : undefined); - } - }; - - $.verto.prototype.videoParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.videoParams[i] = obj[i]; - } - }; - - $.verto.prototype.iceServers = function(obj) { - var verto = this; - verto.options.iceServers = obj; - }; - - $.verto.prototype.loginData = function(params) { - var verto = this; - verto.options.login = params.login; - verto.options.passwd = params.passwd; - verto.rpcClient.loginData(params); - }; - - $.verto.prototype.logout = function(msg) { - var verto = this; - verto.rpcClient.closeSocket(); - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, false); - } - verto.purge(); - }; - - $.verto.prototype.login = function(msg) { - var verto = this; - verto.logout(); - verto.rpcClient.call('login', {}); - }; - - $.verto.prototype.message = function(msg) { - var verto = this; - var err = 0; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - verto.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.prototype.processReply = function(method, success, e) { - var verto = this; - var i; - - //console.log("Response: " + method, success, e); - - switch (method) { - case "verto.subscribe": - for (i in e.unauthorizedChannels) { - drop_bad(verto, e.unauthorizedChannels[i]); - } - for (i in e.subscribedChannels) { - mark_ready(verto, e.subscribedChannels[i]); - } - - break; - case "verto.unsubscribe": - //console.error(e); - break; - } - }; - - $.verto.prototype.sendMethod = function(method, params) { - var verto = this; - - verto.rpcClient.call(method, params, - - function(e) { - /* Success */ - verto.processReply(method, true, e); - }, - - function(e) { - /* Error */ - verto.processReply(method, false, e); - }); - }; - - function do_sub(verto, channel, obj) { - - } - - function drop_bad(verto, channel) { - console.error("drop unauthorized channel: " + channel); - delete verto.eventSUBS[channel]; - } - - function mark_ready(verto, channel) { - for (var j in verto.eventSUBS[channel]) { - verto.eventSUBS[channel][j].ready = true; - console.log("subscribed to channel: " + channel); - if (verto.eventSUBS[channel][j].readyHandler) { - verto.eventSUBS[channel][j].readyHandler(verto, channel); - } - } - } - - var SERNO = 1; - - function do_subscribe(verto, channel, subChannels, sparams) { - var params = sparams || {}; - - var local = params.local; - - var obj = { - eventChannel: channel, - userData: params.userData, - handler: params.handler, - ready: false, - readyHandler: params.readyHandler, - serno: SERNO++ - }; - - var isnew = false; - - if (!verto.eventSUBS[channel]) { - verto.eventSUBS[channel] = []; - subChannels.push(channel); - isnew = true; - } - - verto.eventSUBS[channel].push(obj); - - if (local) { - obj.ready = true; - obj.local = true; - } - - if (!isnew && verto.eventSUBS[channel][0].ready) { - obj.ready = true; - if (obj.readyHandler) { - obj.readyHandler(verto, channel); - } - } - - return { - serno: obj.serno, - eventChannel: channel - }; - - } - - $.verto.prototype.subscribe = function(channel, sparams) { - var verto = this; - var r = []; - var subChannels = []; - var params = sparams || {}; - - if (typeof(channel) === "string") { - r.push(do_subscribe(verto, channel, subChannels, params)); - } else { - for (var i in channel) { - r.push(do_subscribe(verto, channel, subChannels, params)); - } - } - - if (subChannels.length) { - verto.sendMethod("verto.subscribe", { - eventChannel: subChannels.length == 1 ? subChannels[0] : subChannels, - subParams: params.subParams - }); - } - - return r; - }; - - $.verto.prototype.unsubscribe = function(handle) { - var verto = this; - var i; - - if (!handle) { - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - verto.unsubscribe(verto.eventSUBS[i]); - } - } - } else { - var unsubChannels = {}; - var sendChannels = []; - var channel; - - if (typeof(handle) == "string") { - delete verto.eventSUBS[handle]; - unsubChannels[handle]++; - } else { - for (i in handle) { - if (typeof(handle[i]) == "string") { - channel = handle[i]; - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } else { - var repl = []; - channel = handle[i].eventChannel; - - for (var j in verto.eventSUBS[channel]) { - if (verto.eventSUBS[channel][j].serno == handle[i].serno) {} else { - repl.push(verto.eventSUBS[channel][j]); - } - } - - verto.eventSUBS[channel] = repl; - - if (verto.eventSUBS[channel].length === 0) { - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } - } - } - } - - for (var u in unsubChannels) { - console.log("Sending Unsubscribe for: ", u); - sendChannels.push(u); - } - - if (sendChannels.length) { - verto.sendMethod("verto.unsubscribe", { - eventChannel: sendChannels.length == 1 ? sendChannels[0] : sendChannels - }); - } - } - }; - - $.verto.prototype.broadcast = function(channel, params) { - var verto = this; - var msg = { - eventChannel: channel, - data: {} - }; - for (var i in params) { - msg.data[i] = params[i]; - } - verto.sendMethod("verto.broadcast", msg); - }; - - $.verto.prototype.purge = function(callID) { - var verto = this; - var x = 0; - var i; - - for (i in verto.dialogs) { - if (!x) { - console.log("purging dialogs"); - } - x++; - verto.dialogs[i].setState($.verto.enum.state.purge); - } - - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - console.log("purging subscription: " + i); - delete verto.eventSUBS[i]; - } - } - }; - - $.verto.prototype.hangup = function(callID) { - var verto = this; - if (callID) { - var dialog = verto.dialogs[callID]; - - if (dialog) { - dialog.hangup(); - } - } else { - for (var i in verto.dialogs) { - verto.dialogs[i].hangup(); - } - } - }; - - $.verto.prototype.newCall = function(args, callbacks) { - var verto = this; - - if (!verto.rpcClient.socketReady()) { - console.error("Not Connected..."); - return; - } - - if (args["useCamera"]) { - verto.options.deviceParams["useCamera"] = args["useCamera"]; - } - - var dialog = new $.verto.dialog($.verto.enum.direction.outbound, this, args); - - if (callbacks) { - dialog.callbacks = callbacks; - } - - dialog.invite(); - - return dialog; - }; - - $.verto.prototype.handleMessage = function(data) { - var verto = this; - - if (!(data && data.method)) { - console.error("Invalid Data", data); - return; - } - - if (data.params.callID) { - var dialog = verto.dialogs[data.params.callID]; - - if (data.method === "verto.attach" && dialog) { - delete dialog.verto.dialogs[dialog.callID]; - dialog.rtc.stop(); - dialog = null; - } - - if (dialog) { - - switch (data.method) { - case 'verto.bye': - dialog.hangup(data.params); - break; - case 'verto.answer': - dialog.handleAnswer(data.params); - break; - case 'verto.media': - dialog.handleMedia(data.params); - break; - case 'verto.display': - dialog.handleDisplay(data.params); - break; - case 'verto.info': - dialog.handleInfo(data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", dialog, data.method); - break; - } - } else { - - switch (data.method) { - case 'verto.attach': - data.params.attach = true; - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.useVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - dialog.setState($.verto.enum.state.recovering); - - break; - case 'verto.invite': - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.wantVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED"); - break; - } - } - - return { - method: data.method - }; - } else { - switch (data.method) { - case 'verto.punt': - verto.purge(); - verto.logout(); - break; - case 'verto.event': - var list = null; - var key = null; - - if (data.params) { - key = data.params.eventChannel; - } - - if (key) { - list = verto.eventSUBS[key]; - - if (!list) { - list = verto.eventSUBS[key.split(".")[0]]; - } - } - - if (!list && key && key === verto.sessid) { - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); - } - } else if (!list && key && verto.dialogs[key]) { - verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params); - } else if (!list) { - if (!key) { - key = "UNDEFINED"; - } - console.error("UNSUBBED or invalid EVENT " + key + " IGNORED"); - } else { - for (var i in list) { - var sub = list[i]; - - if (!sub || !sub.ready) { - console.error("invalid EVENT for " + key + " IGNORED"); - } else if (sub.handler) { - sub.handler(verto, data.params, sub.userData); - } else if (verto.callbacks.onEvent) { - verto.callbacks.onEvent(verto, data.params, sub.userData); - } else { - console.log("EVENT:", data.params); - } - } - } - - break; - - case "verto.info": - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.info, data.params.msg); - } - //console.error(data); - console.debug("MESSAGE from: " + data.params.msg.from, data.params.msg.body); - - break; - - case 'verto.clientReady': - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.clientReady, data.params); - } - console.debug("CLIENT READY", data.params); - break; - - default: - console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method); - break; - } - } - }; - - var del_array = function(array, name) { - var r = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] != name) { - r.push(array[i]); - } - } - - return r; - }; - - var hashArray = function() { - var vha = this; - - var hash = {}; - var array = []; - - vha.reorder = function(a) { - array = a; - var h = hash; - hash = {}; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - if (h[key]) { - hash[key] = h[key]; - delete h[key]; - } - } - h = undefined; - }; - - vha.clear = function() { - hash = undefined; - array = undefined; - hash = {}; - array = []; - }; - - vha.add = function(name, val, insertAt) { - var redraw = false; - - if (!hash[name]) { - if (insertAt === undefined || insertAt < 0 || insertAt >= array.length) { - array.push(name); - } else { - var x = 0; - var n = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (x++==insertAt) { - n.push(name); - } - n.push(array[i]); - } - - array = undefined; - array = n; - n = undefined; - redraw = true; - } - } - - hash[name] = val; - - return redraw; - }; - - vha.del = function(name) { - var r = false; - - if (hash[name]) { - array = del_array(array, name); - delete hash[name]; - r = true; - } else { - console.error("can't del nonexistant key " + name); - } - - return r; - }; - - vha.get = function(name) { - return hash[name]; - }; - - vha.order = function() { - return array; - }; - - vha.hash = function() { - return hash; - }; - - vha.indexOf = function(name) { - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] == name) { - return i; - } - } - }; - - vha.arrayLen = function() { - return array.length; - }; - - vha.asArray = function() { - var r = []; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - r.push(hash[key]); - } - - return r; - }; - - vha.each = function(cb) { - var len = array.length; - - for (var i = 0; i < len; i++) { - cb(array[i], hash[array[i]]); - } - }; - - vha.dump = function(html) { - var str = ""; - - vha.each(function(name, val) { - str += "name: " + name + " val: " + JSON.stringify(val) + (html ? "
" : "\n"); - }); - - return str; - }; - - }; - - $.verto.liveArray = function(verto, context, name, config) { - var la = this; - var lastSerno = 0; - var binding = null; - var user_obj = config.userObj; - var local = false; - - // Inherit methods of hashArray - hashArray.call(la); - - // Save the hashArray add, del, reorder, clear methods so we can make our own. - la._add = la.add; - la._del = la.del; - la._reorder = la.reorder; - la._clear = la.clear; - - la.context = context; - la.name = name; - la.user_obj = user_obj; - - la.verto = verto; - la.broadcast = function(channel, obj) { - verto.broadcast(channel, obj); - }; - la.errs = 0; - - la.clear = function() { - la._clear(); - lastSerno = 0; - - if (la.onChange) { - la.onChange(la, { - action: "clear" - }); - } - }; - - la.checkSerno = function(serno) { - if (serno < 0) { - return true; - } - - if (lastSerno > 0 && serno != (lastSerno + 1)) { - if (la.onErr) { - la.onErr(la, { - lastSerno: lastSerno, - serno: serno - }); - } - la.errs++; - console.debug(la.errs); - if (la.errs < 3) { - la.bootstrap(la.user_obj); - } - return false; - } else { - lastSerno = serno; - return true; - } - }; - - la.reorder = function(serno, a) { - if (la.checkSerno(serno)) { - la._reorder(a); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "reorder" - }); - } - } - }; - - la.init = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "init", - index: index, - key: key, - data: val - }); - } - } - }; - - la.bootObj = function(serno, val) { - if (la.checkSerno(serno)) { - - //la.clear(); - for (var i in val) { - la._add(val[i][0], val[i][1]); - } - - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "bootObj", - data: val, - redraw: true - }); - } - } - }; - - // @param serno La is the serial number for la particular request. - // @param key If looking at it as a hash table, la represents the key in the hashArray object where you want to store the val object. - // @param index If looking at it as an array, la represents the position in the array where you want to store the val object. - // @param val La is the object you want to store at the key or index location in the hash table / array. - la.add = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - var redraw = la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "add", - index: index, - key: key, - data: val, - redraw: redraw - }); - } - } - }; - - la.modify = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "modify", - key: key, - data: val, - index: index - }); - } - } - }; - - la.del = function(serno, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (index === null || index < 0 || index === undefined) { - index = la.indexOf(key); - } - var ok = la._del(key); - - if (ok && la.onChange) { - la.onChange(la, { - serno: serno, - action: "del", - key: key, - index: index - }); - } - } - }; - - var eventHandler = function(v, e, la) { - var packet = e.data; - - //console.error("READ:", packet); - - if (packet.name != la.name) { - return; - } - - switch (packet.action) { - - case "init": - la.init(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "bootObj": - la.bootObj(packet.wireSerno, packet.data); - break; - case "add": - la.add(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "modify": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.modify(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - } - break; - case "del": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.del(packet.wireSerno, packet.hashKey, packet.arrIndex); - } - break; - - case "clear": - la.clear(); - break; - - case "reorder": - la.reorder(packet.wireSerno, packet.order); - break; - - default: - if (la.checkSerno(packet.wireSerno)) { - if (la.onChange) { - la.onChange(la, { - serno: packet.wireSerno, - action: packet.action, - data: packet.data - }); - } - } - break; - } - }; - - if (la.context) { - binding = la.verto.subscribe(la.context, { - handler: eventHandler, - userData: la, - subParams: config.subParams - }); - } - - la.destroy = function() { - la._clear(); - la.verto.unsubscribe(binding); - }; - - la.sendCommand = function(cmd, obj) { - var self = la; - self.broadcast(self.context, { - liveArray: { - command: cmd, - context: self.context, - name: self.name, - obj: obj - } - }); - }; - - la.bootstrap = function(obj) { - var self = la; - la.sendCommand("bootstrap", obj); - //self.heartbeat(); - }; - - la.changepage = function(obj) { - var self = la; - self.clear(); - self.broadcast(self.context, { - liveArray: { - command: "changepage", - context: la.context, - name: la.name, - obj: obj - } - }); - }; - - la.heartbeat = function(obj) { - var self = la; - - var callback = function() { - self.heartbeat.call(self, obj); - }; - self.broadcast(self.context, { - liveArray: { - command: "heartbeat", - context: self.context, - name: self.name, - obj: obj - } - }); - self.hb_pid = setTimeout(callback, 30000); - }; - - la.bootstrap(la.user_obj); - }; - - $.verto.liveTable = function(verto, context, name, jq, config) { - var dt; - var la = new $.verto.liveArray(verto, context, name, { - subParams: config.subParams - }); - var lt = this; - - lt.liveArray = la; - lt.dataTable = dt; - lt.verto = verto; - - lt.destroy = function() { - if (dt) { - dt.fnDestroy(); - } - if (la) { - la.destroy(); - } - - dt = null; - la = null; - }; - - la.onErr = function(obj, args) { - console.error("Error: ", obj, args); - }; - - /* back compat so jsonstatus can always be enabled */ - function genRow(data) { - if (typeof(data[4]) === "string" && data[4].indexOf("{") > -1) { - var tmp = $.parseJSON(data[4]); - data[4] = tmp.oldStatus; - data[5] = null; - } - return data; - } - - function genArray(obj) { - var data = obj.asArray(); - - for (var i in data) { - data[i] = genRow(data[i]); - } - - return data; - } - - - la.onChange = function(obj, args) { - var index = 0; - var iserr = 0; - - if (!dt) { - if (!config.aoColumns) { - if (args.action != "init") { - return; - } - - config.aoColumns = []; - - for (var i in args.data) { - config.aoColumns.push({ - "sTitle": args.data[i] - }); - } - } - - dt = jq.dataTable(config); - } - - if (dt && (args.action == "del" || args.action == "modify")) { - index = args.index; - - if (index === undefined && args.key) { - index = la.indexOf(args.key); - } - - if (index === undefined) { - console.error("INVALID PACKET Missing INDEX\n", args); - return; - } - } - - if (config.onChange) { - config.onChange(obj, args); - } - - try { - switch (args.action) { - case "bootObj": - if (!args.data) { - console.error("missing data"); - return; - } - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - dt.fnAdjustColumnSizing(); - break; - case "add": - if (!args.data) { - console.error("missing data"); - return; - } - if (args.redraw > -1) { - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - } else { - dt.fnAddData(genRow(args.data)); - } - dt.fnAdjustColumnSizing(); - break; - case "modify": - if (!args.data) { - return; - } - //console.debug(args, index); - dt.fnUpdate(genRow(args.data), index); - dt.fnAdjustColumnSizing(); - break; - case "del": - dt.fnDeleteRow(index); - dt.fnAdjustColumnSizing(); - break; - case "clear": - dt.fnClearTable(); - break; - case "reorder": - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - break; - case "hide": - jq.hide(); - break; - - case "show": - jq.show(); - break; - - } - } catch(err) { - console.error("ERROR: " + err); - iserr++; - } - - if (iserr) { - obj.errs++; - if (obj.errs < 3) { - obj.bootstrap(obj.user_obj); - } - } else { - obj.errs = 0; - } - - }; - - la.onChange(la, { - action: "init" - }); - - }; - - var CONFMAN_SERNO = 1; - - /* - Conference Manager without jQuery table. - */ - - $.verto.conf = function(verto, params) { - var conf = this; - - conf.params = $.extend({ - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - conf.verto = verto; - conf.serno = CONFMAN_SERNO++; - - createMainModeratorMethods(); - - verto.subscribe(conf.params.laData.modChannel, { - handler: function(v, e) { - if (conf.params.onBroadcast) { - conf.params.onBroadcast(verto, conf, e.data); - } - } - }); - - verto.subscribe(conf.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(conf.params.infoCallback) === "function") { - conf.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(conf.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(conf.params.chatCallback) === "function") { - conf.params.chatCallback(v,e); - } - } - }); - }; - - $.verto.conf.prototype.modCommand = function(cmd, id, value) { - var conf = this; - - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.conf.prototype.destroy = function() { - var conf = this; - - conf.destroyed = true; - conf.params.onBroadcast(conf.verto, conf, 'destroy'); - - if (conf.params.laData.modChannel) { - conf.verto.unsubscribe(conf.params.laData.modChannel); - } - - if (conf.params.laData.chatChannel) { - conf.verto.unsubscribe(conf.params.laData.chatChannel); - } - - if (conf.params.laData.infoChannel) { - conf.verto.unsubscribe(conf.params.laData.infoChannel); - } - }; - - function createMainModeratorMethods() { - $.verto.conf.prototype.listVideoLayouts = function() { - this.modCommand("list-videoLayouts", null, null); - }; - - $.verto.conf.prototype.play = function(file) { - this.modCommand("play", null, file); - }; - - $.verto.conf.prototype.stop = function() { - this.modCommand("stop", null, "all"); - }; - - $.verto.conf.prototype.deaf = function(memberID) { - this.modCommand("deaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.undeaf = function(memberID) { - this.modCommand("undeaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.record = function(file) { - this.modCommand("recording", null, ["start", file]); - }; - - $.verto.conf.prototype.stopRecord = function() { - this.modCommand("recording", null, ["stop", "all"]); - }; - - $.verto.conf.prototype.snapshot = function(file) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-write-png", null, file); - }; - - $.verto.conf.prototype.setVideoLayout = function(layout, canvasID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - if (canvasID) { - this.modCommand("vid-layout", null, [layout, canvasID]); - } else { - this.modCommand("vid-layout", null, layout); - } - }; - - $.verto.conf.prototype.kick = function(memberID) { - this.modCommand("kick", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteMic = function(memberID) { - this.modCommand("tmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteVideo = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("tvmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.presenter = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-res-id", parseInt(memberID), "presenter"); - }; - - $.verto.conf.prototype.videoFloor = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-floor", parseInt(memberID), "force"); - }; - - $.verto.conf.prototype.banner = function(memberID, text) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-banner", parseInt(memberID), escape(text)); - }; - - $.verto.conf.prototype.volumeDown = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.volumeUp = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.gainDown = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.gainUp = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.transfer = function(memberID, exten) { - this.modCommand("transfer", parseInt(memberID), exten); - }; - - $.verto.conf.prototype.sendChat = function(message, type) { - var conf = this; - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - } - - $.verto.modfuncs = {}; - - $.verto.confMan = function(verto, params) { - var confMan = this; - - confMan.params = $.extend({ - tableID: null, - statusID: null, - mainModID: null, - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - confMan.verto = verto; - confMan.serno = CONFMAN_SERNO++; - confMan.canvasCount = confMan.params.laData.canvasCount; - - function genMainMod(jq) { - var play_id = "play_" + confMan.serno; - var stop_id = "stop_" + confMan.serno; - var recording_id = "recording_" + confMan.serno; - var snapshot_id = "snapshot_" + confMan.serno; - var rec_stop_id = "recording_stop" + confMan.serno; - var div_id = "confman_" + confMan.serno; - - var html = "

" + - "" + - "" + - "" + - "" + - (confMan.params.hasVid ? "" : "") + - "

"; - - jq.html(html); - - $.verto.modfuncs.change_video_layout = function(id, canvas_id) { - var val = $("#" + id + " option:selected").text(); - if (val !== "none") { - confMan.modCommand("vid-layout", null, [val, canvas_id]); - } - }; - - if (confMan.params.hasVid) { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno; - var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno; - - - var vlhtml = "

" + - "Video Layout Canvas " + (j+1) + - " " + - "

"; - jq.append(vlhtml); - } - - $("#" + snapshot_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("vid-write-png", null, file); - } - }); - } - - $("#" + play_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("play", null, file); - } - }); - - $("#" + stop_id).click(function() { - confMan.modCommand("stop", null, "all"); - }); - - $("#" + recording_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("recording", null, ["start", file]); - } - }); - - $("#" + rec_stop_id).click(function() { - confMan.modCommand("recording", null, ["stop", "all"]); - }); - - } - - function genControls(jq, rowid) { - var x = parseInt(rowid); - var kick_id = "kick_" + x; - var canvas_in_next_id = "canvas_in_next_" + x; - var canvas_in_prev_id = "canvas_in_prev_" + x; - var canvas_out_next_id = "canvas_out_next_" + x; - var canvas_out_prev_id = "canvas_out_prev_" + x; - - var canvas_in_set_id = "canvas_in_set_" + x; - var canvas_out_set_id = "canvas_out_set_" + x; - - var layer_set_id = "layer_set_" + x; - var layer_next_id = "layer_next_" + x; - var layer_prev_id = "layer_prev_" + x; - - var tmute_id = "tmute_" + x; - var tvmute_id = "tvmute_" + x; - var vbanner_id = "vbanner_" + x; - var tvpresenter_id = "tvpresenter_" + x; - var tvfloor_id = "tvfloor_" + x; - var box_id = "box_" + x; - var gainup_id = "gain_in_up" + x; - var gaindn_id = "gain_in_dn" + x; - var volup_id = "vol_in_up" + x; - var voldn_id = "vol_in_dn" + x; - var transfer_id = "transfer" + x; - - - var html = "
"; - - html += "General Controls
"; - - html += "" + - "" + - "" + - "" + - "" + - "" + - ""; - - if (confMan.params.hasVid) { - html += "

Video Controls
"; - - - html += "" + - "" + - "" + - ""; - - if (confMan.canvasCount > 1) { - html += "

Canvas Controls
" + - "" + - "" + - "" + - - "
" + - - "" + - "" + - ""; - } - - html += "
" + - - "" + - "" + - "" + - - - - "
"; - } - - jq.html(html); - - - if (!jq.data("mouse")) { - $("#" + box_id).hide(); - } - - jq.mouseover(function(e) { - jq.data({"mouse": true}); - $("#" + box_id).show(); - }); - - jq.mouseout(function(e) { - jq.data({"mouse": false}); - $("#" + box_id).hide(); - }); - - $("#" + transfer_id).click(function() { - var xten = prompt("Enter Extension"); - if (xten) { - confMan.modCommand("transfer", x, xten); - } - }); - - $("#" + kick_id).click(function() { - confMan.modCommand("kick", x); - }); - - - $("#" + layer_set_id).click(function() { - var cid = prompt("Please enter layer ID", ""); - if (cid) { - confMan.modCommand("vid-layer", x, cid); - } - }); - - $("#" + layer_next_id).click(function() { - confMan.modCommand("vid-layer", x, "next"); - }); - $("#" + layer_prev_id).click(function() { - confMan.modCommand("vid-layer", x, "prev"); - }); - - $("#" + canvas_in_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-canvas", x, cid); - } - }); - - $("#" + canvas_out_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-watching-canvas", x, cid); - } - }); - - $("#" + canvas_in_next_id).click(function() { - confMan.modCommand("vid-canvas", x, "next"); - }); - $("#" + canvas_in_prev_id).click(function() { - confMan.modCommand("vid-canvas", x, "prev"); - }); - - - $("#" + canvas_out_next_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "next"); - }); - $("#" + canvas_out_prev_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "prev"); - }); - - $("#" + tmute_id).click(function() { - confMan.modCommand("tmute", x); - }); - - if (confMan.params.hasVid) { - $("#" + tvmute_id).click(function() { - confMan.modCommand("tvmute", x); - }); - $("#" + tvpresenter_id).click(function() { - confMan.modCommand("vid-res-id", x, "presenter"); - }); - $("#" + tvfloor_id).click(function() { - confMan.modCommand("vid-floor", x, "force"); - }); - $("#" + vbanner_id).click(function() { - var text = prompt("Please enter text", ""); - if (text) { - confMan.modCommand("vid-banner", x, escape(text)); - } - }); - } - - $("#" + gainup_id).click(function() { - confMan.modCommand("volume_in", x, "up"); - }); - - $("#" + gaindn_id).click(function() { - confMan.modCommand("volume_in", x, "down"); - }); - - $("#" + volup_id).click(function() { - confMan.modCommand("volume_out", x, "up"); - }); - - $("#" + voldn_id).click(function() { - confMan.modCommand("volume_out", x, "down"); - }); - - return html; - } - - var atitle = ""; - var awidth = 0; - - //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px"); - - verto.subscribe(confMan.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(confMan.params.infoCallback) === "function") { - confMan.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(confMan.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(confMan.params.chatCallback) === "function") { - confMan.params.chatCallback(v,e); - } - } - }); - - if (confMan.params.laData.role === "moderator") { - atitle = "Action"; - awidth = 600; - - if (confMan.params.mainModID) { - genMainMod($(confMan.params.mainModID)); - $(confMan.params.displayID).html("Moderator Controls Ready

"); - } else { - $(confMan.params.mainModID).html(""); - } - - verto.subscribe(confMan.params.laData.modChannel, { - handler: function(v, e) { - //console.error("MODDATA:", e.data); - if (confMan.params.onBroadcast) { - confMan.params.onBroadcast(verto, confMan, e.data); - } - - if (e.data["conf-command"] === "list-videoLayouts") { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno; - var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno; - - var x = 0; - var options; - - $(vlselect_id).selectmenu({}); - $(vlselect_id).selectmenu("enable"); - $(vlselect_id).empty(); - - $(vlselect_id).append(new Option("Choose a Layout", "none")); - - if (e.data.responseData) { - var rdata = []; - - for (var i in e.data.responseData) { - rdata.push(e.data.responseData[i].name); - } - - options = rdata.sort(function(a, b) { - var ga = a.substring(0, 6) == "group:" ? true : false; - var gb = b.substring(0, 6) == "group:" ? true : false; - - if ((ga || gb) && ga != gb) { - return ga ? -1 : 1; - } - - return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) ); - }); - - for (var i in options) { - $(vlselect_id).append(new Option(options[i], options[i])); - x++; - } - } - - if (x) { - $(vlselect_id).selectmenu('refresh', true); - } else { - $(vlayout_id).hide(); - } - } - } else { - - if (!confMan.destroyed && confMan.params.displayID) { - $(confMan.params.displayID).html(e.data.response + "

"); - if (confMan.lastTimeout) { - clearTimeout(confMan.lastTimeout); - confMan.lastTimeout = 0; - } - confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

");}, 4000); - } - } - } - }); - - - if (confMan.params.hasVid) { - confMan.modCommand("list-videoLayouts", null, null); - } - } - - var row_callback = null; - - if (confMan.params.laData.role === "moderator") { - row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { - if (!aData[5]) { - var $row = $('td:eq(5)', nRow); - genControls($row, aData); - - if (confMan.params.onLaRow) { - confMan.params.onLaRow(verto, confMan, $row, aData); - } - } - }; - } - - confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), { - subParams: { - callID: confMan.params.dialog ? confMan.params.dialog.callID : null - }, - - "onChange": function(obj, args) { - $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)"); - if (confMan.params.onLaChange) { - confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); - } - }, - - "aaData": [], - "aoColumns": [ - { - "sTitle": "ID", - "sWidth": "50" - }, - { - "sTitle": "Number", - "sWidth": "250" - }, - { - "sTitle": "Name", - "sWidth": "250" - }, - { - "sTitle": "Codec", - "sWidth": "100" - }, - { - "sTitle": "Status", - "sWidth": confMan.params.hasVid ? "200px" : "150px" - }, - { - "sTitle": atitle, - "sWidth": awidth, - } - ], - "bAutoWidth": true, - "bDestroy": true, - "bSort": false, - "bInfo": false, - "bFilter": false, - "bLengthChange": false, - "bPaginate": false, - "iDisplayLength": 1400, - - "oLanguage": { - "sEmptyTable": "The Conference is Empty....." - }, - - "fnRowCallback": row_callback - - }); - }; - - $.verto.confMan.prototype.modCommand = function(cmd, id, value) { - var confMan = this; - - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.confMan.prototype.sendChat = function(message, type) { - var confMan = this; - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - - $.verto.confMan.prototype.destroy = function() { - var confMan = this; - - confMan.destroyed = true; - - if (confMan.lt) { - confMan.lt.destroy(); - } - - if (confMan.params.laData.chatChannel) { - confMan.verto.unsubscribe(confMan.params.laData.chatChannel); - } - - if (confMan.params.laData.modChannel) { - confMan.verto.unsubscribe(confMan.params.laData.modChannel); - } - - if (confMan.params.mainModID) { - $(confMan.params.mainModID).html(""); - } - }; - - $.verto.dialog = function(direction, verto, params) { - var dialog = this; - - dialog.params = $.extend({ - useVideo: verto.options.useVideo, - useStereo: verto.options.useStereo, - screenShare: false, - useCamera: false, - useMic: verto.options.deviceParams.useMic, - useSpeak: verto.options.deviceParams.useSpeak, - tag: verto.options.tag, - localTag: verto.options.localTag, - login: verto.options.login, - videoParams: verto.options.videoParams, - useStream: verto.options.useStream, - }, params); - - - if (!dialog.params.screenShare) { - dialog.params.useCamera = verto.options.deviceParams.useCamera; - } - - dialog.verto = verto; - dialog.direction = direction; - dialog.lastState = null; - dialog.state = dialog.lastState = $.verto.enum.state.new; - dialog.callbacks = verto.callbacks; - dialog.answered = false; - dialog.attach = params.attach || false; - dialog.screenShare = params.screenShare || false; - dialog.useCamera = dialog.params.useCamera; - dialog.useMic = dialog.params.useMic; - dialog.useSpeak = dialog.params.useSpeak; - - if (dialog.params.callID) { - dialog.callID = dialog.params.callID; - } else { - dialog.callID = dialog.params.callID = generateGUID(); - } - - if (typeof(dialog.params.tag) === "function") { - dialog.params.tag = dialog.params.tag(); - } - - if (dialog.params.tag) { - dialog.audioStream = document.getElementById(dialog.params.tag); - - if (dialog.params.useVideo) { - dialog.videoStream = dialog.audioStream; - } - } //else conjure one TBD - - if (dialog.params.localTag) { - dialog.localVideo = document.getElementById(dialog.params.localTag); - } - - dialog.verto.dialogs[dialog.callID] = dialog; - - var RTCcallbacks = {}; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.params.display_direction === "outbound") { - dialog.params.remote_caller_id_name = dialog.params.caller_id_name; - dialog.params.remote_caller_id_number = dialog.params.caller_id_number; - } else { - dialog.params.remote_caller_id_name = dialog.params.callee_id_name; - dialog.params.remote_caller_id_number = dialog.params.callee_id_number; - } - - if (!dialog.params.remote_caller_id_name) { - dialog.params.remote_caller_id_name = "Nobody"; - } - - if (!dialog.params.remote_caller_id_number) { - dialog.params.remote_caller_id_number = "UNKNOWN"; - } - - RTCcallbacks.onMessage = function(rtc, msg) { - console.debug(msg); - }; - - RTCcallbacks.onAnswerSDP = function(rtc, sdp) { - console.error("answer sdp", sdp); - }; - } else { - dialog.params.remote_caller_id_name = "Outbound Call"; - dialog.params.remote_caller_id_number = dialog.params.destination_number; - } - - RTCcallbacks.onICESDP = function(rtc) { - console.log("RECV " + rtc.type + " SDP", rtc.mediaData.SDP); - - if (dialog.state == $.verto.enum.state.requesting || dialog.state == $.verto.enum.state.answering || dialog.state == $.verto.enum.state.active) { - location.reload(); - return; - } - - if (rtc.type == "offer") { - if (dialog.state == $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.requesting); - dialog.sendMethod("verto.attach", { - sdp: rtc.mediaData.SDP - }); - } else { - dialog.setState($.verto.enum.state.requesting); - - dialog.sendMethod("verto.invite", { - sdp: rtc.mediaData.SDP - }); - } - } else { //answer - dialog.setState($.verto.enum.state.answering); - - dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", { - sdp: dialog.rtc.mediaData.SDP - }); - } - }; - - RTCcallbacks.onICE = function(rtc) { - //console.log("cand", rtc.mediaData.candidate); - if (rtc.type == "offer") { - console.log("offer", rtc.mediaData.candidate); - return; - } - }; - - RTCcallbacks.onStream = function(rtc, stream) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onGranted === 'function') { - dialog.callbacks.permissionCallback.onGranted(stream); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onGranted === 'function'){ - dialog.verto.options.permissionCallback.onGranted(stream); - } - console.log("stream started"); - }; - - RTCcallbacks.onRemoteStream = function(rtc, stream) { - if (typeof dialog.callbacks.onRemoteStream === 'function') { - dialog.callbacks.onRemoteStream(stream, dialog); - } - console.log("remote stream started"); - }; - - RTCcallbacks.onError = function(e) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onDenied === 'function') { - dialog.callbacks.permissionCallback.onDenied(); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onDenied === 'function'){ - dialog.verto.options.permissionCallback.onDenied(); - } - console.error("ERROR:", e); - dialog.hangup({cause: "Device or Permission Error"}); - }; - - dialog.rtc = new $.FSRTC({ - callbacks: RTCcallbacks, - localVideo: dialog.screenShare ? null : dialog.localVideo, - useVideo: dialog.params.useVideo ? dialog.videoStream : null, - useAudio: dialog.audioStream, - useStereo: dialog.params.useStereo, - videoParams: dialog.params.videoParams, - audioParams: verto.options.audioParams, - iceServers: verto.options.iceServers, - screenShare: dialog.screenShare, - useCamera: dialog.useCamera, - useMic: dialog.useMic, - useSpeak: dialog.useSpeak, - turnServer: verto.options.turnServer, - useStream: dialog.params.useStream - }); - - dialog.rtc.verto = dialog.verto; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.attach) { - dialog.answer(); - } else { - dialog.ring(); - } - } - }; - - $.verto.dialog.prototype.invite = function() { - var dialog = this; - dialog.rtc.call(); - }; - - $.verto.dialog.prototype.sendMethod = function(method, obj) { - var dialog = this; - obj.dialogParams = {}; - - for (var i in dialog.params) { - if (i == "sdp" && method != "verto.invite" && method != "verto.attach") { - continue; - } - - if ((obj.noDialogParams && i != "callID")) { - continue; - } - - obj.dialogParams[i] = dialog.params[i]; - } - - delete obj.noDialogParams; - - dialog.verto.rpcClient.call(method, obj, - - function(e) { - /* Success */ - dialog.processReply(method, true, e); - }, - - function(e) { - /* Error */ - dialog.processReply(method, false, e); - }); - }; - - function checkStateChange(oldS, newS) { - - if (newS == $.verto.enum.state.purge || $.verto.enum.states[oldS.name][newS.name]) { - return true; - } - - return false; - } - - - // Attach audio output device to video element using device/sink ID. - function find_name(id) { - for (var i in $.verto.audioOutDevices) { - var source = $.verto.audioOutDevices[i]; - if (source.id === id) { - return(source.label); - } - } - - return id; - } - - $.verto.dialog.prototype.setAudioPlaybackDevice = function(sinkId, callback, arg) { - var dialog = this; - var element = dialog.audioStream; - - if (typeof element.sinkId !== 'undefined') { - var devname = find_name(sinkId); - console.info("Dialog: " + dialog.callID + " Setting speaker:", element, devname); - - element.setSinkId(sinkId) - .then(function() { - console.log("Dialog: " + dialog.callID + ' Success, audio output device attached: ' + sinkId); - if (callback) { - callback(true, devname, arg); - } - }) - .catch(function(error) { - var errorMessage = error; - if (error.name === 'SecurityError') { - errorMessage = "Dialog: " + dialog.callID + ' You need to use HTTPS for selecting audio output ' + - 'device: ' + error; - } - if (callback) { - callback(false, null, arg); - } - console.error(errorMessage); - }); - } else { - console.warn("Dialog: " + dialog.callID + ' Browser does not support output device selection.'); - if (callback) { - callback(false, null, arg); - } - } - } - - $.verto.dialog.prototype.setState = function(state) { - var dialog = this; - - if (dialog.state == $.verto.enum.state.ringing) { - dialog.stopRinging(); - } - - if (dialog.state == state || !checkStateChange(dialog.state, state)) { - console.error("Dialog " + dialog.callID + ": INVALID state change from " + dialog.state.name + " to " + state.name); - dialog.hangup(); - return false; - } - - console.log("Dialog " + dialog.callID + ": state change from " + dialog.state.name + " to " + state.name); - - dialog.lastState = dialog.state; - dialog.state = state; - - if (dialog.callbacks.onDialogState) { - dialog.callbacks.onDialogState(this); - } - - switch (dialog.state) { - - case $.verto.enum.state.early: - case $.verto.enum.state.active: - - var speaker = dialog.useSpeak; - console.info("Using Speaker: ", speaker); - - if (speaker && speaker !== "any" && speaker !== "none") { - setTimeout(function() { - dialog.setAudioPlaybackDevice(speaker); - }, 500); - } - - break; - - case $.verto.enum.state.trying: - setTimeout(function() { - if (dialog.state == $.verto.enum.state.trying) { - dialog.setState($.verto.enum.state.hangup); - } - }, 30000); - break; - case $.verto.enum.state.purge: - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.hangup: - - if (dialog.lastState.val > $.verto.enum.state.requesting.val && dialog.lastState.val < $.verto.enum.state.hangup.val) { - dialog.sendMethod("verto.bye", {}); - } - - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.destroy: - - if (typeof(dialog.verto.options.tag) === "function") { - $('#' + dialog.params.tag).remove(); - } - - delete dialog.verto.dialogs[dialog.callID]; - if (dialog.params.screenShare) { - dialog.rtc.stopPeer(); - } else { - dialog.rtc.stop(); - } - break; - } - - return true; - }; - - $.verto.dialog.prototype.processReply = function(method, success, e) { - var dialog = this; - - //console.log("Response: " + method + " State:" + dialog.state.name, success, e); - - switch (method) { - - case "verto.answer": - case "verto.attach": - if (success) { - dialog.setState($.verto.enum.state.active); - } else { - dialog.hangup(); - } - break; - case "verto.invite": - if (success) { - dialog.setState($.verto.enum.state.trying); - } else { - dialog.setState($.verto.enum.state.destroy); - } - break; - - case "verto.bye": - dialog.hangup(); - break; - - case "verto.modify": - if (e.holdState) { - if (e.holdState == "held") { - if (dialog.state != $.verto.enum.state.held) { - dialog.setState($.verto.enum.state.held); - } - } else if (e.holdState == "active") { - if (dialog.state != $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.active); - } - } - } - - if (success) {} - - break; - - default: - break; - } - - }; - - $.verto.dialog.prototype.hangup = function(params) { - var dialog = this; - - if (params) { - if (params.causeCode) { - dialog.causeCode = params.causeCode; - } - - if (params.cause) { - dialog.cause = params.cause; - } - } - - if (!dialog.cause && !dialog.causeCode) { - dialog.cause = "NORMAL_CLEARING"; - } - - if (dialog.state.val >= $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) { - dialog.setState($.verto.enum.state.hangup); - } else if (dialog.state.val < $.verto.enum.state.destroy) { - dialog.setState($.verto.enum.state.destroy); - } - }; - - $.verto.dialog.prototype.stopRinging = function() { - var dialog = this; - if (dialog.verto.ringer) { - dialog.verto.ringer.stop(); - } - }; - - $.verto.dialog.prototype.indicateRing = function() { - var dialog = this; - - if (dialog.verto.ringer) { - dialog.verto.ringer.attr("src", dialog.verto.options.ringFile)[0].play(); - - setTimeout(function() { - dialog.stopRinging(); - if (dialog.state == $.verto.enum.state.ringing) { - dialog.indicateRing(); - } - }, - dialog.verto.options.ringSleep); - } - }; - - $.verto.dialog.prototype.ring = function() { - var dialog = this; - - dialog.setState($.verto.enum.state.ringing); - dialog.indicateRing(); - }; - - $.verto.dialog.prototype.useVideo = function(on) { - var dialog = this; - - dialog.params.useVideo = on; - - if (on) { - dialog.videoStream = dialog.audioStream; - } else { - dialog.videoStream = null; - } - - dialog.rtc.useVideo(dialog.videoStream, dialog.localVideo); - - }; - - $.verto.dialog.prototype.setMute = function(what) { - var dialog = this; - return dialog.rtc.setMute(what); - }; - - $.verto.dialog.prototype.getMute = function() { - var dialog = this; - return dialog.rtc.getMute(); - }; - - $.verto.dialog.prototype.setVideoMute = function(what) { - var dialog = this; - return dialog.rtc.setVideoMute(what); - }; - - $.verto.dialog.prototype.getVideoMute = function() { - var dialog = this; - return dialog.rtc.getVideoMute(); - }; - - $.verto.dialog.prototype.useStereo = function(on) { - var dialog = this; - - dialog.params.useStereo = on; - dialog.rtc.useStereo(on); - }; - - $.verto.dialog.prototype.dtmf = function(digits) { - var dialog = this; - if (digits) { - dialog.sendMethod("verto.info", { - dtmf: digits - }); - } - }; - - $.verto.dialog.prototype.rtt = function(obj) { - var dialog = this; - var pobj = {}; - - if (!obj) { - return false; - } - - pobj.code = obj.code; - pobj.chars = obj.chars; - - - if (pobj.chars || pobj.code) { - dialog.sendMethod("verto.info", { - txt: obj, - noDialogParams: true - }); - } - }; - - $.verto.dialog.prototype.transfer = function(dest, params) { - var dialog = this; - if (dest) { - dialog.sendMethod("verto.modify", { - action: "transfer", - destination: dest, - params: params - }); - } - }; - - $.verto.dialog.prototype.replace = function(replaceCallID, params) { - var dialog = this; - if (replaceCallID) { - dialog.sendMethod("verto.modify", { - action: "replace", - replaceCallID: replaceCallID, - params: params - }); - } - }; - - $.verto.dialog.prototype.hold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "hold", - params: params - }); - }; - - $.verto.dialog.prototype.unhold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "unhold", - params: params - }); - }; - - $.verto.dialog.prototype.toggleHold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "toggleHold", - params: params - }); - }; - - $.verto.dialog.prototype.message = function(msg) { - var dialog = this; - var err = 0; - - msg.from = dialog.params.login; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - dialog.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.dialog.prototype.answer = function(params) { - var dialog = this; - - if (!dialog.answered) { - if (!params) { - params = {}; - } - - params.sdp = dialog.params.sdp; - - if (params) { - if (params.useVideo) { - dialog.useVideo(true); - } - dialog.params.callee_id_name = params.callee_id_name; - dialog.params.callee_id_number = params.callee_id_number; - - if (params.useCamera) { - dialog.useCamera = params.useCamera; - } - - if (params.useMic) { - dialog.useMic = params.useMic; - } - - if (params.useSpeak) { - dialog.useSpeak = params.useSpeak; - } - } - - dialog.rtc.createAnswer(params); - dialog.answered = true; - } - }; - - $.verto.dialog.prototype.handleAnswer = function(params) { - var dialog = this; - - dialog.gotAnswer = true; - - if (dialog.state.val >= $.verto.enum.state.active.val) { - return; - } - - if (dialog.state.val >= $.verto.enum.state.early.val) { - dialog.setState($.verto.enum.state.active); - } else { - if (dialog.gotEarly) { - console.log("Dialog " + dialog.callID + " Got answer while still establishing early media, delaying..."); - } else { - console.log("Dialog " + dialog.callID + " Answering Channel"); - dialog.rtc.answer(params.sdp, function() { - dialog.setState($.verto.enum.state.active); - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); - } - } - - - }; - - $.verto.dialog.prototype.cidString = function(enc) { - var dialog = this; - var party = dialog.params.remote_caller_id_name + (enc ? " <" : " <") + dialog.params.remote_caller_id_number + (enc ? ">" : ">"); - return party; - }; - - $.verto.dialog.prototype.sendMessage = function(msg, params) { - var dialog = this; - - if (dialog.callbacks.onMessage) { - dialog.callbacks.onMessage(dialog.verto, dialog, msg, params); - } - }; - - $.verto.dialog.prototype.handleInfo = function(params) { - var dialog = this; - - dialog.sendMessage($.verto.enum.message.info, params); - - }; - - $.verto.dialog.prototype.handleDisplay = function(params) { - var dialog = this; - - if (params.display_name) { - dialog.params.remote_caller_id_name = params.display_name; - } - if (params.display_number) { - dialog.params.remote_caller_id_number = params.display_number; - } - - dialog.sendMessage($.verto.enum.message.display, {}); - }; - - $.verto.dialog.prototype.handleMedia = function(params) { - var dialog = this; - - if (dialog.state.val >= $.verto.enum.state.early.val) { - return; - } - - dialog.gotEarly = true; - - dialog.rtc.answer(params.sdp, function() { - console.log("Dialog " + dialog.callID + "Establishing early media"); - dialog.setState($.verto.enum.state.early); - - if (dialog.gotAnswer) { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.setState($.verto.enum.state.active); - } - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "EARLY SDP", params.sdp); - }; - - $.verto.ENUM = function(s) { - var i = 0, - o = {}; - s.split(" ").map(function(x) { - o[x] = { - name: x, - val: i++ - }; - }); - return Object.freeze(o); - }; - - $.verto.enum = {}; - - $.verto.enum.states = Object.freeze({ - new: { - requesting: 1, - recovering: 1, - ringing: 1, - destroy: 1, - answering: 1, - hangup: 1 - }, - requesting: { - trying: 1, - hangup: 1, - active: 1 - }, - recovering: { - answering: 1, - hangup: 1 - }, - trying: { - active: 1, - early: 1, - hangup: 1 - }, - ringing: { - answering: 1, - hangup: 1 - }, - answering: { - active: 1, - hangup: 1 - }, - active: { - answering: 1, - requesting: 1, - hangup: 1, - held: 1 - }, - held: { - hangup: 1, - active: 1 - }, - early: { - hangup: 1, - active: 1 - }, - hangup: { - destroy: 1 - }, - destroy: {}, - purge: { - destroy: 1 - } - }); - - $.verto.enum.state = $.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge"); - $.verto.enum.direction = $.verto.ENUM("inbound outbound"); - $.verto.enum.message = $.verto.ENUM("display info pvtEvent clientReady"); - - $.verto.enum = Object.freeze($.verto.enum); - - $.verto.saved = []; - - $.verto.unloadJobs = []; - - var unloadEventName = 'beforeunload'; - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - if (iOS) { - unloadEventName = 'pagehide'; - } - - $(window).bind(unloadEventName, function() { - for (var f in $.verto.unloadJobs) { - $.verto.unloadJobs[f](); - } - - if ($.verto.haltClosure) - return $.verto.haltClosure(); - - for (var i in $.verto.saved) { - var verto = $.verto.saved[i]; - if (verto) { - verto.purge(); - verto.logout(); - } - } - - return $.verto.warnOnUnload; - }); - - $.verto.videoDevices = []; - $.verto.audioInDevices = []; - $.verto.audioOutDevices = []; - - var checkDevices = function(runtime) { - console.info("enumerating devices"); - var aud_in = [], aud_out = [], vid = []; - var has_video = 0, has_audio = 0; - var Xstream; - - function gotDevices(deviceInfos) { - // Handles being called several times to update labels. Preserve values. - for (var i = 0; i !== deviceInfos.length; ++i) { - var deviceInfo = deviceInfos[i]; - var text = ""; - - console.log(deviceInfo); - console.log(deviceInfo.kind + ": " + deviceInfo.label + " id = " + deviceInfo.deviceId); - - if (deviceInfo.kind === 'audioinput') { - text = deviceInfo.label || 'microphone ' + (aud_in.length + 1); - aud_in.push({id: deviceInfo.deviceId, kind: "audio_in", label: text}); - } else if (deviceInfo.kind === 'audiooutput') { - text = deviceInfo.label || 'speaker ' + (aud_out.length + 1); - aud_out.push({id: deviceInfo.deviceId, kind: "audio_out", label: text}); - } else if (deviceInfo.kind === 'videoinput') { - text = deviceInfo.label || 'camera ' + (vid.length + 1); - vid.push({id: deviceInfo.deviceId, kind: "video", label: text}); - } else { - console.log('Some other kind of source/device: ', deviceInfo); - } - } - - - $.verto.videoDevices = vid; - $.verto.audioInDevices = aud_in; - $.verto.audioOutDevices = aud_out; - - console.info("Audio IN Devices", $.verto.audioInDevices); - console.info("Audio Out Devices", $.verto.audioOutDevices); - console.info("Video Devices", $.verto.videoDevices); - - if (Xstream) { - Xstream.getTracks().forEach(function(track) {track.stop();}); - } - - if (runtime) { - runtime(true); - } - } - - - - - function handleError(error) { - console.log('device enumeration error: ', error); - if (runtime) runtime(false); - } - - - function checkTypes(devs) { - for (var i = 0; i !== devs.length; ++i) { - - if (devs[i].kind === 'audioinput') { - has_audio++; - } else if (devs[i].kind === 'videoinput') { - has_video++; - } - } - - navigator.getUserMedia({ audio: (has_audio > 0 ? true : false), video: (has_video > 0 ? true : false)}, - function(stream) { - Xstream = stream; - navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError); - }, - function(err) { - console.log("The following error occurred: " + err.name); - } - ); - } - - navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError); - - }; - - $.verto.refreshDevices = function(runtime) { - checkDevices(runtime); - } - - $.verto.init = function(obj, runtime) { - if (!obj) { - obj = {}; - } - - if (!obj.skipPermCheck && !obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - checkDevices(runtime); - }, true, true); - } else if (obj.skipPermCheck && !obj.skipDeviceCheck) { - checkDevices(runtime); - } else if (!obj.skipPermCheck && obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - runtime(status); - }, true, true); - } else { - runtime(null); - } - - } - - $.verto.genUUID = function () { - return generateGUID(); - } - - -})(jQuery); -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -function maybeAddCandidate(iceTransport, candidate) { - // Edge's internal representation adds some fields therefore - // not all fieldѕ are taken into account. - var alreadyAdded = iceTransport.getRemoteCandidates() - .find(function(remoteCandidate) { - return candidate.foundation === remoteCandidate.foundation && - candidate.ip === remoteCandidate.ip && - candidate.port === remoteCandidate.port && - candidate.priority === remoteCandidate.priority && - candidate.protocol === remoteCandidate.protocol && - candidate.type === remoteCandidate.type; - }); - if (!alreadyAdded) { - iceTransport.addRemoteCandidate(candidate); - } - return !alreadyAdded; -} - - -// https://w3c.github.io/mediacapture-main/#mediastream -// Helper function to add the track to the stream and -// dispatch the event ourselves. -function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); -} - -function makeError(name, description) { - var e = new Error(description); - e.name = name; - return e; -} - -module.exports = function(window, edgeVersion) { - var RTCPeerConnection = function(config) { - var pc = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - pc[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.canTrickleIceCandidates = null; - - this.needNegotiation = false; - - this.localStreams = []; - this.remoteStreams = []; - - this.localDescription = null; - this.remoteDescription = null; - - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - config = JSON.parse(JSON.stringify(config || {})); - - this.usingBundle = config.bundlePolicy === 'max-bundle'; - if (config.rtcpMuxPolicy === 'negotiate') { - throw(makeError('NotSupportedError', - 'rtcpMuxPolicy \'negotiate\' is not supported')); - } else if (!config.rtcpMuxPolicy) { - config.rtcpMuxPolicy = 'require'; - } - - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - break; - default: - config.iceTransportPolicy = 'all'; - break; - } - - switch (config.bundlePolicy) { - case 'balanced': - case 'max-compat': - case 'max-bundle': - break; - default: - config.bundlePolicy = 'balanced'; - break; - } - - config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); - - this._iceGatherers = []; - if (config.iceCandidatePoolSize) { - for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers = new window.RTCIceGatherer({ - iceServers: config.iceServers, - gatherPolicy: config.iceTransportPolicy - }); - } - } else { - config.iceCandidatePoolSize = 0; - } - - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - this._sdpSessionVersion = 0; - - this._dtlsRole = undefined; // role for a=setup to use in answers. - - this._isClosed = false; - }; - - // set up event handlers on prototype - RTCPeerConnection.prototype.onicecandidate = null; - RTCPeerConnection.prototype.onaddstream = null; - RTCPeerConnection.prototype.ontrack = null; - RTCPeerConnection.prototype.onremovestream = null; - RTCPeerConnection.prototype.onsignalingstatechange = null; - RTCPeerConnection.prototype.oniceconnectionstatechange = null; - RTCPeerConnection.prototype.onicegatheringstatechange = null; - RTCPeerConnection.prototype.onnegotiationneeded = null; - RTCPeerConnection.prototype.ondatachannel = null; - - RTCPeerConnection.prototype._dispatchEvent = function(name, event) { - if (this._isClosed) { - return; - } - this.dispatchEvent(event); - if (typeof this['on' + name] === 'function') { - this['on' + name](event); - } - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this._dispatchEvent('icegatheringstatechange', event); - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - RTCPeerConnection.prototype.getLocalStreams = function() { - return this.localStreams; - }; - - RTCPeerConnection.prototype.getRemoteStreams = function() { - return this.remoteStreams; - }; - - // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - associatedRemoteMediaStreams: [], - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - this.transceivers.push(transceiver); - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - var alreadyExists = this.transceivers.find(function(s) { - return s.track === track; - }); - - if (alreadyExists) { - throw makeError('InvalidAccessError', 'Track already exists.'); - } - - if (this.signalingState === 'closed') { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - this._maybeFireNegotiationNeeded(); - - if (this.localStreams.indexOf(stream) === -1) { - this.localStreams.push(stream); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - if (edgeVersion >= 15025) { - stream.getTracks().forEach(function(track) { - pc.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - pc.addTrack(track, clonedStream); - }); - } - }; - - RTCPeerConnection.prototype.removeTrack = function(sender) { - if (!(sender instanceof window.RTCRtpSender)) { - throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.'); - } - - var transceiver = this.transceivers.find(function(t) { - return t.rtpSender === sender; - }); - - if (!transceiver) { - throw makeError('InvalidAccessError', - 'Sender was not created by this connection.'); - } - var stream = transceiver.stream; - - transceiver.rtpSender.stop(); - transceiver.rtpSender = null; - transceiver.track = null; - transceiver.stream = null; - - // remove the stream from the set of local streams - var localStreams = this.transceivers.map(function(t) { - return t.stream; - }); - if (localStreams.indexOf(stream) === -1 && - this.localStreams.indexOf(stream) > -1) { - this.localStreams.splice(this.localStreams.indexOf(stream), 1); - } - - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - stream.getTracks().forEach(function(track) { - var sender = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (sender) { - pc.removeTrack(sender); - } - }); - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - - RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, - usingBundle) { - var pc = this; - if (usingBundle && sdpMLineIndex > 0) { - return this.transceivers[0].iceGatherer; - } else if (this._iceGatherers.length) { - return this._iceGatherers.shift(); - } - var iceGatherer = new window.RTCIceGatherer({ - iceServers: this._config.iceServers, - gatherPolicy: this._config.iceTransportPolicy - }); - Object.defineProperty(iceGatherer, 'state', - {value: 'new', writable: true} - ); - - this.transceivers[sdpMLineIndex].candidates = []; - this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].candidates !== null) { - pc.transceivers[sdpMLineIndex].candidates.push(event.candidate); - } - }; - iceGatherer.addEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - return iceGatherer; - }; - - // start gathering from an RTCIceGatherer. - RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { - var pc = this; - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer.onlocalcandidate) { - return; - } - var candidates = this.transceivers[sdpMLineIndex].candidates; - this.transceivers[sdpMLineIndex].candidates = null; - iceGatherer.removeEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - iceGatherer.onlocalcandidate = function(evt) { - if (pc.usingBundle && sdpMLineIndex > 0) { - // if we know that we use bundle we can drop candidates with - // ѕdpMLineIndex > 0. If we don't do this then our state gets - // confused since we dispose the extra ice gatherer. - return; - } - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - // Edge emits an empty object for RTCIceCandidateComplete‥ - var end = !cand || Object.keys(cand).length === 0; - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { - iceGatherer.state = 'completed'; - } - } else { - if (iceGatherer.state === 'new') { - iceGatherer.state = 'gathering'; - } - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(pc.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - pc.localDescription.sdp = sections.join(''); - var complete = pc.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - if (pc.iceGatheringState !== 'gathering') { - pc.iceGatheringState = 'gathering'; - pc._emitGatheringStateChange(); - } - - // Emit candidate. Also emit null candidate when all gatherers are - // complete. - if (!end) { - pc._dispatchEvent('icecandidate', event); - } - if (complete) { - pc._dispatchEvent('icecandidate', new Event('icecandidate')); - pc.iceGatheringState = 'complete'; - pc._emitGatheringStateChange(); - } - }; - - // emit already gathered candidates. - window.setTimeout(function() { - candidates.forEach(function(candidate) { - var e = new Event('RTCIceGatherEvent'); - e.candidate = candidate; - iceGatherer.onlocalcandidate(e); - }); - }, 0); - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var pc = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - pc._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - pc._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itpc. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - pc._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - if (transceiver.recvEncodingParameters.length) { - params.encodings = transceiver.recvEncodingParameters; - } - params.rtcp = { - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.rtcpParameters.cname) { - params.rtcp.cname = transceiver.rtcpParameters.cname; - } - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set local ' + description.type + - ' in state ' + pc.signalingState)); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - pc.transceivers[sdpMLineIndex].localCapabilities = caps; - }); - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - pc._gather(transceiver.mid, sdpMLineIndex); - }); - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = pc.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!pc.usingBundle || sdpMLineIndex === 0) { - pc._gather(transceiver.mid, sdpMLineIndex); - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - pc._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set remote ' + description.type + - ' in state ' + pc.signalingState)); - } - - var streams = {}; - this.remoteStreams.forEach(function(stream) { - streams[stream.id] = stream; - }); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - this.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { - pc.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - pc.transceivers[sdpMLineIndex]) { - pc._disposeIceAndDtlsTransports(sdpMLineIndex); - pc.transceivers[sdpMLineIndex].iceGatherer = - pc.transceivers[0].iceGatherer; - pc.transceivers[sdpMLineIndex].iceTransport = - pc.transceivers[0].iceTransport; - pc.transceivers[sdpMLineIndex].dtlsTransport = - pc.transceivers[0].dtlsTransport; - if (pc.transceivers[sdpMLineIndex].rtpSender) { - pc.transceivers[sdpMLineIndex].rtpSender.setTransport( - pc.transceivers[0].dtlsTransport); - } - if (pc.transceivers[sdpMLineIndex].rtpReceiver) { - pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - pc.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex] || - pc._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - usingBundle); - } - - if (cands.length && transceiver.iceTransport.state === 'new') { - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - var isNewTrack = false; - if (direction === 'sendrecv' || direction === 'sendonly') { - isNewTrack = !transceiver.rtpReceiver; - rtpReceiver = transceiver.rtpReceiver || - new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); - - if (isNewTrack) { - var stream; - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid && remoteMsid.stream === '-') { - // no-op. a stream id of '-' means: no associated stream. - } else if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - stream = streams[remoteMsid.stream]; - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - stream = streams.default; - } - if (stream) { - addTrackToStreamAndFireEvent(track, stream); - transceiver.associatedRemoteMediaStreams.push(stream); - } - receiverList.push([track, rtpReceiver, stream]); - } - } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { - transceiver.associatedRemoteMediaStreams.forEach(function(s) { - var nativeTrack = s.getTracks().find(function(t) { - return t.id === transceiver.rtpReceiver.track.id; - }); - if (nativeTrack) { - removeTrackFromStreamAndFireEvent(nativeTrack, s); - } - }); - transceiver.associatedRemoteMediaStreams = []; - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - pc._transceive(pc.transceivers[sdpMLineIndex], - false, - isNewTrack); - } else if (description.type === 'answer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - pc.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - pc.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (cands.length && iceTransport.state === 'new') { - if ((isIceLite || isComplete) && - (!usingBundle || sdpMLineIndex === 0)) { - iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - if (!usingBundle || sdpMLineIndex === 0) { - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - pc._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams.default); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - if (this._dtlsRole === undefined) { - this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; - } - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - if (pc.remoteStreams.indexOf(stream) === -1) { - pc.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - window.setTimeout(function() { - pc._dispatchEvent('addstream', event); - }); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - fireAddTrack(pc, track, receiver, [stream]); - }); - } - }); - receiverList.forEach(function(item) { - if (item[2]) { - return; - } - fireAddTrack(pc, item[0], item[1], []); - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(pc && pc.transceivers)) { - return; - } - pc.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._isClosed = true; - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this._dispatchEvent('signalingstatechange', event); - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var pc = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (pc.needNegotiation === false) { - return; - } - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); - }, 0); - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== this.iceConnectionState) { - this.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this._dispatchEvent('iceconnectionstatechange', event); - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createOffer after close')); - } - - var numAudioTracks = this.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = this.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - var offerOptions = arguments[0]; - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - this.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - this._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - this._createTransceiver('video'); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - pc.usingBundle); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video' && - !sendEncodingParameters[0].rtx) { - sendEncodingParameters[0].rtx = { - ssrc: sendEncodingParameters[0].ssrc + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, kind); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += writeMediaSection(transceiver, transceiver.localCapabilities, - 'offer', transceiver.stream, pc._dtlsRole); - sdp += 'a=rtcp-rsize\r\n'; - - if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && - (sdpMLineIndex === 0 || !pc.usingBundle)) { - transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { - cand.component = 1; - sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; - }); - - if (transceiver.iceGatherer.state === 'completed') { - sdp += 'a=end-of-candidates\r\n'; - } - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer after close')); - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - var mediaSectionsInOffer = SDPUtils.splitSections( - this.remoteDescription.sdp).length - 1; - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (sdpMLineIndex + 1 > mediaSectionsInOffer) { - return; - } - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video' && - !transceiver.sendEncodingParameters[0].rtx) { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream, pc._dtlsRole); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - var sections; - if (!candidate || candidate.candidate === '') { - for (var j = 0; j < this.transceivers.length; j++) { - if (this.transceivers[j].isDatachannel) { - continue; - } - this.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[j + 1] += 'a=end-of-candidates\r\n'; - this.remoteDescription.sdp = sections.join(''); - if (this.usingBundle) { - break; - } - } - } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { - throw new TypeError('sdpMLineIndex or sdpMid required'); - } else if (!this.remoteDescription) { - return Promise.reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.isDatachannel) { - return Promise.resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return Promise.resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== this.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); - } - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[sdpMLineIndex + 1] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } else { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - resolve(results); - }); - }); - }; - - // legacy callback shims. Should be moved to adapter.js some days. - var methods = ['createOffer', 'createAnswer']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[0] === 'function' || - typeof args[1] === 'function') { // legacy - return nativeMethod.apply(this, [arguments[2]]) - .then(function(description) { - if (typeof args[0] === 'function') { - args[0].apply(null, [description]); - } - }, function(error) { - if (typeof args[1] === 'function') { - args[1].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function' || - typeof args[2] === 'function') { // legacy - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }, function(error) { - if (typeof args[2] === 'function') { - args[2].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // getStats is special. It doesn't have a spec legacy method yet we support - // getStats(something, cb) without error callbacks. - ['getStats'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function') { - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - return RTCPeerConnection; -}; - -},{"sdp":2}],2:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - case 'ufrag': - candidate.ufrag = parts[i + 1]; // for backward compability. - candidate.usernameFragment = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr - sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.split(' '); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } - }; - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -SDPUtils.parseMLine = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return { - kind: mline[0].substr(2), - port: parseInt(mline[1], 10), - protocol: mline[2], - fmt: mline.slice(3).join(' ') - }; -}; - -// Expose public methods. -if (typeof module === 'object') { - module.exports = SDPUtils; -} - -},{}],3:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":4}],4:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var utils = require('./utils'); -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - var commonShim = require('./common_shim') || null; - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - commonShim.shimCreateObjectURL(window); - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - commonShim.shimCreateObjectURL(window); - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - commonShim.shimCreateObjectURL(window); - - edgeShim.shimGetUserMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - commonShim.shimCreateObjectURL(window); - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimCreateOfferLegacy(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){ - -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - } - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } else if (!('RTCRtpTransceiver' in window)) { - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - if (!e.transceiver) { - e.transceiver = {receiver: e.receiver}; - } - return e; - }); - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrackWithNative: function(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function(streamId) { - return pc._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - var existingSenders = pc.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = pc.getSenders().filter(function(newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function(streamId) { - var idx = pc._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - pc._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (pc._shimmedLocalStreams[streamId].length === 1) { - delete pc._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; - }, - - shimAddTrackRemoveTrack: function(window) { - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && - browserDetails.version >= 65) { - return this.shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - var nativeStreams = origGetLocalStreams.apply(this); - pc._reverseStreams = pc._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return pc._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function() { - pc.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), - externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), - internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - var args = arguments; - var isLegacyCall = arguments.length && - typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(pc, [ - function(description) { - var desc = replaceInternalStreamId(pc, description); - args[0].apply(null, [desc]); - }, - function(err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2] - ]); - } - return nativeMethod.apply(pc, arguments) - .then(function(description) { - return replaceInternalStreamId(pc, description); - }); - }; - }); - - var origSetLocalDescription = - window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function() { - var pc = this; - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(pc, arguments); - } - arguments[0] = replaceExternalStreamId(pc, arguments[0]); - return origSetLocalDescription.apply(pc, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor( - window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, - 'localDescription', { - get: function() { - var pc = this; - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(pc, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(pc._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var pc = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(pc, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var pc = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof arguments[0] === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - -},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - var constraintsToChrome_ = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - InvalidStateError: 'NotReadableError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotReadableError', - MediaDeviceKillSwitchOn: 'NotReadableError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return getUserMediaPromise_(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":13}],7:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var utils = require('./utils'); - -module.exports = { - shimRTCIceCandidate: function(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (window.RTCIceCandidate && 'foundation' in - window.RTCIceCandidate.prototype) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function(args) { - // Remove the a= which shouldn't be part of the candidate string. - if (typeof args === 'object' && args.candidate && - args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = SDPUtils.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, - parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment, - }; - }; - return augmentedCandidate; - }; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype && - URL.createObjectURL && URL.revokeObjectURL)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - }, - - shimMaxMessageSize: function(window) { - if (window.RTCSctpTransport || !window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function(description) { - var sections = SDPUtils.splitSections(description.sdp); - sections.shift(); - return sections.some(function(mediaSection) { - var mLine = SDPUtils.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' - && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = - browserDetails.version === 57 ? 65535 : 65536; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' - && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && - remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - pc._sctp = null; - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function() { - return maxMessageSize; - } - }); - pc._sctp = sctp; - } - - return origSetRemoteDescription.apply(pc, arguments); - }; - }, - - shimSendThrowTypeError: function(window) { - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - var origCreateDataChannel = - window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function() { - var pc = this; - var dataChannel = origCreateDataChannel.apply(pc, arguments); - var origDataChannelSend = dataChannel.send; - - // Patch 'send' method - dataChannel.send = function() { - var dc = this; - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (length > pc.sctp.maxMessageSize) { - throw new DOMException('Message too large (can send a maximum of ' + - pc.sctp.maxMessageSize + ' bytes)', 'TypeError'); - } - return origDataChannelSend.apply(dc, arguments); - }; - - return dataChannel; - }; - } -}; - -},{"./utils":13,"sdp":2}],8:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var shimRTCPeerConnection = require('rtcpeerconnection-shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - - window.RTCPeerConnection = - shimRTCPeerConnection(window, browserDetails.version); - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.transceiver = {receiver: event.receiver}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - if (typeof window === 'object' && window.RTCTrackEvent && - ('receiver' in window.RTCTrackEvent.prototype) && - !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - }, - - shimRemoveStream: function(window) { - if (!window.RTCPeerConnection || - 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function(sender) { - if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } -}; - -},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var getUserMedia_ = function(constraints, onSuccess, onError) { - var constraintsToFF37_ = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r. min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":13}],12:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; -var utils = require('../utils'); - -module.exports = { - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var pc = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(pc, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - return _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var pc = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - var pc = this; - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - e.streams.forEach(function(stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in window.RTCPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - }, - shimTrackEventTransceiver: function(window) { - // Add event.transceiver member over deprecated event.receiver - if (typeof window === 'object' && window.RTCPeerConnection && - ('receiver' in window.RTCTrackEvent.prototype) && - // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is - // defined for some reason even when window.RTCTransceiver is not. - !window.RTCTransceiver) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimCreateOfferLegacy: function(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { - var pc = this; - if (offerOptions) { - var audioTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && - !audioTransceiver) { - pc.addTransceiver('audio'); - } - - var videoTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - videoTransceiver.setDirection('sendonly'); - } else if (videoTransceiver.direction === 'recvonly') { - videoTransceiver.setDirection('inactive'); - } - } else if (offerOptions.offerToReceiveVideo === true && - !videoTransceiver) { - pc.addTransceiver('video'); - } - } - return origCreateOffer.apply(pc, arguments); - }; - } -}; - -},{"../utils":13}],13:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object. -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function(e) { - cb(wrapper(e)); - }; - this._eventMap = this._eventMap || {}; - this._eventMap[cb] = wrappedCallback; - return nativeAddEventListener.apply(this, [nativeEventName, - wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap - || !this._eventMap[cb]) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[cb]; - delete this._eventMap[cb]; - return nativeRemoveEventListener.apply(this, [nativeEventName, - unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function() { - return this['_on' + eventNameToWrap]; - }, - set: function(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, - this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, - this['_on' + eventNameToWrap] = cb); - } - } - }); -} - -// Utility methods. -module.exports = { - extractVersion: extractVersion, - wrapPeerConnectionEvent: wrapPeerConnectionEvent, - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - if (navigator.mozGetUserMedia) { // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -},{}]},{},[3])(3) -}); \ No newline at end of file +(function($){function findLine(sdpLines,prefix,substr){return findLineInRange(sdpLines,0,-1,prefix,substr);} +function findLineInRange(sdpLines,startLine,endLine,prefix,substr){var realEndLine=(endLine!=-1)?endLine:sdpLines.length;for(var i=startLine;i=0;if(iOS){self.options.useVideo.setAttribute("playsinline",true);}} +var element=self.options.useAudio;console.log("REMOTE STREAM",stream,element);FSRTCattachMediaStream(element,stream);self.remoteStream=stream;onRemoteStreamSuccess(self,stream);} +function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");} +$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stopPeer=function(){if(self.peer){console.log("stopping peer");self.peer.stop();}} +$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';self.options.useVideo['src']='';} +if(self.localStream&&!self.options.useStream){if(typeof self.localStream.stop=='function'){self.localStream.stop();}else{if(self.localStream.active){var tracks=self.localStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}} +self.localStream=null;} +if(self.options.localVideo){deactivateLocalVideo(self.options.localVideo);} +if(self.options.localVideoStream&&!self.options.useStream){if(typeof self.options.localVideoStream.stop=='function'){self.options.localVideoStream.stop();}else{if(self.options.localVideoStream.active){var tracks=self.options.localVideoStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}}} +if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.getMute=function(){var self=this;return self.audioEnabled;} +$.FSRTC.prototype.setMute=function(what){var self=this;if(!self.localStream){return false;} +var audioTracks=self.localStream.getAudioTracks();for(var i=0,len=audioTracks.length;i=w&&$.FSRTC.validRes[i][1]>=h){w=$.FSRTC.validRes[i][0];h=$.FSRTC.validRes[i][1];}} +return[w,h];} +var resList=[[160,120],[320,180],[320,240],[640,360],[640,480],[1280,720],[1920,1080]];var resI=0;var ttl=0;var checkRes=function(cam,func){if(resI>=resList.length){var res={'validRes':$.FSRTC.validRes,'bestResSupported':$.FSRTC.bestResSupported()};localStorage.setItem("res_"+cam,$.toJSON(res));if(func)return func(res);return;} +w=resList[resI][0];h=resList[resI][1];resI++;var video={width:{exact:w},height:{exact:h}};if(cam!=="any"){video=assignMediaIdToConstraint(cam,video);} +getUserMedia({constraints:{audio:ttl++==0,video:video},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info(w+"x"+h+" supported.");$.FSRTC.validRes.push([w,h]);checkRes(cam,func);},onerror:function(e){console.warn(w+"x"+h+" not supported.");checkRes(cam,func);}});} +$.FSRTC.getValidRes=function(cam,func){var used=[];var cached=localStorage.getItem("res_"+cam);if(cached){var cache=$.parseJSON(cached);if(cache){$.FSRTC.validRes=cache.validRes;console.log("CACHED RES FOR CAM "+cam,cache);}else{console.error("INVALID CACHE");} +return func?func(cache):null;} +$.FSRTC.validRes=[];resI=0;checkRes(cam,func);} +$.FSRTC.checkPerms=function(runtime,check_audio,check_video){getUserMedia({constraints:{audio:check_audio,video:check_video,},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info("media perm init complete");if(runtime){setTimeout(runtime,100,true);}},onerror:function(e){if(check_video&&check_audio){console.error("error, retesting with audio params only");return $.FSRTC.checkPerms(runtime,check_audio,false);} +console.error("media perm init error");if(runtime){runtime(false)}}});}})(jQuery);(function($){$.JsonRpcClient=function(options){var self=this;this.options=$.extend({ajaxUrl:null,socketUrl:null,onmessage:null,login:null,passwd:null,sessid:null,loginParams:null,userVariables:null,getSocket:function(onmessage_cb){return self._getSocket(onmessage_cb);}},options);self.ws_cnt=0;this.wsOnMessage=function(event){self._wsOnMessage(event);};};$.JsonRpcClient.prototype._ws_socket=null;$.JsonRpcClient.prototype._ws_callbacks={};$.JsonRpcClient.prototype._current_id=1;$.JsonRpcClient.prototype.speedTest=function(bytes,cb){var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this.speedCB=cb;this.speedBytes=bytes;socket.send("#SPU "+bytes);var loops=bytes/1024;var rem=bytes%1024;var i;var data=new Array(1024).join(".");for(i=0;i1){return false;} +return true;};$.JsonRpcClient.prototype.closeSocket=function(){var self=this;if(self.socketReady()){self._ws_socket.onclose=function(w){console.log("Closing Socket");};self._ws_socket.close();}};$.JsonRpcClient.prototype.loginData=function(params){var self=this;self.options.login=params.login;self.options.passwd=params.passwd;self.options.loginParams=params.loginParams;self.options.userVariables=params.userVariables;};$.JsonRpcClient.prototype.connectSocket=function(onmessage_cb){var self=this;if(self.to){clearTimeout(self.to);} +if(!self.socketReady()){self.authing=false;if(self._ws_socket){delete self._ws_socket;} +self._ws_socket=new WebSocket(self.options.socketUrl);if(self._ws_socket){self._ws_socket.onmessage=onmessage_cb;self._ws_socket.onclose=function(w){if(!self.ws_sleep){self.ws_sleep=1000;} +if(self.options.onWSClose){self.options.onWSClose(self);} +if(self.ws_cnt>10&&self.options.wsFallbackURL){self.options.socketUrl=self.options.wsFallbackURL;} +console.error("Websocket Lost "+self.ws_cnt+" sleep: "+self.ws_sleep+"msec");self.to=setTimeout(function(){console.log("Attempting Reconnection....");self.connectSocket(onmessage_cb);},self.ws_sleep);self.ws_cnt++;if(self.ws_sleep<3000&&(self.ws_cnt%10)===0){self.ws_sleep+=1000;}};self._ws_socket.onopen=function(){if(self.to){clearTimeout(self.to);} +self.ws_sleep=1000;self.ws_cnt=0;if(self.options.onWSConnect){self.options.onWSConnect(self);} +var req;while((req=$.JsonRpcClient.q.pop())){self._ws_socket.send(req);}};}} +return self._ws_socket?true:false;};$.JsonRpcClient.prototype.stopRetrying=function(){if(self.to) +clearTimeout(self.to);} +$.JsonRpcClient.prototype._getSocket=function(onmessage_cb){if(this.options.socketUrl===null||!("WebSocket"in window))return null;this.connectSocket(onmessage_cb);return this._ws_socket;};$.JsonRpcClient.q=[];$.JsonRpcClient.prototype._wsCall=function(socket,request,success_cb,error_cb){var request_json=$.toJSON(request);if(socket.readyState<1){self=this;$.JsonRpcClient.q.push(request_json);}else{socket.send(request_json);} +if('id'in request&&typeof success_cb!=='undefined'){this._ws_callbacks[request.id]={request:request_json,request_obj:request,success_cb:success_cb,error_cb:error_cb};}};$.JsonRpcClient.prototype._wsOnMessage=function(event){var response;if(event.data[0]=="#"&&event.data[1]=="S"&&event.data[2]=="P"){if(event.data[3]=="U"){this.up_dur=parseInt(event.data.substring(4));}else if(this.speedCB&&event.data[3]=="D"){this.down_dur=parseInt(event.data.substring(4));var up_kps=(((this.speedBytes*8)/(this.up_dur/1000))/1024).toFixed(0);var down_kps=(((this.speedBytes*8)/(this.down_dur/1000))/1024).toFixed(0);console.info("Speed Test: Up: "+up_kps+" Down: "+down_kps);var cb=this.speedCB;this.speedCB=null;cb(event,{upDur:this.up_dur,downDur:this.down_dur,upKPS:up_kps,downKPS:down_kps});} +return;} +try{response=$.parseJSON(event.data);if(typeof response==='object'&&'jsonrpc'in response&&response.jsonrpc==='2.0'){if('result'in response&&this._ws_callbacks[response.id]){var success_cb=this._ws_callbacks[response.id].success_cb;delete this._ws_callbacks[response.id];success_cb(response.result,this);return;}else if('error'in response&&this._ws_callbacks[response.id]){var error_cb=this._ws_callbacks[response.id].error_cb;var orig_req=this._ws_callbacks[response.id].request;if(!self.authing&&response.error.code==-32000&&self.options.login&&self.options.passwd){self.authing=true;this.call("login",{login:self.options.login,passwd:self.options.passwd,loginParams:self.options.loginParams,userVariables:self.options.userVariables},this._ws_callbacks[response.id].request_obj.method=="login"?function(e){self.authing=false;console.log("logged in");delete self._ws_callbacks[response.id];if(self.options.onWSLogin){self.options.onWSLogin(true,self);}}:function(e){self.authing=false;console.log("logged in, resending request id: "+response.id);var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send(orig_req);} +if(self.options.onWSLogin){self.options.onWSLogin(true,self);}},function(e){console.log("error logging in, request id:",response.id);delete self._ws_callbacks[response.id];error_cb(response.error,this);if(self.options.onWSLogin){self.options.onWSLogin(false,self);}});return;} +delete this._ws_callbacks[response.id];error_cb(response.error,this);return;}}}catch(err){console.log("ERROR: "+err);return;} +if(typeof this.options.onmessage==='function'){event.eventData=response;if(!event.eventData){event.eventData={};} +var reply=this.options.onmessage(event);if(reply&&typeof reply==="object"&&event.eventData.id){var msg={jsonrpc:"2.0",id:event.eventData.id,result:reply};var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send($.toJSON(msg));}}}};$.JsonRpcClient._batchObject=function(jsonrpcclient,all_done_cb,error_cb){this._requests=[];this.jsonrpcclient=jsonrpcclient;this.all_done_cb=all_done_cb;this.error_cb=typeof error_cb==='function'?error_cb:function(){};};$.JsonRpcClient._batchObject.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};} +if(this.options.sessid){params.sessid=this.options.sessid;} +if(!success_cb){success_cb=function(e){console.log("Success: ",e);};} +if(!error_cb){error_cb=function(e){console.log("Error: ",e);};} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params,id:this.jsonrpcclient._current_id++},success_cb:success_cb,error_cb:error_cb});};$.JsonRpcClient._batchObject.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params}});};$.JsonRpcClient._batchObject.prototype._execute=function(){var self=this;if(this._requests.length===0)return;var batch_request=[];var handlers={};var i=0;var call;var success_cb;var error_cb;var socket=self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);if(socket!==null){for(i=0;i0){data.params.useVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);dialog.setState($.verto.enum.state.recovering);break;case'verto.invite':if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.wantVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");break;}} +return{method:data.method};}else{switch(data.method){case'verto.punt':verto.purge();verto.logout();break;case'verto.event':var list=null;var key=null;if(data.params){key=data.params.eventChannel;} +if(key){list=verto.eventSUBS[key];if(!list){list=verto.eventSUBS[key.split(".")[0]];}} +if(!list&&key&&key===verto.sessid){if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.pvtEvent,data.params);}}else if(!list&&key&&verto.dialogs[key]){verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent,data.params);}else if(!list){if(!key){key="UNDEFINED";} +console.error("UNSUBBED or invalid EVENT "+key+" IGNORED");}else{for(var i in list){var sub=list[i];if(!sub||!sub.ready){console.error("invalid EVENT for "+key+" IGNORED");}else if(sub.handler){sub.handler(verto,data.params,sub.userData);}else if(verto.callbacks.onEvent){verto.callbacks.onEvent(verto,data.params,sub.userData);}else{console.log("EVENT:",data.params);}}} +break;case"verto.info":if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.info,data.params.msg);} +console.debug("MESSAGE from: "+data.params.msg.from,data.params.msg.body);break;case'verto.clientReady':if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.clientReady,data.params);} +console.debug("CLIENT READY",data.params);break;default:console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}};var del_array=function(array,name){var r=[];var len=array.length;for(var i=0;i=array.length){array.push(name);}else{var x=0;var n=[];var len=array.length;for(var i=0;i":"\n");});return str;};};$.verto.liveArray=function(verto,context,name,config){var la=this;var lastSerno=0;var binding=null;var user_obj=config.userObj;var local=false;hashArray.call(la);la._add=la.add;la._del=la.del;la._reorder=la.reorder;la._clear=la.clear;la.context=context;la.name=name;la.user_obj=user_obj;la.verto=verto;la.broadcast=function(channel,obj){verto.broadcast(channel,obj);};la.errs=0;la.clear=function(){la._clear();lastSerno=0;if(la.onChange){la.onChange(la,{action:"clear"});}};la.checkSerno=function(serno){if(serno<0){return true;} +if(lastSerno>0&&serno!=(lastSerno+1)){if(la.onErr){la.onErr(la,{lastSerno:lastSerno,serno:serno});} +la.errs++;console.debug(la.errs);if(la.errs<3){la.bootstrap(la.user_obj);} +return false;}else{lastSerno=serno;return true;}};la.reorder=function(serno,a){if(la.checkSerno(serno)){la._reorder(a);if(la.onChange){la.onChange(la,{serno:serno,action:"reorder"});}}};la.init=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(la.onChange){la.onChange(la,{serno:serno,action:"init",index:index,key:key,data:val});}}};la.bootObj=function(serno,val){if(la.checkSerno(serno)){for(var i in val){la._add(val[i][0],val[i][1]);} +if(la.onChange){la.onChange(la,{serno:serno,action:"bootObj",data:val,redraw:true});}}};la.add=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){var redraw=la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"add",index:index,key:key,data:val,redraw:redraw});}}};la.modify=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"modify",key:key,data:val,index:index});}}};la.del=function(serno,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(index===null||index<0||index===undefined){index=la.indexOf(key);} +var ok=la._del(key);if(ok&&la.onChange){la.onChange(la,{serno:serno,action:"del",key:key,index:index});}}};var eventHandler=function(v,e,la){var packet=e.data;if(packet.name!=la.name){return;} +switch(packet.action){case"init":la.init(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"bootObj":la.bootObj(packet.wireSerno,packet.data);break;case"add":la.add(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"modify":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.modify(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);} +break;case"del":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.del(packet.wireSerno,packet.hashKey,packet.arrIndex);} +break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,packet.order);break;default:if(la.checkSerno(packet.wireSerno)){if(la.onChange){la.onChange(la,{serno:packet.wireSerno,action:packet.action,data:packet.data});}} +break;}};if(la.context){binding=la.verto.subscribe(la.context,{handler:eventHandler,userData:la,subParams:config.subParams});} +la.destroy=function(){la._clear();la.verto.unsubscribe(binding);};la.sendCommand=function(cmd,obj){var self=la;self.broadcast(self.context,{liveArray:{command:cmd,context:self.context,name:self.name,obj:obj}});};la.bootstrap=function(obj){var self=la;la.sendCommand("bootstrap",obj);};la.changepage=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"changepage",context:la.context,name:la.name,obj:obj}});};la.heartbeat=function(obj){var self=la;var callback=function(){self.heartbeat.call(self,obj);};self.broadcast(self.context,{liveArray:{command:"heartbeat",context:self.context,name:self.name,obj:obj}});self.hb_pid=setTimeout(callback,30000);};la.bootstrap(la.user_obj);};$.verto.liveTable=function(verto,context,name,jq,config){var dt;var la=new $.verto.liveArray(verto,context,name,{subParams:config.subParams});var lt=this;lt.liveArray=la;lt.dataTable=dt;lt.verto=verto;lt.destroy=function(){if(dt){dt.fnDestroy();} +if(la){la.destroy();} +dt=null;la=null;};la.onErr=function(obj,args){console.error("Error: ",obj,args);};function genRow(data){if(typeof(data[4])==="string"&&data[4].indexOf("{")>-1){var tmp=$.parseJSON(data[4]);data[4]=tmp.oldStatus;data[5]=null;} +return data;} +function genArray(obj){var data=obj.asArray();for(var i in data){data[i]=genRow(data[i]);} +return data;} +la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;} +config.aoColumns=[];for(var i in args.data){config.aoColumns.push({"sTitle":args.data[i]});}} +dt=jq.dataTable(config);} +if(dt&&(args.action=="del"||args.action=="modify")){index=args.index;if(index===undefined&&args.key){index=la.indexOf(args.key);} +if(index===undefined){console.error("INVALID PACKET Missing INDEX\n",args);return;}} +if(config.onChange){config.onChange(obj,args);} +try{switch(args.action){case"bootObj":if(!args.data){console.error("missing data");return;} +dt.fnClearTable();dt.fnAddData(genArray(obj));dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;} +if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(genArray(obj));}else{dt.fnAddData(genRow(args.data));} +dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;} +dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;} +if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.infoChannel,{handler:function(v,e){if(typeof(conf.params.infoCallback)==="function"){conf.params.infoCallback(v,e);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);} +if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);} +if(conf.params.laData.infoChannel){conf.verto.unsubscribe(conf.params.laData.infoChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';} +if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-res-id",parseInt(memberID),"presenter");};$.verto.conf.prototype.videoFloor=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-floor",parseInt(memberID),"force");};$.verto.conf.prototype.banner=function(memberID,text){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-banner",parseInt(memberID),escape(text));};$.verto.conf.prototype.volumeDown=function(memberID){this.modCommand("volume_out",parseInt(memberID),"down");};$.verto.conf.prototype.volumeUp=function(memberID){this.modCommand("volume_out",parseInt(memberID),"up");};$.verto.conf.prototype.gainDown=function(memberID){this.modCommand("volume_in",parseInt(memberID),"down");};$.verto.conf.prototype.gainUp=function(memberID){this.modCommand("volume_in",parseInt(memberID),"up");};$.verto.conf.prototype.transfer=function(memberID,exten){this.modCommand("transfer",parseInt(memberID),exten);};$.verto.conf.prototype.sendChat=function(message,type){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};} +$.verto.modfuncs={};$.verto.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;confMan.canvasCount=confMan.params.laData.canvasCount;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="

"+""+""+""+""+ +(confMan.params.hasVid?"":"")+"

";jq.html(html);$.verto.modfuncs.change_video_layout=function(id,canvas_id){var val=$("#"+id+" option:selected").text();if(val!=="none"){confMan.modCommand("vid-layout",null,[val,canvas_id]);}};if(confMan.params.hasVid){for(var j=0;j
"+"Video Layout Canvas "+(j+1)+" "+"

";jq.append(vlhtml);} +$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});} +$("#"+play_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("play",null,file);}});$("#"+stop_id).click(function(){confMan.modCommand("stop",null,"all");});$("#"+recording_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("recording",null,["start",file]);}});$("#"+rec_stop_id).click(function(){confMan.modCommand("recording",null,["stop","all"]);});} +function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var canvas_in_next_id="canvas_in_next_"+x;var canvas_in_prev_id="canvas_in_prev_"+x;var canvas_out_next_id="canvas_out_next_"+x;var canvas_out_prev_id="canvas_out_prev_"+x;var canvas_in_set_id="canvas_in_set_"+x;var canvas_out_set_id="canvas_out_set_"+x;var layer_set_id="layer_set_"+x;var layer_next_id="layer_next_"+x;var layer_prev_id="layer_prev_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var gainup_id="gain_in_up"+x;var gaindn_id="gain_in_dn"+x;var volup_id="vol_in_up"+x;var voldn_id="vol_in_dn"+x;var transfer_id="transfer"+x;var html="
";html+="General Controls
";html+=""+""+""+""+""+""+"";if(confMan.params.hasVid){html+="

Video Controls
";html+=""+""+""+"";if(confMan.canvasCount>1){html+="

Canvas Controls
"+""+""+""+"
"+""+""+"";} +html+="
"+""+""+""+"
";} +jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();} +jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});} +$("#"+gainup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+gaindn_id).click(function(){confMan.modCommand("volume_in",x,"down");});$("#"+volup_id).click(function(){confMan.modCommand("volume_out",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_out",x,"down");});return html;} +var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.infoChannel,{handler:function(v,e){if(typeof(confMan.params.infoCallback)==="function"){confMan.params.infoCallback(v,e);}}});verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready

");}else{$(confMan.params.mainModID).html("");} +verto.subscribe(confMan.params.laData.modChannel,{handler:function(v,e){if(confMan.params.onBroadcast){confMan.params.onBroadcast(verto,confMan,e.data);} +if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;jb)?1:-1));});for(var i in options){$(vlselect_id).append(new Option(options[i],options[i]));x++;}} +if(x){$(vlselect_id).selectmenu('refresh',true);}else{$(vlayout_id).hide();}}}else{if(!confMan.destroyed&&confMan.params.displayID){$(confMan.params.displayID).html(e.data.response+"

");if(confMan.lastTimeout){clearTimeout(confMan.lastTimeout);confMan.lastTimeout=0;} +confMan.lastTimeout=setTimeout(function(){$(confMan.params.displayID).html(confMan.destroyed?"":"Moderator Controls Ready

");},4000);}}}});if(confMan.params.hasVid){confMan.modCommand("list-videoLayouts",null,null);}} +var row_callback=null;if(confMan.params.laData.role==="moderator"){row_callback=function(nRow,aData,iDisplayIndex,iDisplayIndexFull){if(!aData[5]){var $row=$('td:eq(5)',nRow);genControls($row,aData);if(confMan.params.onLaRow){confMan.params.onLaRow(verto,confMan,$row,aData);}}};} +confMan.lt=new $.verto.liveTable(verto,confMan.params.laData.laChannel,confMan.params.laData.laName,$(confMan.params.tableID),{subParams:{callID:confMan.params.dialog?confMan.params.dialog.callID:null},"onChange":function(obj,args){$(confMan.params.statusID).text("Conference Members: "+" ("+obj.arrayLen()+" Total)");if(confMan.params.onLaChange){confMan.params.onLaChange(verto,confMan,$.verto.enum.confEvent.laChange,obj,args);}},"aaData":[],"aoColumns":[{"sTitle":"ID","sWidth":"50"},{"sTitle":"Number","sWidth":"250"},{"sTitle":"Name","sWidth":"250"},{"sTitle":"Codec","sWidth":"100"},{"sTitle":"Status","sWidth":confMan.params.hasVid?"200px":"150px"},{"sTitle":atitle,"sWidth":awidth,}],"bAutoWidth":true,"bDestroy":true,"bSort":false,"bInfo":false,"bFilter":false,"bLengthChange":false,"bPaginate":false,"iDisplayLength":1400,"oLanguage":{"sEmptyTable":"The Conference is Empty....."},"fnRowCallback":row_callback});};$.verto.confMan.prototype.modCommand=function(cmd,id,value){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.confMan.prototype.sendChat=function(message,type){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};$.verto.confMan.prototype.destroy=function(){var confMan=this;confMan.destroyed=true;if(confMan.lt){confMan.lt.destroy();} +if(confMan.params.laData.chatChannel){confMan.verto.unsubscribe(confMan.params.laData.chatChannel);} +if(confMan.params.laData.modChannel){confMan.verto.unsubscribe(confMan.params.laData.modChannel);} +if(confMan.params.mainModID){$(confMan.params.mainModID).html("");}};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,screenShare:false,useCamera:false,useMic:verto.options.deviceParams.useMic,useMicLabel:verto.options.deviceParams.useMicLabel,useSpeak:verto.options.deviceParams.useSpeak,tag:verto.options.tag,localTag:verto.options.localTag,login:verto.options.login,videoParams:verto.options.videoParams,useStream:verto.options.useStream,},params);if(!dialog.params.screenShare){dialog.params.useCamera=verto.options.deviceParams.useCamera;dialog.params.useCameraLabel=verto.options.deviceParams.useCameraLabel;} +dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;dialog.screenShare=params.screenShare||false;dialog.useCamera=dialog.params.useCamera;dialog.useCameraLabel=dialog.params.useCameraLabel;dialog.useMic=dialog.params.useMic;dialog.useMicLabel=dialog.params.useMicLabel;dialog.useSpeak=dialog.params.useSpeak;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();} +if(typeof(dialog.params.tag)==="function"){dialog.params.tag=dialog.params.tag();} +if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}} +if(dialog.params.localTag){dialog.localVideo=document.getElementById(dialog.params.localTag);} +dialog.verto.dialogs[dialog.callID]=dialog;var RTCcallbacks={};if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.params.display_direction==="outbound"){dialog.params.remote_caller_id_name=dialog.params.caller_id_name;dialog.params.remote_caller_id_number=dialog.params.caller_id_number;}else{dialog.params.remote_caller_id_name=dialog.params.callee_id_name;dialog.params.remote_caller_id_number=dialog.params.callee_id_number;} +if(!dialog.params.remote_caller_id_name){dialog.params.remote_caller_id_name="Nobody";} +if(!dialog.params.remote_caller_id_number){dialog.params.remote_caller_id_number="UNKNOWN";} +RTCcallbacks.onMessage=function(rtc,msg){console.debug(msg);};RTCcallbacks.onAnswerSDP=function(rtc,sdp){console.error("answer sdp",sdp);};}else{dialog.params.remote_caller_id_name="Outbound Call";dialog.params.remote_caller_id_number=dialog.params.destination_number;} +RTCcallbacks.onICESDP=function(rtc){console.log("RECV "+rtc.type+" SDP",rtc.mediaData.SDP);if(dialog.state==$.verto.enum.state.requesting||dialog.state==$.verto.enum.state.answering||dialog.state==$.verto.enum.state.active){location.reload();return;} +if(rtc.type=="offer"){if(dialog.state==$.verto.enum.state.active){dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.attach",{sdp:rtc.mediaData.SDP});}else{dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.invite",{sdp:rtc.mediaData.SDP});}}else{dialog.setState($.verto.enum.state.answering);dialog.sendMethod(dialog.attach?"verto.attach":"verto.answer",{sdp:dialog.rtc.mediaData.SDP});}};RTCcallbacks.onICE=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.candidate);return;}};RTCcallbacks.onStream=function(rtc,stream){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onGranted==='function'){dialog.callbacks.permissionCallback.onGranted(stream);} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onGranted==='function'){dialog.verto.options.permissionCallback.onGranted(stream);} +console.log("stream started");};RTCcallbacks.onRemoteStream=function(rtc,stream){if(typeof dialog.callbacks.onRemoteStream==='function'){dialog.callbacks.onRemoteStream(stream,dialog);} +console.log("remote stream started");};RTCcallbacks.onError=function(e){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onDenied==='function'){dialog.callbacks.permissionCallback.onDenied();} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onDenied==='function'){dialog.verto.options.permissionCallback.onDenied();} +console.error("ERROR:",e);dialog.hangup({cause:"Device or Permission Error"});};dialog.rtc=new $.FSRTC({callbacks:RTCcallbacks,localVideo:dialog.screenShare?null:dialog.localVideo,useVideo:dialog.params.useVideo?dialog.videoStream:null,useAudio:dialog.audioStream,useStereo:dialog.params.useStereo,videoParams:dialog.params.videoParams,audioParams:verto.options.audioParams,iceServers:verto.options.iceServers,screenShare:dialog.screenShare,useCamera:dialog.useCamera,useCameraLabel:dialog.useCameraLabel,useMic:dialog.useMic,useMicLabel:dialog.useMicLabel,useSpeak:dialog.useSpeak,turnServer:verto.options.turnServer,useStream:dialog.params.useStream});dialog.rtc.verto=dialog.verto;if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.attach){dialog.answer();}else{dialog.ring();}}};$.verto.dialog.prototype.invite=function(){var dialog=this;dialog.rtc.call();};$.verto.dialog.prototype.sendMethod=function(method,obj){var dialog=this;obj.dialogParams={};for(var i in dialog.params){if(i=="sdp"&&method!="verto.invite"&&method!="verto.attach"){continue;} +if((obj.noDialogParams&&i!="callID")){continue;} +obj.dialogParams[i]=dialog.params[i];} +delete obj.noDialogParams;dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,true,e);},function(e){dialog.processReply(method,false,e);});};function checkStateChange(oldS,newS){if(newS==$.verto.enum.state.purge||$.verto.enum.states[oldS.name][newS.name]){return true;} +return false;} +function find_name(id){for(var i in $.verto.audioOutDevices){var source=$.verto.audioOutDevices[i];if(source.id===id){return(source.label);}} +return id;} +$.verto.dialog.prototype.setAudioPlaybackDevice=function(sinkId,callback,arg){var dialog=this;var element=dialog.audioStream;if(typeof element.sinkId!=='undefined'){var devname=find_name(sinkId);console.info("Dialog: "+dialog.callID+" Setting speaker:",element,devname);element.setSinkId(sinkId).then(function(){console.log("Dialog: "+dialog.callID+' Success, audio output device attached: '+sinkId);if(callback){callback(true,devname,arg);}}).catch(function(error){var errorMessage=error;if(error.name==='SecurityError'){errorMessage="Dialog: "+dialog.callID+' You need to use HTTPS for selecting audio output '+'device: '+error;} +if(callback){callback(false,null,arg);} +console.error(errorMessage);});}else{console.warn("Dialog: "+dialog.callID+' Browser does not support output device selection.');if(callback){callback(false,null,arg);}}} +$.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();} +if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;} +console.log("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);} +switch(dialog.state){case $.verto.enum.state.early:case $.verto.enum.state.active:var speaker=dialog.useSpeak;console.info("Using Speaker: ",speaker);if(speaker&&speaker!=="any"&&speaker!=="none"){setTimeout(function(){dialog.setAudioPlaybackDevice(speaker);},500);} +break;case $.verto.enum.state.trying:setTimeout(function(){if(dialog.state==$.verto.enum.state.trying){dialog.setState($.verto.enum.state.hangup);}},30000);break;case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});} +dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:if(typeof(dialog.verto.options.tag)==="function"){$('#'+dialog.params.tag).remove();} +delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();} +break;} +return true;};$.verto.dialog.prototype.processReply=function(method,success,e){var dialog=this;switch(method){case"verto.answer":case"verto.attach":if(success){dialog.setState($.verto.enum.state.active);}else{dialog.hangup();} +break;case"verto.invite":if(success){dialog.setState($.verto.enum.state.trying);}else{dialog.setState($.verto.enum.state.destroy);} +break;case"verto.bye":dialog.hangup();break;case"verto.modify":if(e.holdState){if(e.holdState=="held"){if(dialog.state!=$.verto.enum.state.held){dialog.setState($.verto.enum.state.held);}}else if(e.holdState=="active"){if(dialog.state!=$.verto.enum.state.active){dialog.setState($.verto.enum.state.active);}}} +if(success){} +break;default:break;}};$.verto.dialog.prototype.hangup=function(params){var dialog=this;if(params){if(params.causeCode){dialog.causeCode=params.causeCode;} +if(params.cause){dialog.cause=params.cause;}} +if(!dialog.cause&&!dialog.causeCode){dialog.cause="NORMAL_CLEARING";} +if(dialog.state.val>=$.verto.enum.state.new.val&&dialog.state.val<$.verto.enum.state.hangup.val){dialog.setState($.verto.enum.state.hangup);}else if(dialog.state.val<$.verto.enum.state.destroy){dialog.setState($.verto.enum.state.destroy);}};$.verto.dialog.prototype.stopRinging=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.stop();}};$.verto.dialog.prototype.indicateRing=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.attr("src",dialog.verto.options.ringFile)[0].play();setTimeout(function(){dialog.stopRinging();if(dialog.state==$.verto.enum.state.ringing){dialog.indicateRing();}},dialog.verto.options.ringSleep);}};$.verto.dialog.prototype.ring=function(){var dialog=this;dialog.setState($.verto.enum.state.ringing);dialog.indicateRing();};$.verto.dialog.prototype.useVideo=function(on){var dialog=this;dialog.params.useVideo=on;if(on){dialog.videoStream=dialog.audioStream;}else{dialog.videoStream=null;} +dialog.rtc.useVideo(dialog.videoStream,dialog.localVideo);};$.verto.dialog.prototype.setMute=function(what){var dialog=this;return dialog.rtc.setMute(what);};$.verto.dialog.prototype.getMute=function(){var dialog=this;return dialog.rtc.getMute();};$.verto.dialog.prototype.setVideoMute=function(what){var dialog=this;return dialog.rtc.setVideoMute(what);};$.verto.dialog.prototype.getVideoMute=function(){var dialog=this;return dialog.rtc.getVideoMute();};$.verto.dialog.prototype.useStereo=function(on){var dialog=this;dialog.params.useStereo=on;dialog.rtc.useStereo(on);};$.verto.dialog.prototype.dtmf=function(digits){var dialog=this;if(digits){dialog.sendMethod("verto.info",{dtmf:digits});}};$.verto.dialog.prototype.rtt=function(obj){var dialog=this;var pobj={};if(!obj){return false;} +pobj.code=obj.code;pobj.chars=obj.chars;if(pobj.chars||pobj.code){dialog.sendMethod("verto.info",{txt:obj,noDialogParams:true});}};$.verto.dialog.prototype.transfer=function(dest,params){var dialog=this;if(dest){dialog.sendMethod("verto.modify",{action:"transfer",destination:dest,params:params});}};$.verto.dialog.prototype.replace=function(replaceCallID,params){var dialog=this;if(replaceCallID){dialog.sendMethod("verto.modify",{action:"replace",replaceCallID:replaceCallID,params:params});}};$.verto.dialog.prototype.hold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"hold",params:params});};$.verto.dialog.prototype.unhold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"unhold",params:params});};$.verto.dialog.prototype.toggleHold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"toggleHold",params:params});};$.verto.dialog.prototype.message=function(msg){var dialog=this;var err=0;msg.from=dialog.params.login;if(!msg.to){console.error("Missing To");err++;} +if(!msg.body){console.error("Missing Body");err++;} +if(err){return false;} +dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(!params){params={};} +params.sdp=dialog.params.sdp;if(params){if(params.useVideo){dialog.useVideo(true);} +dialog.params.callee_id_name=params.callee_id_name;dialog.params.callee_id_number=params.callee_id_number;if(params.useCamera){dialog.useCamera=params.useCamera;dialog.useCameraLabel=params.useCameraLabel;} +if(params.useMic){dialog.useMic=params.useMic;dialog.useMic=params.useMicLabel;} +if(params.useSpeak){dialog.useSpeak=params.useSpeak;}} +dialog.rtc.createAnswer(params);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(params){var dialog=this;dialog.gotAnswer=true;if(dialog.state.val>=$.verto.enum.state.active.val){return;} +if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{if(dialog.gotEarly){console.log("Dialog "+dialog.callID+" Got answer while still establishing early media, delaying...");}else{console.log("Dialog "+dialog.callID+" Answering Channel");dialog.rtc.answer(params.sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"ANSWER SDP",params.sdp);}}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" <":" <")+dialog.params.remote_caller_id_number+(enc?">":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;} +if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;} +dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(params){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;} +dialog.gotEarly=true;dialog.rtc.answer(params.sdp,function(){console.log("Dialog "+dialog.callID+"Establishing early media");dialog.setState($.verto.enum.state.early);if(dialog.gotAnswer){console.log("Dialog "+dialog.callID+"Answering Channel");dialog.setState($.verto.enum.state.active);}},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"EARLY SDP",params.sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,recovering:1,ringing:1,destroy:1,answering:1,hangup:1},requesting:{trying:1,hangup:1,active:1},recovering:{answering:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{answering:1,requesting:1,hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent clientReady");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$.verto.unloadJobs=[];var unloadEventName='beforeunload';var iOS=['iPad','iPhone','iPod'].indexOf(navigator.platform)>=0;if(iOS){unloadEventName='pagehide';} +$(window).bind(unloadEventName,function(){for(var f in $.verto.unloadJobs){$.verto.unloadJobs[f]();} +if($.verto.haltClosure) +return $.verto.haltClosure();for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.purge();verto.logout();}} +return $.verto.warnOnUnload;});$.verto.videoDevices=[];$.verto.audioInDevices=[];$.verto.audioOutDevices=[];var checkDevices=function(runtime){console.info("enumerating devices");var aud_in=[],aud_out=[],vid=[];var has_video=0,has_audio=0;var Xstream;function gotDevices(deviceInfos){for(var i=0;i!==deviceInfos.length;++i){var deviceInfo=deviceInfos[i];var text="";console.log(deviceInfo);console.log(deviceInfo.kind+": "+deviceInfo.label+" id = "+deviceInfo.deviceId);if(deviceInfo.kind==='audioinput'){text=deviceInfo.label||'microphone '+(aud_in.length+1);aud_in.push({id:deviceInfo.deviceId,kind:"audio_in",label:text});}else if(deviceInfo.kind==='audiooutput'){text=deviceInfo.label||'speaker '+(aud_out.length+1);aud_out.push({id:deviceInfo.deviceId,kind:"audio_out",label:text});}else if(deviceInfo.kind==='videoinput'){text=deviceInfo.label||'camera '+(vid.length+1);vid.push({id:deviceInfo.deviceId,kind:"video",label:text});}else{console.log('Some other kind of source/device: ',deviceInfo);}} +$.verto.videoDevices=vid;$.verto.audioInDevices=aud_in;$.verto.audioOutDevices=aud_out;console.info("Audio IN Devices",$.verto.audioInDevices);console.info("Audio Out Devices",$.verto.audioOutDevices);console.info("Video Devices",$.verto.videoDevices);if(Xstream){Xstream.getTracks().forEach(function(track){track.stop();});} +if(runtime){runtime(true);}} +function handleError(error){console.log('device enumeration error: ',error);if(runtime)runtime(false);} +function checkTypes(devs){for(var i=0;i!==devs.length;++i){if(devs[i].kind==='audioinput'){has_audio++;}else if(devs[i].kind==='videoinput'){has_video++;}} +navigator.getUserMedia({audio:(has_audio>0?true:false),video:(has_video>0?true:false)},function(stream){Xstream=stream;navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);},function(err){console.log("The following error occurred: "+err.name);});} +navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError);};$.verto.refreshDevices=function(runtime){checkDevices(runtime);} +$.verto.init=function(obj,runtime){if(!obj){obj={};} +if(!obj.skipPermCheck&&!obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){checkDevices(runtime);},true,true);}else if(obj.skipPermCheck&&!obj.skipDeviceCheck){checkDevices(runtime);}else if(!obj.skipPermCheck&&obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){runtime(status);},true,true);}else{runtime(null);}} +$.verto.genUUID=function(){return generateGUID();}})(jQuery);(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter=f()}})(function(){var define,module,exports;return(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i0&&arguments[0]!==undefined?arguments[0]:{},window=_ref.window;var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{shimChrome:true,shimFirefox:true,shimEdge:true,shimSafari:true};var logging=utils.log;var browserDetails=utils.detectBrowser(window);var adapter={browserDetails:browserDetails,commonShim:commonShim,extractVersion:utils.extractVersion,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings};switch(browserDetails.browser){case'chrome':if(!chromeShim||!chromeShim.shimPeerConnection||!options.shimChrome){logging('Chrome shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming chrome.');adapter.browserShim=chromeShim;chromeShim.shimGetUserMedia(window);chromeShim.shimMediaStream(window);chromeShim.shimPeerConnection(window);chromeShim.shimOnTrack(window);chromeShim.shimAddTrackRemoveTrack(window);chromeShim.shimGetSendersWithDtmf(window);chromeShim.shimSenderReceiverGetStats(window);chromeShim.fixNegotiationNeeded(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;case'firefox':if(!firefoxShim||!firefoxShim.shimPeerConnection||!options.shimFirefox){logging('Firefox shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming firefox.');adapter.browserShim=firefoxShim;firefoxShim.shimGetUserMedia(window);firefoxShim.shimPeerConnection(window);firefoxShim.shimOnTrack(window);firefoxShim.shimRemoveStream(window);firefoxShim.shimSenderGetStats(window);firefoxShim.shimReceiverGetStats(window);firefoxShim.shimRTCDataChannel(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'edge':if(!edgeShim||!edgeShim.shimPeerConnection||!options.shimEdge){logging('MS edge shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming edge.');adapter.browserShim=edgeShim;edgeShim.shimGetUserMedia(window);edgeShim.shimGetDisplayMedia(window);edgeShim.shimPeerConnection(window);edgeShim.shimReplaceTrack(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'safari':if(!safariShim||!options.shimSafari){logging('Safari shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming safari.');adapter.browserShim=safariShim;safariShim.shimRTCIceServerUrls(window);safariShim.shimCreateOfferLegacy(window);safariShim.shimCallbacksAPI(window);safariShim.shimLocalStreamsAPI(window);safariShim.shimRemoteStreamsAPI(window);safariShim.shimTrackEventTransceiver(window);safariShim.shimGetUserMedia(window);commonShim.shimRTCIceCandidate(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;default:logging('Unsupported browser!');break;} +return adapter;}},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimMediaStream=shimMediaStream;exports.shimOnTrack=shimOnTrack;exports.shimGetSendersWithDtmf=shimGetSendersWithDtmf;exports.shimSenderReceiverGetStats=shimSenderReceiverGetStats;exports.shimAddTrackRemoveTrackWithNative=shimAddTrackRemoveTrackWithNative;exports.shimAddTrackRemoveTrack=shimAddTrackRemoveTrack;exports.shimPeerConnection=shimPeerConnection;exports.fixNegotiationNeeded=fixNegotiationNeeded;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function walkStats(stats,base,resultSet){if(!base||resultSet.has(base.id)){return;} +resultSet.set(base.id,base);Object.keys(base).forEach(function(name){if(name.endsWith('Id')){walkStats(stats,stats.get(base[name]),resultSet);}else if(name.endsWith('Ids')){base[name].forEach(function(id){walkStats(stats,stats.get(id),resultSet);});}});} +function filterStats(result,track,outbound){var streamStatsType=outbound?'outbound-rtp':'inbound-rtp';var filteredResult=new Map();if(track===null){return filteredResult;} +var trackStats=[];result.forEach(function(value){if(value.type==='track'&&value.trackIdentifier===track.id){trackStats.push(value);}});trackStats.forEach(function(trackStat){result.forEach(function(stats){if(stats.type===streamStatsType&&stats.trackId===trackStat.id){walkStats(result,stats,filteredResult);}});});return filteredResult;} +function shimMediaStream(window){window.MediaStream=window.MediaStream||window.webkitMediaStream;} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('ontrack'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'ontrack',{get:function get(){return this._ontrack;},set:function set(f){if(this._ontrack){this.removeEventListener('track',this._ontrack);} +this.addEventListener('track',this._ontrack=f);},enumerable:true,configurable:true});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var _this=this;if(!this._ontrackpoly){this._ontrackpoly=function(e){e.stream.addEventListener('addtrack',function(te){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===te.track.id;});}else{receiver={track:te.track};} +var event=new Event('track');event.track=te.track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});e.stream.getTracks().forEach(function(track){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===track.id;});}else{receiver={track:track};} +var event=new Event('track');event.track=track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});};this.addEventListener('addstream',this._ontrackpoly);} +return origSetRemoteDescription.apply(this,arguments);};}else{utils.wrapPeerConnectionEvent(window,'track',function(e){if(!e.transceiver){Object.defineProperty(e,'transceiver',{value:{receiver:e.receiver}});} +return e;});}} +function shimGetSendersWithDtmf(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('getSenders'in window.RTCPeerConnection.prototype)&&'createDTMFSender'in window.RTCPeerConnection.prototype){var shimSenderWithDtmf=function shimSenderWithDtmf(pc,track){return{track:track,get dtmf(){if(this._dtmf===undefined){if(track.kind==='audio'){this._dtmf=pc.createDTMFSender(track);}else{this._dtmf=null;}} +return this._dtmf;},_pc:pc};};if(!window.RTCPeerConnection.prototype.getSenders){window.RTCPeerConnection.prototype.getSenders=function(){this._senders=this._senders||[];return this._senders.slice();};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){var sender=origAddTrack.apply(this,arguments);if(!sender){sender=shimSenderWithDtmf(this,track);this._senders.push(sender);} +return sender;};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){origRemoveTrack.apply(this,arguments);var idx=this._senders.indexOf(sender);if(idx!==-1){this._senders.splice(idx,1);}};} +var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this2=this;this._senders=this._senders||[];origAddStream.apply(this,[stream]);stream.getTracks().forEach(function(track){_this2._senders.push(shimSenderWithDtmf(_this2,track));});};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;this._senders=this._senders||[];origRemoveStream.apply(this,[stream]);stream.getTracks().forEach(function(track){var sender=_this3._senders.find(function(s){return s.track===track;});if(sender){_this3._senders.splice(_this3._senders.indexOf(sender),1);}});};}else if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&'getSenders'in window.RTCPeerConnection.prototype&&'createDTMFSender'in window.RTCPeerConnection.prototype&&window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;window.RTCPeerConnection.prototype.getSenders=function(){var _this4=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this4;});return senders;};Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=this._pc.createDTMFSender(this.track);}else{this._dtmf=null;}} +return this._dtmf;}});}} +function shimSenderReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender&&window.RTCRtpReceiver)){return;} +if(!('getStats'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this5=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this5;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){var sender=this;return this._pc.getStats().then(function(result){return(filterStats(result,sender.track,true));});};} +if(!('getStats'in window.RTCRtpReceiver.prototype)){var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this6=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this6;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){var receiver=this;return this._pc.getStats().then(function(result){return filterStats(result,receiver.track,false);});};} +if(!('getStats'in window.RTCRtpSender.prototype&&'getStats'in window.RTCRtpReceiver.prototype)){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof window.MediaStreamTrack){var track=arguments[0];var sender=void 0;var receiver=void 0;var err=void 0;this.getSenders().forEach(function(s){if(s.track===track){if(sender){err=true;}else{sender=s;}}});this.getReceivers().forEach(function(r){if(r.track===track){if(receiver){err=true;}else{receiver=r;}} +return r.track===track;});if(err||sender&&receiver){return Promise.reject(new DOMException('There are more than one sender or receiver for the track.','InvalidAccessError'));}else if(sender){return sender.getStats();}else if(receiver){return receiver.getStats();} +return Promise.reject(new DOMException('There is no sender or receiver for the track.','InvalidAccessError'));} +return origGetStats.apply(this,arguments);};} +function shimAddTrackRemoveTrackWithNative(window){window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this7=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};return Object.keys(this._shimmedLocalStreams).map(function(streamId){return _this7._shimmedLocalStreams[streamId][0];});};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(!stream){return origAddTrack.apply(this,arguments);} +this._shimmedLocalStreams=this._shimmedLocalStreams||{};var sender=origAddTrack.apply(this,arguments);if(!this._shimmedLocalStreams[stream.id]){this._shimmedLocalStreams[stream.id]=[stream,sender];}else if(this._shimmedLocalStreams[stream.id].indexOf(sender)===-1){this._shimmedLocalStreams[stream.id].push(sender);} +return sender;};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this8=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this8.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});var existingSenders=this.getSenders();origAddStream.apply(this,arguments);var newSenders=this.getSenders().filter(function(newSender){return existingSenders.indexOf(newSender)===-1;});this._shimmedLocalStreams[stream.id]=[stream].concat(newSenders);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._shimmedLocalStreams=this._shimmedLocalStreams||{};delete this._shimmedLocalStreams[stream.id];return origRemoveStream.apply(this,arguments);};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this9=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};if(sender){Object.keys(this._shimmedLocalStreams).forEach(function(streamId){var idx=_this9._shimmedLocalStreams[streamId].indexOf(sender);if(idx!==-1){_this9._shimmedLocalStreams[streamId].splice(idx,1);} +if(_this9._shimmedLocalStreams[streamId].length===1){delete _this9._shimmedLocalStreams[streamId];}});} +return origRemoveTrack.apply(this,arguments);};} +function shimAddTrackRemoveTrack(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(window.RTCPeerConnection.prototype.addTrack&&browserDetails.version>=65){return shimAddTrackRemoveTrackWithNative(window);} +var origGetLocalStreams=window.RTCPeerConnection.prototype.getLocalStreams;window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this10=this;var nativeStreams=origGetLocalStreams.apply(this);this._reverseStreams=this._reverseStreams||{};return nativeStreams.map(function(stream){return _this10._reverseStreams[stream.id];});};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this11=this;this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this11.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});if(!this._reverseStreams[stream.id]){var newStream=new window.MediaStream(stream.getTracks());this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;stream=newStream;} +origAddStream.apply(this,[stream]);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};origRemoveStream.apply(this,[this._streams[stream.id]||stream]);delete this._reverseStreams[this._streams[stream.id]?this._streams[stream.id].id:stream.id];delete this._streams[stream.id];};window.RTCPeerConnection.prototype.addTrack=function(track,stream){var _this12=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +var streams=[].slice.call(arguments,1);if(streams.length!==1||!streams[0].getTracks().find(function(t){return t===track;})){throw new DOMException('The adapter.js addTrack polyfill only supports a single '+' stream which is associated with the specified track.','NotSupportedError');} +var alreadyExists=this.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');} +this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};var oldStream=this._streams[stream.id];if(oldStream){oldStream.addTrack(track);Promise.resolve().then(function(){_this12.dispatchEvent(new Event('negotiationneeded'));});}else{var newStream=new window.MediaStream([track]);this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;this.addStream(newStream);} +return this.getSenders().find(function(s){return s.track===track;});};function replaceInternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(internalStream.id,'g'),externalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +function replaceExternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(externalStream.id,'g'),internalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +['createOffer','createAnswer'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var _this13=this;var args=arguments;var isLegacyCall=arguments.length&&typeof arguments[0]==='function';if(isLegacyCall){return nativeMethod.apply(this,[function(description){var desc=replaceInternalStreamId(_this13,description);args[0].apply(null,[desc]);},function(err){if(args[1]){args[1].apply(null,err);}},arguments[2]]);} +return nativeMethod.apply(this,arguments).then(function(description){return replaceInternalStreamId(_this13,description);});};});var origSetLocalDescription=window.RTCPeerConnection.prototype.setLocalDescription;window.RTCPeerConnection.prototype.setLocalDescription=function(){if(!arguments.length||!arguments[0].type){return origSetLocalDescription.apply(this,arguments);} +arguments[0]=replaceExternalStreamId(this,arguments[0]);return origSetLocalDescription.apply(this,arguments);};var origLocalDescription=Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype,'localDescription');Object.defineProperty(window.RTCPeerConnection.prototype,'localDescription',{get:function get(){var description=origLocalDescription.get.apply(this);if(description.type===''){return description;} +return replaceInternalStreamId(this,description);}});window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this14=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +if(!sender._pc){throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.','TypeError');} +var isLocal=sender._pc===this;if(!isLocal){throw new DOMException('Sender was not created by this connection.','InvalidAccessError');} +this._streams=this._streams||{};var stream=void 0;Object.keys(this._streams).forEach(function(streamid){var hasTrack=_this14._streams[streamid].getTracks().find(function(track){return sender.track===track;});if(hasTrack){stream=_this14._streams[streamid];}});if(stream){if(stream.getTracks().length===1){this.removeStream(this._reverseStreams[stream.id]);}else{stream.removeTrack(sender.track);} +this.dispatchEvent(new Event('negotiationneeded'));}};} +function shimPeerConnection(window){if(!window.RTCPeerConnection&&window.webkitRTCPeerConnection){window.RTCPeerConnection=window.webkitRTCPeerConnection;} +if(!window.RTCPeerConnection){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,successCallback,errorCallback){var _this15=this;var args=arguments;if(arguments.length>0&&typeof selector==='function'){return origGetStats.apply(this,arguments);} +if(origGetStats.length===0&&(arguments.length===0||typeof arguments[0]!=='function')){return origGetStats.apply(this,[]);} +var fixChromeStats_=function fixChromeStats_(response){var standardReport={};var reports=response.result();reports.forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:{localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[report.type]||report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name);});standardReport[standardStats.id]=standardStats;});return standardReport;};var makeMapStats=function makeMapStats(stats){return new Map(Object.keys(stats).map(function(key){return[key,stats[key]];}));};if(arguments.length>=2){var successCallbackWrapper_=function successCallbackWrapper_(response){args[1](makeMapStats(fixChromeStats_(response)));};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]]);} +return new Promise(function(resolve,reject){origGetStats.apply(_this15,[function(response){resolve(makeMapStats(fixChromeStats_(response)));},reject]);}).then(successCallback,errorCallback);};['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};} +function fixNegotiationNeeded(window){utils.wrapPeerConnectionEvent(window,'negotiationneeded',function(e){var pc=e.target;if(pc.signalingState!=='stable'){return;} +return e;});}},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,getSourceId){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +if(typeof getSourceId!=='function'){console.error('shimGetDisplayMedia: getSourceId argument is not '+'a function');return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){return getSourceId(constraints).then(function(sourceId){var widthSpecified=constraints.video&&constraints.video.width;var heightSpecified=constraints.video&&constraints.video.height;var frameRateSpecified=constraints.video&&constraints.video.frameRate;constraints.video={mandatory:{chromeMediaSource:'desktop',chromeMediaSourceId:sourceId,maxFrameRate:frameRateSpecified||3}};if(widthSpecified){constraints.video.mandatory.maxWidth=widthSpecified;} +if(heightSpecified){constraints.video.mandatory.maxHeight=heightSpecified;} +return window.navigator.mediaDevices.getUserMedia(constraints);});};}},{}],5:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +var logging=utils.log;function shimGetUserMedia(window){var navigator=window&&window.navigator;if(!navigator.mediaDevices){return;} +var browserDetails=utils.detectBrowser(window);var constraintsToChrome_=function constraintsToChrome_(c){if((typeof c==='undefined'?'undefined':_typeof(c))!=='object'||c.mandatory||c.optional){return c;} +var cc={};Object.keys(c).forEach(function(key){if(key==='require'||key==='advanced'||key==='mediaSource'){return;} +var r=_typeof(c[key])==='object'?c[key]:{ideal:c[key]};if(r.exact!==undefined&&typeof r.exact==='number'){r.min=r.max=r.exact;} +var oldname_=function oldname_(prefix,name){if(prefix){return prefix+name.charAt(0).toUpperCase()+name.slice(1);} +return name==='deviceId'?'sourceId':name;};if(r.ideal!==undefined){cc.optional=cc.optional||[];var oc={};if(typeof r.ideal==='number'){oc[oldname_('min',key)]=r.ideal;cc.optional.push(oc);oc={};oc[oldname_('max',key)]=r.ideal;cc.optional.push(oc);}else{oc[oldname_('',key)]=r.ideal;cc.optional.push(oc);}} +if(r.exact!==undefined&&typeof r.exact!=='number'){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_('',key)]=r.exact;}else{['min','max'].forEach(function(mix){if(r[mix]!==undefined){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_(mix,key)]=r[mix];}});}});if(c.advanced){cc.optional=(cc.optional||[]).concat(c.advanced);} +return cc;};var shimConstraints_=function shimConstraints_(constraints,func){if(browserDetails.version>=61){return func(constraints);} +constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&_typeof(constraints.audio)==='object'){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} +if(constraints&&_typeof(constraints.video)==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='undefined'?'undefined':_typeof(face))==='object'?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<66;if(face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment')&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches=void 0;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} +if(matches){return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return d.kind==='videoinput';});var dev=devices.find(function(d){return matches.some(function(match){return d.label.toLowerCase().includes(match);});});if(!dev&&devices.length&&matches.includes('back')){dev=devices[devices.length-1];} +if(dev){constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId};} +constraints.video=constraintsToChrome_(constraints.video);logging('chrome: '+JSON.stringify(constraints));return func(constraints);});}} +constraints.video=constraintsToChrome_(constraints.video);} +logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function shimError_(e){if(browserDetails.version>=64){return e;} +return{name:{PermissionDeniedError:'NotAllowedError',PermissionDismissedError:'NotAllowedError',InvalidStateError:'NotAllowedError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotAllowedError',MediaDeviceKillSwitchOn:'NotAllowedError',TabCaptureError:'AbortError',ScreenCaptureError:'AbortError',DeviceCaptureError:'AbortError'}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function toString(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function getUserMedia_(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){if(onError){onError(shimError_(e));}});});};navigator.getUserMedia=getUserMedia_.bind(navigator);var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length){stream.getTracks().forEach(function(track){track.stop();});throw new DOMException('','NotFoundError');} +return stream;},function(e){return Promise.reject(shimError_(e));});});};}},{"../utils.js":15}],6:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimRTCIceCandidate=shimRTCIceCandidate;exports.shimMaxMessageSize=shimMaxMessageSize;exports.shimSendThrowTypeError=shimSendThrowTypeError;exports.shimConnectionState=shimConnectionState;exports.removeAllowExtmapMixed=removeAllowExtmapMixed;var _sdp=require('sdp');var _sdp2=_interopRequireDefault(_sdp);var _utils=require('./utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function shimRTCIceCandidate(window){if(!window.RTCIceCandidate||window.RTCIceCandidate&&'foundation'in window.RTCIceCandidate.prototype){return;} +var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){if((typeof args==='undefined'?'undefined':_typeof(args))==='object'&&args.candidate&&args.candidate.indexOf('a=')===0){args=JSON.parse(JSON.stringify(args));args.candidate=args.candidate.substr(2);} +if(args.candidate&&args.candidate.length){var nativeCandidate=new NativeRTCIceCandidate(args);var parsedCandidate=_sdp2.default.parseCandidate(args.candidate);var augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment};};return augmentedCandidate;} +return new NativeRTCIceCandidate(args);};window.RTCIceCandidate.prototype=NativeRTCIceCandidate.prototype;utils.wrapPeerConnectionEvent(window,'icecandidate',function(e){if(e.candidate){Object.defineProperty(e,'candidate',{value:new window.RTCIceCandidate(e.candidate),writable:'false'});} +return e;});} +function shimMaxMessageSize(window){if(window.RTCSctpTransport||!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(!('sctp'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'sctp',{get:function get(){return typeof this._sctp==='undefined'?null:this._sctp;}});} +var sctpInDescription=function sctpInDescription(description){var sections=_sdp2.default.splitSections(description.sdp);sections.shift();return sections.some(function(mediaSection){var mLine=_sdp2.default.parseMLine(mediaSection);return mLine&&mLine.kind==='application'&&mLine.protocol.indexOf('SCTP')!==-1;});};var getRemoteFirefoxVersion=function getRemoteFirefoxVersion(description){var match=description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(match===null||match.length<2){return-1;} +var version=parseInt(match[1],10);return version!==version?-1:version;};var getCanSendMaxMessageSize=function getCanSendMaxMessageSize(remoteIsFirefox){var canSendMaxMessageSize=65536;if(browserDetails.browser==='firefox'){if(browserDetails.version<57){if(remoteIsFirefox===-1){canSendMaxMessageSize=16384;}else{canSendMaxMessageSize=2147483637;}}else if(browserDetails.version<60){canSendMaxMessageSize=browserDetails.version===57?65535:65536;}else{canSendMaxMessageSize=2147483637;}} +return canSendMaxMessageSize;};var getMaxMessageSize=function getMaxMessageSize(description,remoteIsFirefox){var maxMessageSize=65536;if(browserDetails.browser==='firefox'&&browserDetails.version===57){maxMessageSize=65535;} +var match=_sdp2.default.matchPrefix(description.sdp,'a=max-message-size:');if(match.length>0){maxMessageSize=parseInt(match[0].substr(19),10);}else if(browserDetails.browser==='firefox'&&remoteIsFirefox!==-1){maxMessageSize=2147483637;} +return maxMessageSize;};var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){this._sctp=null;if(sctpInDescription(arguments[0])){var isFirefox=getRemoteFirefoxVersion(arguments[0]);var canSendMMS=getCanSendMaxMessageSize(isFirefox);var remoteMMS=getMaxMessageSize(arguments[0],isFirefox);var maxMessageSize=void 0;if(canSendMMS===0&&remoteMMS===0){maxMessageSize=Number.POSITIVE_INFINITY;}else if(canSendMMS===0||remoteMMS===0){maxMessageSize=Math.max(canSendMMS,remoteMMS);}else{maxMessageSize=Math.min(canSendMMS,remoteMMS);} +var sctp={};Object.defineProperty(sctp,'maxMessageSize',{get:function get(){return maxMessageSize;}});this._sctp=sctp;} +return origSetRemoteDescription.apply(this,arguments);};} +function shimSendThrowTypeError(window){if(!(window.RTCPeerConnection&&'createDataChannel'in window.RTCPeerConnection.prototype)){return;} +function wrapDcSend(dc,pc){var origDataChannelSend=dc.send;dc.send=function(){var data=arguments[0];var length=data.length||data.size||data.byteLength;if(dc.readyState==='open'&&pc.sctp&&length>pc.sctp.maxMessageSize){throw new TypeError('Message too large (can send a maximum of '+pc.sctp.maxMessageSize+' bytes)');} +return origDataChannelSend.apply(dc,arguments);};} +var origCreateDataChannel=window.RTCPeerConnection.prototype.createDataChannel;window.RTCPeerConnection.prototype.createDataChannel=function(){var dataChannel=origCreateDataChannel.apply(this,arguments);wrapDcSend(dataChannel,this);return dataChannel;};utils.wrapPeerConnectionEvent(window,'datachannel',function(e){wrapDcSend(e.channel,e.target);return e;});} +function shimConnectionState(window){if(!window.RTCPeerConnection||'connectionState'in window.RTCPeerConnection.prototype){return;} +var proto=window.RTCPeerConnection.prototype;Object.defineProperty(proto,'connectionState',{get:function get(){return{completed:'connected',checking:'connecting'}[this.iceConnectionState]||this.iceConnectionState;},enumerable:true,configurable:true});Object.defineProperty(proto,'onconnectionstatechange',{get:function get(){return this._onconnectionstatechange||null;},set:function set(cb){if(this._onconnectionstatechange){this.removeEventListener('connectionstatechange',this._onconnectionstatechange);delete this._onconnectionstatechange;} +if(cb){this.addEventListener('connectionstatechange',this._onconnectionstatechange=cb);}},enumerable:true,configurable:true});['setLocalDescription','setRemoteDescription'].forEach(function(method){var origMethod=proto[method];proto[method]=function(){if(!this._connectionstatechangepoly){this._connectionstatechangepoly=function(e){var pc=e.target;if(pc._lastConnectionState!==pc.connectionState){pc._lastConnectionState=pc.connectionState;var newEvent=new Event('connectionstatechange',e);pc.dispatchEvent(newEvent);} +return e;};this.addEventListener('iceconnectionstatechange',this._connectionstatechangepoly);} +return origMethod.apply(this,arguments);};});} +function removeAllowExtmapMixed(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(browserDetails.browser==='chrome'&&browserDetails.version>=71){return;} +var nativeSRD=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(desc){if(desc&&desc.sdp&&desc.sdp.indexOf('\na=extmap-allow-mixed')!==-1){desc.sdp=desc.sdp.split('\n').filter(function(line){return line.trim()!=='a=extmap-allow-mixed';}).join('\n');} +return nativeSRD.apply(this,arguments);};}},{"./utils":15,"sdp":17}],7:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimPeerConnection=shimPeerConnection;exports.shimReplaceTrack=shimReplaceTrack;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);var _filtericeservers=require('./filtericeservers');var _rtcpeerconnectionShim=require('rtcpeerconnection-shim');var _rtcpeerconnectionShim2=_interopRequireDefault(_rtcpeerconnectionShim);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} +if(!window.RTCSessionDescription){window.RTCSessionDescription=function(args){return args;};} +if(browserDetails.version<15025){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,'enabled');Object.defineProperty(window.MediaStreamTrack.prototype,'enabled',{set:function set(value){origMSTEnabled.set.call(this,value);var ev=new Event('enabled');ev.enabled=value;this.dispatchEvent(ev);}});}} +if(window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=new window.RTCDtmfSender(this);}else if(this.track.kind==='video'){this._dtmf=null;}} +return this._dtmf;}});} +if(window.RTCDtmfSender&&!window.RTCDTMFSender){window.RTCDTMFSender=window.RTCDtmfSender;} +var RTCPeerConnectionShim=(0,_rtcpeerconnectionShim2.default)(window,browserDetails.version);window.RTCPeerConnection=function(config){if(config&&config.iceServers){config.iceServers=(0,_filtericeservers.filterIceServers)(config.iceServers,browserDetails.version);utils.log('ICE servers after filtering:',config.iceServers);} +return new RTCPeerConnectionShim(config);};window.RTCPeerConnection.prototype=RTCPeerConnectionShim.prototype;} +function shimReplaceTrack(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.filterIceServers=filterIceServers;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){utils.deprecated('RTCIceServer.url','RTCIceServer.urls');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){if(url.indexOf('stun:')===0){return false;} +var validTurn=url.startsWith('turn')&&!url.startsWith('turn:[')&&url.includes('transport=udp');if(validTurn&&!hasTurn){hasTurn=true;return true;} +return validTurn&&!hasTurn;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});}},{"../utils":15}],9:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window){if(!('getDisplayMedia'in window.navigator)){return;} +if(!window.navigator.mediaDevices){return;} +if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=window.navigator.getDisplayMedia.bind(window.navigator.mediaDevices);}},{}],10:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetUserMedia=shimGetUserMedia;function shimGetUserMedia(window){var navigator=window&&window.navigator;var shimError_=function shimError_(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function toString(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};}},{}],11:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimOnTrack=shimOnTrack;exports.shimPeerConnection=shimPeerConnection;exports.shimSenderGetStats=shimSenderGetStats;exports.shimReceiverGetStats=shimReceiverGetStats;exports.shimRemoveStream=shimRemoveStream;exports.shimRTCDataChannel=shimRTCDataChannel;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCTrackEvent&&'receiver'in window.RTCTrackEvent.prototype&&!('transceiver'in window.RTCTrackEvent.prototype)){Object.defineProperty(window.RTCTrackEvent.prototype,'transceiver',{get:function get(){return{receiver:this.receiver};}});}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} +if(!window.RTCPeerConnection&&window.mozRTCPeerConnection){window.RTCPeerConnection=window.mozRTCPeerConnection;} +['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};var modernStatsTypes={inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'};var nativeGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,onSucc,onErr){return nativeGetStats.apply(this,[selector||null]).then(function(stats){if(browserDetails.version<53&&!onSucc){try{stats.forEach(function(stat){stat.type=modernStatsTypes[stat.type]||stat.type;});}catch(e){if(e.name!=='TypeError'){throw e;} +stats.forEach(function(stat,i){stats.set(i,Object.assign({},stat,{type:modernStatsTypes[stat.type]||stat.type}));});}} +return stats;}).then(onSucc,onErr);};} +function shimSenderGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpSender.prototype){return;} +var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map());};} +function shimReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpReceiver.prototype){return;} +var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this2=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this2;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track);};} +function shimRemoveStream(window){if(!window.RTCPeerConnection||'removeStream'in window.RTCPeerConnection.prototype){return;} +window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;utils.deprecated('removeStream','removeTrack');this.getSenders().forEach(function(sender){if(sender.track&&stream.getTracks().includes(sender.track)){_this3.removeTrack(sender);}});};} +function shimRTCDataChannel(window){if(window.DataChannel&&!window.RTCDataChannel){window.RTCDataChannel=window.DataChannel;}}},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,preferredMediaSource){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){if(!(constraints&&constraints.video)){var err=new DOMException('getDisplayMedia without video '+'constraints is undefined');err.name='NotFoundError';err.code=8;return Promise.reject(err);} +if(constraints.video===true){constraints.video={mediaSource:preferredMediaSource};}else{constraints.video.mediaSource=preferredMediaSource;} +return window.navigator.mediaDevices.getUserMedia(constraints);};}},{}],13:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimGetUserMedia(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var MediaStreamTrack=window&&window.MediaStreamTrack;navigator.getUserMedia=function(constraints,onSuccess,onError){utils.deprecated('navigator.getUserMedia','navigator.mediaDevices.getUserMedia');navigator.mediaDevices.getUserMedia(constraints).then(onSuccess,onError);};if(!(browserDetails.version>55&&'autoGainControl'in navigator.mediaDevices.getSupportedConstraints())){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};var nativeGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){if((typeof c==='undefined'?'undefined':_typeof(c))==='object'&&_typeof(c.audio)==='object'){c=JSON.parse(JSON.stringify(c));remap(c.audio,'autoGainControl','mozAutoGainControl');remap(c.audio,'noiseSuppression','mozNoiseSuppression');} +return nativeGetUserMedia(c);};if(MediaStreamTrack&&MediaStreamTrack.prototype.getSettings){var nativeGetSettings=MediaStreamTrack.prototype.getSettings;MediaStreamTrack.prototype.getSettings=function(){var obj=nativeGetSettings.apply(this,arguments);remap(obj,'mozAutoGainControl','autoGainControl');remap(obj,'mozNoiseSuppression','noiseSuppression');return obj;};} +if(MediaStreamTrack&&MediaStreamTrack.prototype.applyConstraints){var nativeApplyConstraints=MediaStreamTrack.prototype.applyConstraints;MediaStreamTrack.prototype.applyConstraints=function(c){if(this.kind==='audio'&&(typeof c==='undefined'?'undefined':_typeof(c))==='object'){c=JSON.parse(JSON.stringify(c));remap(c,'autoGainControl','mozAutoGainControl');remap(c,'noiseSuppression','mozNoiseSuppression');} +return nativeApplyConstraints.apply(this,[c]);};}}}},{"../utils":15}],14:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimLocalStreamsAPI=shimLocalStreamsAPI;exports.shimRemoteStreamsAPI=shimRemoteStreamsAPI;exports.shimCallbacksAPI=shimCallbacksAPI;exports.shimGetUserMedia=shimGetUserMedia;exports.shimConstraints=shimConstraints;exports.shimRTCIceServerUrls=shimRTCIceServerUrls;exports.shimTrackEventTransceiver=shimTrackEventTransceiver;exports.shimCreateOfferLegacy=shimCreateOfferLegacy;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimLocalStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getLocalStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getLocalStreams=function(){if(!this._localStreams){this._localStreams=[];} +return this._localStreams;};} +if(!('addStream'in window.RTCPeerConnection.prototype)){var _addTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addStream=function(stream){var _this=this;if(!this._localStreams){this._localStreams=[];} +if(!this._localStreams.includes(stream)){this._localStreams.push(stream);} +stream.getTracks().forEach(function(track){return _addTrack.call(_this,track,stream);});};window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(stream){if(!this._localStreams){this._localStreams=[stream];}else if(!this._localStreams.includes(stream)){this._localStreams.push(stream);}} +return _addTrack.call(this,track,stream);};} +if(!('removeStream'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.removeStream=function(stream){var _this2=this;if(!this._localStreams){this._localStreams=[];} +var index=this._localStreams.indexOf(stream);if(index===-1){return;} +this._localStreams.splice(index,1);var tracks=stream.getTracks();this.getSenders().forEach(function(sender){if(tracks.includes(sender.track)){_this2.removeTrack(sender);}});};}} +function shimRemoteStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getRemoteStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[];};} +if(!('onaddstream'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'onaddstream',{get:function get(){return this._onaddstream;},set:function set(f){var _this3=this;if(this._onaddstream){this.removeEventListener('addstream',this._onaddstream);this.removeEventListener('track',this._onaddstreampoly);} +this.addEventListener('addstream',this._onaddstream=f);this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!_this3._remoteStreams){_this3._remoteStreams=[];} +if(_this3._remoteStreams.includes(stream)){return;} +_this3._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;_this3.dispatchEvent(event);});});}});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var pc=this;if(!this._onaddstreampoly){this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!pc._remoteStreams){pc._remoteStreams=[];} +if(pc._remoteStreams.indexOf(stream)>=0){return;} +pc._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;pc.dispatchEvent(event);});});} +return origSetRemoteDescription.apply(pc,arguments);};}} +function shimCallbacksAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +var prototype=window.RTCPeerConnection.prototype;var createOffer=prototype.createOffer;var createAnswer=prototype.createAnswer;var setLocalDescription=prototype.setLocalDescription;var setRemoteDescription=prototype.setRemoteDescription;var addIceCandidate=prototype.addIceCandidate;prototype.createOffer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createOffer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.createAnswer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createAnswer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};var withCallback=function withCallback(description,successCallback,failureCallback){var promise=setLocalDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setLocalDescription=withCallback;withCallback=function withCallback(description,successCallback,failureCallback){var promise=setRemoteDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setRemoteDescription=withCallback;withCallback=function withCallback(candidate,successCallback,failureCallback){var promise=addIceCandidate.apply(this,[candidate]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.addIceCandidate=withCallback;} +function shimGetUserMedia(window){var navigator=window&&window.navigator;if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){var mediaDevices=navigator.mediaDevices;var _getUserMedia=mediaDevices.getUserMedia.bind(mediaDevices);navigator.mediaDevices.getUserMedia=function(constraints){return _getUserMedia(shimConstraints(constraints));};} +if(!navigator.getUserMedia&&navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){navigator.getUserMedia=function(constraints,cb,errcb){navigator.mediaDevices.getUserMedia(constraints).then(cb,errcb);}.bind(navigator);}} +function shimConstraints(constraints){if(constraints&&constraints.video!==undefined){return Object.assign({},constraints,{video:utils.compactObject(constraints.video)});} +return constraints;} +function shimRTCIceServerUrls(window){var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i=pos&&parseInt(match[pos],10);} +function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(!window.RTCPeerConnection){return;} +var proto=window.RTCPeerConnection.prototype;var nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap){return nativeAddEventListener.apply(this,arguments);} +var wrappedCallback=function wrappedCallback(e){var modifiedEvent=wrapper(e);if(modifiedEvent){cb(modifiedEvent);}};this._eventMap=this._eventMap||{};this._eventMap[cb]=wrappedCallback;return nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback]);};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb]){return nativeRemoveEventListener.apply(this,arguments);} +var unwrappedCb=this._eventMap[cb];delete this._eventMap[cb];return nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb]);};Object.defineProperty(proto,'on'+eventNameToWrap,{get:function get(){return this['_on'+eventNameToWrap];},set:function set(cb){if(this['_on'+eventNameToWrap]){this.removeEventListener(eventNameToWrap,this['_on'+eventNameToWrap]);delete this['_on'+eventNameToWrap];} +if(cb){this.addEventListener(eventNameToWrap,this['_on'+eventNameToWrap]=cb);}},enumerable:true,configurable:true});} +function disableLog(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +logDisabled_=bool;return bool?'adapter.js logging disabled':'adapter.js logging enabled';} +function disableWarnings(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +deprecationWarnings_=!bool;return'adapter.js deprecation warnings '+(bool?'disabled':'enabled');} +function log(){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'){if(logDisabled_){return;} +if(typeof console!=='undefined'&&typeof console.log==='function'){console.log.apply(console,arguments);}}} +function deprecated(oldMethod,newMethod){if(!deprecationWarnings_){return;} +console.warn(oldMethod+' is deprecated, please use '+newMethod+' instead.');} +function detectBrowser(window){var navigator=window.navigator;var result={browser:null,version:null};if(typeof window==='undefined'||!window.navigator){result.browser='Not a browser.';return result;} +if(navigator.mozGetUserMedia){result.browser='firefox';result.version=extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);}else if(navigator.webkitGetUserMedia){result.browser='chrome';result.version=extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)){result.browser='edge';result.version=extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);}else if(window.RTCPeerConnection&&navigator.userAgent.match(/AppleWebKit\/(\d+)\./)){result.browser='safari';result.version=extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Not a supported browser.';return result;} +return result;} +function compactObject(data){if((typeof data==='undefined'?'undefined':_typeof(data))!=='object'){return data;} +return Object.keys(data).reduce(function(accumulator,key){var isObject=_typeof(data[key])==='object';var value=isObject?compactObject(data[key]):data[key];var isEmptyObject=isObject&&!Object.keys(value).length;if(value===undefined||isEmptyObject){return accumulator;} +return Object.assign(accumulator,_defineProperty({},key,value));},{});}},{}],16:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');function fixStatsType(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;} +function writeMediaSection(transceiver,caps,type,stream,dtlsRole){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':dtlsRole||'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var trackId=transceiver.rtpSender._initialTrackId||transceiver.rtpSender.track.id;transceiver.rtpSender._initialTrackId=trackId;var msid='msid:'+(stream?stream.id:'-')+' '+ +trackId+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){console.warn('RTCIceServer.url is deprecated! Use urls instead.');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){var validTurn=url.indexOf('turn:')===0&&url.indexOf('transport=udp')!==-1&&url.indexOf('turn:[')===-1&&!hasTurn;if(validTurn){hasTurn=true;return true;} +return url.indexOf('stun:')===0&&edgeVersion>=14393&&url.indexOf('?transport=udp')===-1;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});} +function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;i--){this._iceGatherers.push(new window.RTCIceGatherer({iceServers:config.iceServers,gatherPolicy:config.iceTransportPolicy}));}}else{config.iceCandidatePoolSize=0;} +this._config=config;this.transceivers=[];this._sdpSessionId=SDPUtils.generateSessionId();this._sdpSessionVersion=0;this._dtlsRole=undefined;this._isClosed=false;};Object.defineProperty(RTCPeerConnection.prototype,'localDescription',{configurable:true,get:function(){return this._localDescription;}});Object.defineProperty(RTCPeerConnection.prototype,'remoteDescription',{configurable:true,get:function(){return this._remoteDescription;}});RTCPeerConnection.prototype.onicecandidate=null;RTCPeerConnection.prototype.onaddstream=null;RTCPeerConnection.prototype.ontrack=null;RTCPeerConnection.prototype.onremovestream=null;RTCPeerConnection.prototype.onsignalingstatechange=null;RTCPeerConnection.prototype.oniceconnectionstatechange=null;RTCPeerConnection.prototype.onconnectionstatechange=null;RTCPeerConnection.prototype.onicegatheringstatechange=null;RTCPeerConnection.prototype.onnegotiationneeded=null;RTCPeerConnection.prototype.ondatachannel=null;RTCPeerConnection.prototype._dispatchEvent=function(name,event){if(this._isClosed){return;} +this.dispatchEvent(event);if(typeof this['on'+name]==='function'){this['on'+name](event);}};RTCPeerConnection.prototype._emitGatheringStateChange=function(){var event=new Event('icegatheringstatechange');this._dispatchEvent('icegatheringstatechange',event);};RTCPeerConnection.prototype.getConfiguration=function(){return this._config;};RTCPeerConnection.prototype.getLocalStreams=function(){return this.localStreams;};RTCPeerConnection.prototype.getRemoteStreams=function(){return this.remoteStreams;};RTCPeerConnection.prototype._createTransceiver=function(kind,doNotAdd){var hasBundleTransport=this.transceivers.length>0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,associatedRemoteMediaStreams:[],wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} +if(!doNotAdd){this.transceivers.push(transceiver);} +return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call addTrack on a closed peerconnection.');} +var alreadyExists=this.transceivers.find(function(s){return s.track===track;});if(alreadyExists){throw makeError('InvalidAccessError','Track already exists.');} +var transceiver;for(var i=0;i=15025){stream.getTracks().forEach(function(track){pc.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){pc.addTrack(track,clonedStream);});}};RTCPeerConnection.prototype.removeTrack=function(sender){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call removeTrack on a closed peerconnection.');} +if(!(sender instanceof window.RTCRtpSender)){throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.');} +var transceiver=this.transceivers.find(function(t){return t.rtpSender===sender;});if(!transceiver){throw makeError('InvalidAccessError','Sender was not created by this connection.');} +var stream=transceiver.stream;transceiver.rtpSender.stop();transceiver.rtpSender=null;transceiver.track=null;transceiver.stream=null;var localStreams=this.transceivers.map(function(t){return t.stream;});if(localStreams.indexOf(stream)===-1&&this.localStreams.indexOf(stream)>-1){this.localStreams.splice(this.localStreams.indexOf(stream),1);} +this._maybeFireNegotiationNeeded();};RTCPeerConnection.prototype.removeStream=function(stream){var pc=this;stream.getTracks().forEach(function(track){var sender=pc.getSenders().find(function(s){return s.track===track;});if(sender){pc.removeTrack(sender);}});};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(sdpMLineIndex,usingBundle){var pc=this;if(usingBundle&&sdpMLineIndex>0){return this.transceivers[0].iceGatherer;}else if(this._iceGatherers.length){return this._iceGatherers.shift();} +var iceGatherer=new window.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});Object.defineProperty(iceGatherer,'state',{value:'new',writable:true});this.transceivers[sdpMLineIndex].bufferedCandidateEvents=[];this.transceivers[sdpMLineIndex].bufferCandidates=function(event){var end=!event.candidate||Object.keys(event.candidate).length===0;iceGatherer.state=end?'completed':'gathering';if(pc.transceivers[sdpMLineIndex].bufferedCandidateEvents!==null){pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event);}};iceGatherer.addEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);return iceGatherer;};RTCPeerConnection.prototype._gather=function(mid,sdpMLineIndex){var pc=this;var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer.onlocalcandidate){return;} +var bufferedCandidateEvents=this.transceivers[sdpMLineIndex].bufferedCandidateEvents;this.transceivers[sdpMLineIndex].bufferedCandidateEvents=null;iceGatherer.removeEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);iceGatherer.onlocalcandidate=function(evt){if(pc.usingBundle&&sdpMLineIndex>0){return;} +var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state==='new'||iceGatherer.state==='gathering'){iceGatherer.state='completed';}}else{if(iceGatherer.state==='new'){iceGatherer.state='gathering';} +cand.component=1;cand.ufrag=iceGatherer.getLocalParameters().usernameFragment;var serializedCandidate=SDPUtils.writeCandidate(cand);event.candidate=Object.assign(event.candidate,SDPUtils.parseCandidate(serializedCandidate));event.candidate.candidate=serializedCandidate;event.candidate.toJSON=function(){return{candidate:event.candidate.candidate,sdpMid:event.candidate.sdpMid,sdpMLineIndex:event.candidate.sdpMLineIndex,usernameFragment:event.candidate.usernameFragment};};} +var sections=SDPUtils.getMediaSections(pc._localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex]+='a=end-of-candidates\r\n';} +pc._localDescription.sdp=SDPUtils.getDescription(pc._localDescription.sdp)+ +sections.join('');var complete=pc.transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});if(pc.iceGatheringState!=='gathering'){pc.iceGatheringState='gathering';pc._emitGatheringStateChange();} +if(!end){pc._dispatchEvent('icecandidate',event);} +if(complete){pc._dispatchEvent('icecandidate',new Event('icecandidate'));pc.iceGatheringState='complete';pc._emitGatheringStateChange();}};window.setTimeout(function(){bufferedCandidateEvents.forEach(function(e){iceGatherer.onlocalcandidate(e);});},0);};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var pc=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){pc._updateIceConnectionState();pc._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){pc._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});pc._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} +var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} +var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlsstatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} +transceiver.rtpSender.send(params);} +if(recv&&transceiver.rtpReceiver&¶ms.codecs.length>0){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} +if(transceiver.recvEncodingParameters.length){params.encodings=transceiver.recvEncodingParameters;}else{params.encodings=[{}];} +params.rtcp={compound:transceiver.rtcpParameters.compound};if(transceiver.rtcpParameters.cname){params.rtcp.cname=transceiver.rtcpParameters.cname;} +if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} +transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setLocalDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set local '+description.type+' in state '+pc.signalingState));} +var sections;var sessionpart;if(description.type==='offer'){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);pc.transceivers[sdpMLineIndex].localCapabilities=caps;});pc.transceivers.forEach(function(transceiver,sdpMLineIndex){pc._gather(transceiver.mid,sdpMLineIndex);});}else if(description.type==='answer'){sections=SDPUtils.splitSections(pc._remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=pc.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;if(!rejected&&!transceiver.rejected){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} +if(!pc.usingBundle||sdpMLineIndex===0){pc._gather(transceiver.mid,sdpMLineIndex);if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var params=getCommonCapabilities(localCapabilities,remoteCapabilities);pc._transceive(transceiver,params.codecs.length>0,false);}});} +pc._localDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-local-offer');}else{pc._updateSignalingState('stable');} +return Promise.resolve();};RTCPeerConnection.prototype.setRemoteDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set remote '+description.type+' in state '+pc.signalingState));} +var streams={};pc.remoteStreams.forEach(function(stream){streams[stream.id]=stream;});var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;pc.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){pc.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{pc.canTrickleIceCandidates=false;} +sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(rejected||(kind==='application'&&(protocol==='DTLS/SCTP'||protocol==='UDP/DTLS/SCTP'))){pc.transceivers[sdpMLineIndex]={mid:mid,kind:kind,protocol:protocol,rejected:true};return;} +if(!rejected&&pc.transceivers[sdpMLineIndex]&&pc.transceivers[sdpMLineIndex].rejected){pc.transceivers[sdpMLineIndex]=pc._createTransceiver(kind,true);} +var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} +recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&pc.transceivers[sdpMLineIndex]){pc._disposeIceAndDtlsTransports(sdpMLineIndex);pc.transceivers[sdpMLineIndex].iceGatherer=pc.transceivers[0].iceGatherer;pc.transceivers[sdpMLineIndex].iceTransport=pc.transceivers[0].iceTransport;pc.transceivers[sdpMLineIndex].dtlsTransport=pc.transceivers[0].dtlsTransport;if(pc.transceivers[sdpMLineIndex].rtpSender){pc.transceivers[sdpMLineIndex].rtpSender.setTransport(pc.transceivers[0].dtlsTransport);} +if(pc.transceivers[sdpMLineIndex].rtpReceiver){pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(pc.transceivers[0].dtlsTransport);}} +if(description.type==='offer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex]||pc._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,usingBundle);} +if(cands.length&&transceiver.iceTransport.state==='new'){if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+2)*1001}];var isNewTrack=false;if(direction==='sendrecv'||direction==='sendonly'){isNewTrack=!transceiver.rtpReceiver;rtpReceiver=transceiver.rtpReceiver||new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);if(isNewTrack){var stream;track=rtpReceiver.track;if(remoteMsid&&remoteMsid.stream==='-'){}else if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} +Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});stream=streams[remoteMsid.stream];}else{if(!streams.default){streams.default=new window.MediaStream();} +stream=streams.default;} +if(stream){addTrackToStreamAndFireEvent(track,stream);transceiver.associatedRemoteMediaStreams.push(stream);} +receiverList.push([track,rtpReceiver,stream]);}}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track){transceiver.associatedRemoteMediaStreams.forEach(function(s){var nativeTrack=s.getTracks().find(function(t){return t.id===transceiver.rtpReceiver.track.id;});if(nativeTrack){removeTrackFromStreamAndFireEvent(nativeTrack,s);}});transceiver.associatedRemoteMediaStreams=[];} +transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;pc._transceive(pc.transceivers[sdpMLineIndex],false,isNewTrack);}else if(description.type==='answer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;pc.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;pc.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;pc.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if(cands.length&&iceTransport.state==='new'){if((isIceLite||isComplete)&&(!usingBundle||sdpMLineIndex===0)){iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +if(!usingBundle||sdpMLineIndex===0){if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +pc._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams[remoteMsid.stream]);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams.default);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});if(pc._dtlsRole===undefined){pc._dtlsRole=description.type==='offer'?'active':'passive';} +pc._remoteDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-remote-offer');}else{pc._updateSignalingState('stable');} +Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){if(pc.remoteStreams.indexOf(stream)===-1){pc.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;window.setTimeout(function(){pc._dispatchEvent('addstream',event);});} +receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} +fireAddTrack(pc,track,receiver,[stream]);});}});receiverList.forEach(function(item){if(item[2]){return;} +fireAddTrack(pc,item[0],item[1],[]);});window.setTimeout(function(){if(!(pc&&pc.transceivers)){return;} +pc.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);return Promise.resolve();};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} +if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} +if(transceiver.rtpSender){transceiver.rtpSender.stop();} +if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._isClosed=true;this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this._dispatchEvent('signalingstatechange',event);};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var pc=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} +this.needNegotiation=true;window.setTimeout(function(){if(pc.needNegotiation){pc.needNegotiation=false;var event=new Event('negotiationneeded');pc._dispatchEvent('negotiationneeded',event);}},0);};RTCPeerConnection.prototype._updateIceConnectionState=function(){var newState;var states={'new':0,closed:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;}});newState='new';if(states.failed>0){newState='failed';}else if(states.checking>0){newState='checking';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';}else if(states.completed>0){newState='completed';} +if(newState!==this.iceConnectionState){this.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this._dispatchEvent('iceconnectionstatechange',event);}};RTCPeerConnection.prototype._updateConnectionState=function(){var newState;var states={'new':0,closed:0,connecting:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.dtlsTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;}});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';} +if(newState!==this.connectionState){this.connectionState=newState;var event=new Event('connectionstatechange');this._dispatchEvent('connectionstatechange',event);}};RTCPeerConnection.prototype.createOffer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createOffer after close'));} +var numAudioTracks=pc.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=pc.transceivers.filter(function(t){return t.kind==='video';}).length;var offerOptions=arguments[0];if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} +if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} +if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} +pc.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){pc._createTransceiver('audio');numAudioTracks--;} +if(numVideoTracks>0){pc._createTransceiver('video');numVideoTracks--;}} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);pc.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=transceiver.mid||SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,pc.usingBundle);} +var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';} +if(transceiver.remoteCapabilities&&transceiver.remoteCapabilities.codecs){transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec){if(codec.name.toLowerCase()===remoteCodec.name.toLowerCase()&&codec.clockRate===remoteCodec.clockRate){codec.preferredPayloadType=remoteCodec.payloadType;}});}});localCapabilities.headerExtensions.forEach(function(hdrExt){var remoteExtensions=transceiver.remoteCapabilities&&transceiver.remoteCapabilities.headerExtensions||[];remoteExtensions.forEach(function(rHdrExt){if(hdrExt.uri===rHdrExt.uri){hdrExt.id=rHdrExt.id;}});});var sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'&&!sendEncodingParameters[0].rtx){sendEncodingParameters[0].rtx={ssrc:sendEncodingParameters[0].ssrc+1};}} +if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} +transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(pc._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';pc.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream,pc._dtlsRole);sdp+='a=rtcp-rsize\r\n';if(transceiver.iceGatherer&&pc.iceGatheringState!=='new'&&(sdpMLineIndex===0||!pc.usingBundle)){transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1;sdp+='a='+SDPUtils.writeCandidate(cand)+'\r\n';});if(transceiver.iceGatherer.state==='completed'){sdp+='a=end-of-candidates\r\n';}}});var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.createAnswer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer after close'));} +if(!(pc.signalingState==='have-remote-offer'||pc.signalingState==='have-local-pranswer')){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer in signalingState '+pc.signalingState));} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);if(pc.usingBundle){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';var mediaSectionsInOffer=SDPUtils.getMediaSections(pc._remoteDescription.sdp).length;pc.transceivers.forEach(function(transceiver,sdpMLineIndex){if(sdpMLineIndex+1>mediaSectionsInOffer){return;} +if(transceiver.rejected){if(transceiver.kind==='application'){if(transceiver.protocol==='DTLS/SCTP'){sdp+='m=application 0 DTLS/SCTP 5000\r\n';}else{sdp+='m=application 0 '+transceiver.protocol+' webrtc-datachannel\r\n';}}else if(transceiver.kind==='audio'){sdp+='m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n'+'a=rtpmap:0 PCMU/8000\r\n';}else if(transceiver.kind==='video'){sdp+='m=video 0 UDP/TLS/RTP/SAVPF 120\r\n'+'a=rtpmap:120 VP8/90000\r\n';} +sdp+='c=IN IP4 0.0.0.0\r\n'+'a=inactive\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} +if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} +if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'&&!transceiver.sendEncodingParameters[0].rtx){transceiver.sendEncodingParameters[0].rtx={ssrc:transceiver.sendEncodingParameters[0].ssrc+1};}}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +sdp+=writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream,pc._dtlsRole);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.addIceCandidate=function(candidate){var pc=this;var sections;if(candidate&&!(candidate.sdpMLineIndex!==undefined||candidate.sdpMid)){return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required'));} +return new Promise(function(resolve,reject){if(!pc._remoteDescription){return reject(makeError('InvalidStateError','Can not add ICE candidate without a remote description'));}else if(!candidate||candidate.candidate===''){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return resolve();} +if(cand.component&&cand.component!==1){return resolve();} +if(sdpMLineIndex===0||(sdpMLineIndex>0&&transceiver.iceTransport!==pc.transceivers[0].iceTransport)){if(!maybeAddCandidate(transceiver.iceTransport,cand)){return reject(makeError('OperationError','Can not add ICE candidate'));}} +var candidateString=candidate.candidate.trim();if(candidateString.indexOf('a=')===0){candidateString=candidateString.substr(2);} +sections=SDPUtils.getMediaSections(pc._remoteDescription.sdp);sections[sdpMLineIndex]+='a='+ +(cand.type?candidateString:'end-of-candidates') ++'\r\n';pc._remoteDescription.sdp=SDPUtils.getDescription(pc._remoteDescription.sdp)+ +sections.join('');}else{return reject(makeError('OperationError','Can not add ICE candidate'));}} +resolve();});};RTCPeerConnection.prototype.getStats=function(selector){if(selector&&selector instanceof window.MediaStreamTrack){var senderOrReceiver=null;this.transceivers.forEach(function(transceiver){if(transceiver.rtpSender&&transceiver.rtpSender.track===selector){senderOrReceiver=transceiver.rtpSender;}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track===selector){senderOrReceiver=transceiver.rtpReceiver;}});if(!senderOrReceiver){throw makeError('InvalidAccessError','Invalid selector.');} +return senderOrReceiver.getStats();} +var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});return Promise.all(promises).then(function(allStats){var results=new Map();allStats.forEach(function(stats){stats.forEach(function(stat){results.set(stat.id,stat);});});return results;});};var ortcObjects=['RTCRtpSender','RTCRtpReceiver','RTCIceGatherer','RTCIceTransport','RTCDtlsTransport'];ortcObjects.forEach(function(ortcObjectName){var obj=window[ortcObjectName];if(obj&&obj.prototype&&obj.prototype.getStats){var nativeGetstats=obj.prototype.getStats;obj.prototype.getStats=function(){return nativeGetstats.apply(this).then(function(nativeStats){var mapStats=new Map();Object.keys(nativeStats).forEach(function(id){nativeStats[id].type=fixStatsType(nativeStats[id]);mapStats.set(id,nativeStats[id]);});return mapStats;});};}});var methods=['createOffer','createAnswer'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[0]==='function'||typeof args[1]==='function'){return nativeMethod.apply(this,[arguments[2]]).then(function(description){if(typeof args[0]==='function'){args[0].apply(null,[description]);}},function(error){if(typeof args[1]==='function'){args[1].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});methods=['setLocalDescription','setRemoteDescription','addIceCandidate'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'||typeof args[2]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}},function(error){if(typeof args[2]==='function'){args[2].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});['getStats'].forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}});} +return nativeMethod.apply(this,arguments);};});return RTCPeerConnection;};},{"sdp":17}],17:[function(require,module,exports){'use strict';var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10);};SDPUtils.localCName=SDPUtils.generateIdentifier();SDPUtils.splitLines=function(blob){return blob.trim().split('\n').map(function(line){return line.trim();});};SDPUtils.splitSections=function(blob){var parts=blob.split('\nm=');return parts.map(function(part,index){return(index>0?'m='+part:part).trim()+'\r\n';});};SDPUtils.getDescription=function(blob){var sections=SDPUtils.splitSections(blob);return sections&§ions[0];};SDPUtils.getMediaSections=function(blob){var sections=SDPUtils.splitSections(blob);sections.shift();return sections;};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} +var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],address:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i0?parts[0].split('/')[1]:'sendrecv',uri:parts[1]};};SDPUtils.writeExtmap=function(headerExtension){return'a=extmap:'+(headerExtension.id||headerExtension.preferredId)+ +(headerExtension.direction&&headerExtension.direction!=='sendrecv'?'/'+headerExtension.direction:'')+' '+headerExtension.uri+'\r\n';};SDPUtils.parseFmtp=function(line){var parsed={};var kv;var parts=line.substr(line.indexOf(' ')+1).split(';');for(var j=0;j-1){parts.attribute=line.substr(sp+1,colon-sp-1);parts.value=line.substr(colon+1);}else{parts.attribute=line.substr(sp+1);} +return parts;};SDPUtils.parseSsrcGroup=function(line){var parts=line.substr(13).split(' ');return{semantics:parts.shift(),ssrcs:parts.map(function(ssrc){return parseInt(ssrc,10);})};};SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,'a=mid:')[0];if(mid){return mid.substr(6);}};SDPUtils.parseFingerprint=function(line){var parts=line.substr(14).split(' ');return{algorithm:parts[0].toLowerCase(),value:parts[1]};};SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.matchPrefix(mediaSection+sessionpart,'a=fingerprint:');return{role:'auto',fingerprints:lines.map(SDPUtils.parseFingerprint)};};SDPUtils.writeDtlsParameters=function(params,setupType){var sdp='a=setup:'+setupType+'\r\n';params.fingerprints.forEach(function(fp){sdp+='a=fingerprint:'+fp.algorithm+' '+fp.value+'\r\n';});return sdp;};SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var iceParameters={usernameFragment:lines.filter(function(line){return line.indexOf('a=ice-ufrag:')===0;})[0].substr(12),password:lines.filter(function(line){return line.indexOf('a=ice-pwd:')===0;})[0].substr(10)};return iceParameters;};SDPUtils.writeIceParameters=function(params){return'a=ice-ufrag:'+params.usernameFragment+'\r\n'+'a=ice-pwd:'+params.password+'\r\n';};SDPUtils.parseRtpParameters=function(mediaSection){var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]};var lines=SDPUtils.splitLines(mediaSection);var mline=lines[0].split(' ');for(var i=3;i0?'9':'0';sdp+=' UDP/TLS/RTP/SAVPF ';sdp+=caps.codecs.map(function(codec){if(codec.preferredPayloadType!==undefined){return codec.preferredPayloadType;} +return codec.payloadType;}).join(' ')+'\r\n';sdp+='c=IN IP4 0.0.0.0\r\n';sdp+='a=rtcp:9 IN IP4 0.0.0.0\r\n';caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec);sdp+=SDPUtils.writeFmtp(codec);sdp+=SDPUtils.writeRtcpFb(codec);});var maxptime=0;caps.codecs.forEach(function(codec){if(codec.maxptime>maxptime){maxptime=codec.maxptime;}});if(maxptime>0){sdp+='a=maxptime:'+maxptime+'\r\n';} +sdp+='a=rtcp-mux\r\n';if(caps.headerExtensions){caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension);});} +return sdp;};SDPUtils.parseRtpEncodingParameters=function(mediaSection){var encodingParameters=[];var description=SDPUtils.parseRtpParameters(mediaSection);var hasRed=description.fecMechanisms.indexOf('RED')!==-1;var hasUlpfec=description.fecMechanisms.indexOf('ULPFEC')!==-1;var ssrcs=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='cname';});var primarySsrc=ssrcs.length>0&&ssrcs[0].ssrc;var secondarySsrc;var flows=SDPUtils.matchPrefix(mediaSection,'a=ssrc-group:FID').map(function(line){var parts=line.substr(17).split(' ');return parts.map(function(part){return parseInt(part,10);});});if(flows.length>0&&flows[0].length>1&&flows[0][0]===primarySsrc){secondarySsrc=flows[0][1];} +description.codecs.forEach(function(codec){if(codec.name.toUpperCase()==='RTX'&&codec.parameters.apt){var encParam={ssrc:primarySsrc,codecPayloadType:parseInt(codec.parameters.apt,10)};if(primarySsrc&&secondarySsrc){encParam.rtx={ssrc:secondarySsrc};} +encodingParameters.push(encParam);if(hasRed){encParam=JSON.parse(JSON.stringify(encParam));encParam.fec={ssrc:primarySsrc,mechanism:hasUlpfec?'red+ulpfec':'red'};encodingParameters.push(encParam);}}});if(encodingParameters.length===0&&primarySsrc){encodingParameters.push({ssrc:primarySsrc});} +var bandwidth=SDPUtils.matchPrefix(mediaSection,'b=');if(bandwidth.length){if(bandwidth[0].indexOf('b=TIAS:')===0){bandwidth=parseInt(bandwidth[0].substr(7),10);}else if(bandwidth[0].indexOf('b=AS:')===0){bandwidth=parseInt(bandwidth[0].substr(5),10)*1000*0.95 +-(50*40*8);}else{bandwidth=undefined;} +encodingParameters.forEach(function(params){params.maxBitrate=bandwidth;});} +return encodingParameters;};SDPUtils.parseRtcpParameters=function(mediaSection){var rtcpParameters={};var remoteSsrc=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(obj){return obj.attribute==='cname';})[0];if(remoteSsrc){rtcpParameters.cname=remoteSsrc.value;rtcpParameters.ssrc=remoteSsrc.ssrc;} +var rsize=SDPUtils.matchPrefix(mediaSection,'a=rtcp-rsize');rtcpParameters.reducedSize=rsize.length>0;rtcpParameters.compound=rsize.length===0;var mux=SDPUtils.matchPrefix(mediaSection,'a=rtcp-mux');rtcpParameters.mux=mux.length>0;return rtcpParameters;};SDPUtils.parseMsid=function(mediaSection){var parts;var spec=SDPUtils.matchPrefix(mediaSection,'a=msid:');if(spec.length===1){parts=spec[0].substr(7).split(' ');return{stream:parts[0],track:parts[1]};} +var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(msidParts){return msidParts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId,sessVer,sessUser){var sessionId;var version=sessVer!==undefined?sessVer:2;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} +var user=sessUser||'thisisadapterortc';return'v=0\r\n'+'o='+user+' '+sessionId+' '+version+' IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var msid='msid:'+stream.id+' '+ +transceiver.rtpSender.track.id+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;};SDPUtils.getDirection=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);for(var i=0;i - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.FSRTC.js - WebRTC Glue code - * - */ -(function($) { - - // Find the line in sdpLines that starts with |prefix|, and, if specified, - // contains |substr| (case-insensitive search). - function findLine(sdpLines, prefix, substr) { - return findLineInRange(sdpLines, 0, -1, prefix, substr); - } - - // Find the line in sdpLines[startLine...endLine - 1] that starts with |prefix| - // and, if specified, contains |substr| (case-insensitive search). - function findLineInRange(sdpLines, startLine, endLine, prefix, substr) { - var realEndLine = (endLine != -1) ? endLine : sdpLines.length; - for (var i = startLine; i < realEndLine; ++i) { - if (sdpLines[i].indexOf(prefix) === 0) { - if (!substr || sdpLines[i].toLowerCase().indexOf(substr.toLowerCase()) !== -1) { - return i; - } - } - } - return null; - } - - // Gets the codec payload type from an a=rtpmap:X line. - function getCodecPayloadType(sdpLine) { - var pattern = new RegExp('a=rtpmap:(\\d+) \\w+\\/\\d+'); - var result = sdpLine.match(pattern); - return (result && result.length == 2) ? result[1] : null; - } - - // Returns a new m= line with the specified codec as the first one. - function setDefaultCodec(mLine, payload) { - var elements = mLine.split(' '); - var newLine = []; - var index = 0; - for (var i = 0; i < elements.length; i++) { - if (index === 3) { // Format of media starts from the fourth. - newLine[index++] = payload; // Put target payload to the first. - } - if (elements[i] !== payload) newLine[index++] = elements[i]; - } - return newLine.join(' '); - } - - $.FSRTC = function(options) { - this.options = $.extend({ - useVideo: null, - useStereo: false, - userData: null, - localVideo: null, - screenShare: false, - useCamera: "any", - iceServers: false, - videoParams: {}, - audioParams: {}, - callbacks: { - onICEComplete: function() {}, - onICE: function() {}, - onOfferSDP: function() {} - }, - useStream: null, - }, options); - - this.audioEnabled = true; - this.videoEnabled = true; - - - this.mediaData = { - SDP: null, - profile: {}, - candidateList: [] - }; - - this.constraints = { - offerToReceiveAudio: this.options.useSpeak === "none" ? false : true, - offerToReceiveVideo: this.options.useVideo ? true : false, - }; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - - setCompat(); - checkCompat(); - }; - - $.FSRTC.validRes = []; - - $.FSRTC.prototype.useVideo = function(obj, local) { - var self = this; - - if (obj) { - self.options.useVideo = obj; - self.options.localVideo = local; - self.constraints.offerToReceiveVideo = true; - } else { - self.options.useVideo = null; - self.options.localVideo = null; - self.constraints.offerToReceiveVideo = false; - } - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - } - }; - - $.FSRTC.prototype.useStereo = function(on) { - var self = this; - self.options.useStereo = on; - }; - - // Sets Opus in stereo if stereo is enabled, by adding the stereo=1 fmtp param. - $.FSRTC.prototype.stereoHack = function(sdp) { - var self = this; - - if (!self.options.useStereo) { - return sdp; - } - - var sdpLines = sdp.split('\r\n'); - - // Find opus payload. - var opusIndex = findLine(sdpLines, 'a=rtpmap', 'opus/48000'), opusPayload; - - if (!opusIndex) { - return sdp; - } else { - opusPayload = getCodecPayloadType(sdpLines[opusIndex]); - } - - // Find the payload in fmtp line. - var fmtpLineIndex = findLine(sdpLines, 'a=fmtp:' + opusPayload.toString()); - - if (fmtpLineIndex === null) { - // create an fmtp line - sdpLines[opusIndex] = sdpLines[opusIndex] + '\r\na=fmtp:' + opusPayload.toString() + " stereo=1; sprop-stereo=1" - } else { - // Append stereo=1 to fmtp line. - sdpLines[fmtpLineIndex] = sdpLines[fmtpLineIndex].concat('; stereo=1; sprop-stereo=1'); - } - - sdp = sdpLines.join('\r\n'); - return sdp; - }; - - function setCompat() { - } - - function checkCompat() { - return true; - } - - function onStreamError(self, e) { - console.log('There has been a problem retrieving the streams - did you allow access? Check Device Resolution', e); - doCallback(self, "onError", e); - } - - function onStreamSuccess(self, stream) { - console.log("Stream Success"); - doCallback(self, "onStream", stream); - } - - function onRemoteStreamSuccess(self, stream) { - console.log("Remote Stream Success"); - doCallback(self, "onRemoteStream", stream); - } - - function onICE(self, candidate) { - self.mediaData.candidate = candidate; - self.mediaData.candidateList.push(self.mediaData.candidate); - - doCallback(self, "onICE"); - } - - function doCallback(self, func, arg) { - if (func in self.options.callbacks) { - self.options.callbacks[func](self, arg); - } - } - - function onICEComplete(self, candidate) { - console.log("ICE Complete"); - doCallback(self, "onICEComplete"); - } - - function onChannelError(self, e) { - console.error("Channel Error", e); - doCallback(self, "onError", e); - } - - function onICESDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("ICE SDP"); - doCallback(self, "onICESDP"); - } - - function onAnswerSDP(self, sdp) { - self.answer.SDP = self.stereoHack(sdp.sdp); - console.log("ICE ANSWER SDP"); - doCallback(self, "onAnswerSDP", self.answer.SDP); - } - - function onMessage(self, msg) { - console.log("Message"); - doCallback(self, "onICESDP", msg); - } - - FSRTCattachMediaStream = function(element, stream) { - if (typeof element.srcObject !== 'undefined') { - element.srcObject = stream; - } else { - console.error('Error attaching stream to element.'); - } - } - - function onRemoteStream(self, stream) { - if (self.options.useVideo) { - self.options.useVideo.style.display = 'block'; - - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - - if (iOS) { - self.options.useVideo.setAttribute("playsinline", true); - } - } - - var element = self.options.useAudio; - console.log("REMOTE STREAM", stream, element); - - FSRTCattachMediaStream(element, stream); - - - - //self.options.useAudio.play(); - self.remoteStream = stream; - onRemoteStreamSuccess(self, stream); - } - - function onOfferSDP(self, sdp) { - self.mediaData.SDP = self.stereoHack(sdp.sdp); - console.log("Offer SDP"); - doCallback(self, "onOfferSDP"); - } - - $.FSRTC.prototype.answer = function(sdp, onSuccess, onError) { - this.peer.addAnswerSDP({ - type: "answer", - sdp: sdp - }, - onSuccess, onError); - }; - - $.FSRTC.prototype.stopPeer = function() { - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - } - - $.FSRTC.prototype.stop = function() { - var self = this; - - if (self.options.useVideo) { - self.options.useVideo.style.display = 'none'; - self.options.useVideo['src'] = ''; - } - - if (self.localStream && !self.options.useStream) { - if(typeof self.localStream.stop == 'function') { - self.localStream.stop(); - } else { - if (self.localStream.active){ - var tracks = self.localStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - self.localStream = null; - } - - if (self.options.localVideo) { - deactivateLocalVideo(self.options.localVideo); - } - - if (self.options.localVideoStream && !self.options.useStream) { - if(typeof self.options.localVideoStream.stop == 'function') { - self.options.localVideoStream.stop(); - } else { - if (self.options.localVideoStream.active){ - var tracks = self.options.localVideoStream.getTracks(); - console.log(tracks); - tracks.forEach(function(track, index){ - console.log(track); - track.stop(); - }) - } - } - } - - if (self.peer) { - console.log("stopping peer"); - self.peer.stop(); - } - }; - - $.FSRTC.prototype.getMute = function() { - var self = this; - return self.audioEnabled; - } - - $.FSRTC.prototype.setMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var audioTracks = self.localStream.getAudioTracks(); - - for (var i = 0, len = audioTracks.length; i < len; i++ ) { - switch(what) { - case "on": - audioTracks[i].enabled = true; - break; - case "off": - audioTracks[i].enabled = false; - break; - case "toggle": - audioTracks[i].enabled = !audioTracks[i].enabled; - default: - break; - } - - self.audioEnabled = audioTracks[i].enabled; - } - - return !self.audioEnabled; - } - - $.FSRTC.prototype.getVideoMute = function() { - var self = this; - return self.videoEnabled; - } - - $.FSRTC.prototype.setVideoMute = function(what) { - var self = this; - if (!self.localStream) { - return false; - } - var videoTracks = self.localStream.getVideoTracks(); - - for (var i = 0, len = videoTracks.length; i < len; i++ ) { - switch(what) { - case "on": - videoTracks[i].enabled = true; - break; - case "off": - videoTracks[i].enabled = false; - break; - case "toggle": - videoTracks[i].enabled = !videoTracks[i].enabled; - default: - break; - } - - self.videoEnabled = videoTracks[i].enabled; - } - - return !self.videoEnabled; - } - - $.FSRTC.prototype.createAnswer = function(params) { - var self = this; - self.type = "answer"; - self.remoteSDP = params.sdp; - console.debug("inbound sdp: ", params.sdp); - - function onSuccess(stream) { - self.localStream = stream; - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: function(stream) { - return onRemoteStream(self, stream); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - offerSDP: { - type: "offer", - sdp: self.remoteSDP - }, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useVideo && self.options.localVideo && !self.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: params.useCamera }, - }, - localVideo: self.options.localVideo, - onsuccess: function(e) {self.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else { - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - } - - }; - - function getMediaParams(obj) { - - var audio; - - if (obj.options.useMic && obj.options.useMic === "none") { - console.log("Microphone Disabled"); - audio = false; - } else if (obj.options.videoParams && obj.options.screenShare) {//obj.options.videoParams.chromeMediaSource == 'desktop') { - console.error("SCREEN SHARE", obj.options.videoParams); - audio = false; - } else { - audio = { - }; - - if (obj.options.audioParams) { - audio = obj.options.audioParams; - } - - if (obj.options.useMic !== "any") { - //audio.optional = [{sourceId: obj.options.useMic}]; - audio.deviceId = {exact: obj.options.useMic}; - } - } - - if (obj.options.useVideo && obj.options.localVideo && !obj.options.useStream) { - getUserMedia({ - constraints: { - audio: false, - video: { deviceId: obj.options.useCamera }, - }, - localVideo: obj.options.localVideo, - onsuccess: function(e) {obj.options.localVideoStream = e; console.log("local video ready");}, - onerror: function(e) {console.error("local video error!");} - }); - } - - var video = {}; - var bestFrameRate = obj.options.videoParams.vertoBestFrameRate; - var minFrameRate = obj.options.videoParams.minFrameRate || 15; - delete obj.options.videoParams.vertoBestFrameRate; - - if (obj.options.screenShare) { - if (!obj.options.useCamera && !!navigator.mozGetUserMedia) { - //This is an issue, only FireFox needs to ask this additional question if its screen or window we need a better way - var dowin = window.confirm("Do you want to share an application window? If not you can share an entire screen."); - - video = { - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight}, - mediaSource: dowin ? "window" : "screen" - } - } else { - var opt = []; - if (obj.options.useCamera) { - opt.push({sourceId: obj.options.useCamera}); - } - - if (bestFrameRate) { - opt.push({minFrameRate: bestFrameRate}); - opt.push({maxFrameRate: bestFrameRate}); - } - - video = { - mandatory: obj.options.videoParams, - optional: opt - }; - // NOTE: This is a workaround for - // https://bugs.chromium.org/p/chromium/issues/detail?id=862325 - if (!!navigator.userAgent.match(/Android/i)) { - delete video.frameRate.min; - } - } - } else { - - video = { - //mandatory: obj.options.videoParams, - width: {min: obj.options.videoParams.minWidth, max: obj.options.videoParams.maxWidth}, - height: {min: obj.options.videoParams.minHeight, max: obj.options.videoParams.maxHeight} - }; - - - - var useVideo = obj.options.useVideo; - - if (useVideo && obj.options.useCamera && obj.options.useCamera !== "none") { - //if (!video.optional) { - //video.optional = []; - //} - - - if (obj.options.useCamera !== "any") { - //video.optional.push({sourceId: obj.options.useCamera}); - video.deviceId = { - exact: obj.options.useCamera, - }; - } - - if (bestFrameRate) { - //video.optional.push({minFrameRate: bestFrameRate}); - //video.optional.push({maxFrameRate: bestFrameRate}); - video.frameRate = {ideal: bestFrameRate, min: minFrameRate, max: 30}; - } - - } else { - console.log("Camera Disabled"); - video = false; - useVideo = false; - } - } - - return {audio: audio, video: video, useVideo: useVideo}; - } - - $.FSRTC.prototype.call = function(profile) { - checkCompat(); - - var self = this; - var screen = false; - - self.type = "offer"; - - if (self.options.videoParams && self.options.screenShare) { //self.options.videoParams.chromeMediaSource == 'desktop') { - screen = true; - } - - function onSuccess(stream) { - self.localStream = stream; - - if (screen) { - self.constraints.offerToReceiveVideo = false; - self.constraints.offerToReceiveAudio = false; - self.constraints.offerToSendAudio = false; - } - - self.peer = FSRTCPeerConnection({ - type: self.type, - attachStream: self.localStream, - onICE: function(candidate) { - return onICE(self, candidate); - }, - onICEComplete: function() { - return onICEComplete(self); - }, - onRemoteStream: screen ? function(stream) {} : function(stream) { - return onRemoteStream(self, stream); - }, - onOfferSDP: function(sdp) { - return onOfferSDP(self, sdp); - }, - onICESDP: function(sdp) { - return onICESDP(self, sdp); - }, - onChannelError: function(e) { - return onChannelError(self, e); - }, - constraints: self.constraints, - iceServers: self.options.iceServers, - turnServer: self.options.turnServer - }); - - onStreamSuccess(self, stream); - } - - function onError(e) { - onStreamError(self, e); - } - - var mediaParams = getMediaParams(self); - - console.log("Audio constraints", mediaParams.audio); - console.log("Video constraints", mediaParams.video); - - if (self.options.useStream) { - if (self.options.useVideo) { - self.options.localVideoStream = self.options.useStream; - if (self.options.localVideo) { - activateLocalVideo(self.options.localVideo, self.options.useStream); - } - } - onSuccess(self.options.useStream); - } - else if (mediaParams.audio || mediaParams.video) { - - getUserMedia({ - constraints: { - audio: mediaParams.audio, - video: mediaParams.video - }, - video: mediaParams.useVideo, - onsuccess: onSuccess, - onerror: onError - }); - - } else { - onSuccess(null); - } - - - - /* - navigator.getUserMedia({ - video: self.options.useVideo, - audio: true - }, onSuccess, onError); - */ - - }; - - // DERIVED from RTCPeerConnection-v1.5 - // 2013, @muazkh - github.com/muaz-khan - // MIT License - https://www.webrtc-experiment.com/licence/ - // Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/RTCPeerConnection - - function FSRTCPeerConnection(options) { - var gathering = false, done = false; - var config = {}; - var default_ice = [{ urls: ['stun:stun.l.google.com:19302'] }]; - - if (self.options.turnServer) { - default_ice.push(self.options.turnServer) - } - - if (options.iceServers) { - if (typeof(options.iceServers) === "boolean") { - config.iceServers = default_ice; - } else { - config.iceServers = options.iceServers; - } - } - - config.bundlePolicy = "max-compat"; - - var peer = new window.RTCPeerConnection(config); - - openOffererChannel(); - var x = 0; - - function ice_handler() { - - done = true; - gathering = null; - - if (options.onICEComplete) { - options.onICEComplete(); - } - - if (options.type == "offer") { - options.onICESDP(peer.localDescription); - } else { - if (!x && options.onICESDP) { - options.onICESDP(peer.localDescription); - } - } - } - - peer.onicecandidate = function(event) { - - if (done) { - return; - } - - if (!gathering) { - gathering = setTimeout(ice_handler, 1000); - } - - if (event) { - if (event.candidate) { - options.onICE(event.candidate); - } - } else { - done = true; - - if (gathering) { - clearTimeout(gathering); - gathering = null; - } - - ice_handler(); - } - }; - - // attachStream = MediaStream; - if (options.attachStream) peer.addStream(options.attachStream); - - // attachStreams[0] = audio-stream; - // attachStreams[1] = video-stream; - // attachStreams[2] = screen-capturing-stream; - if (options.attachStreams && options.attachStream.length) { - var streams = options.attachStreams; - for (var i = 0; i < streams.length; i++) { - peer.addStream(streams[i]); - } - } - - peer.onaddstream = function(event) { - var remoteMediaStream = event.stream; - - // onRemoteStreamEnded(MediaStream) - remoteMediaStream.oninactive = function () { - if (options.onRemoteStreamEnded) options.onRemoteStreamEnded(remoteMediaStream); - }; - - // onRemoteStream(MediaStream) - if (options.onRemoteStream) options.onRemoteStream(remoteMediaStream); - - //console.debug('on:add:stream', remoteMediaStream); - }; - - //var constraints = options.constraints || { - // offerToReceiveAudio: true, - //offerToReceiveVideo: true - //}; - - // onOfferSDP(RTCSessionDescription) - function createOffer() { - if (!options.onOfferSDP) return; - - peer.createOffer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - options.onOfferSDP(sessionDescription); - }, - onSdpError, options.constraints); - } - - // onAnswerSDP(RTCSessionDescription) - function createAnswer() { - if (options.type != "answer") return; - - //options.offerSDP.sdp = addStereo(options.offerSDP.sdp); - peer.setRemoteDescription(new window.RTCSessionDescription(options.offerSDP), onSdpSuccess, onSdpError); - peer.createAnswer(function(sessionDescription) { - sessionDescription.sdp = serializeSdp(sessionDescription.sdp); - peer.setLocalDescription(sessionDescription); - if (options.onAnswerSDP) { - options.onAnswerSDP(sessionDescription); - } - }, - onSdpError); - } - - - if ((options.onChannelMessage) || !options.onChannelMessage) { - createOffer(); - createAnswer(); - } - - // DataChannel Bandwidth - function setBandwidth(sdp) { - // remove existing bandwidth lines - sdp = sdp.replace(/b=AS([^\r\n]+\r\n)/g, ''); - sdp = sdp.replace(/a=mid:data\r\n/g, 'a=mid:data\r\nb=AS:1638400\r\n'); - - return sdp; - } - - // old: FF<>Chrome interoperability management - function getInteropSDP(sdp) { - var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZ'.split(''), - extractedChars = ''; - - function getChars() { - extractedChars += chars[parseInt(Math.random() * 40)] || ''; - if (extractedChars.length < 40) getChars(); - - return extractedChars; - } - - // usually audio-only streaming failure occurs out of audio-specific crypto line - // a=crypto:1 AES_CM_128_HMAC_SHA1_32 --------- kAttributeCryptoVoice - if (options.onAnswerSDP) sdp = sdp.replace(/(a=crypto:0 AES_CM_128_HMAC_SHA1_32)(.*?)(\r\n)/g, ''); - - // video-specific crypto line i.e. SHA1_80 - // a=crypto:1 AES_CM_128_HMAC_SHA1_80 --------- kAttributeCryptoVideo - var inline = getChars() + '\r\n' + (extractedChars = ''); - sdp = sdp.indexOf('a=crypto') == -1 ? sdp.replace(/c=IN/g, 'a=crypto:1 AES_CM_128_HMAC_SHA1_80 inline:' + inline + 'c=IN') : sdp; - - return sdp; - } - - function serializeSdp(sdp) { - return sdp; - } - - // DataChannel management - var channel; - - function openOffererChannel() { - if (!options.onChannelMessage) return; - - _openOffererChannel(); - - return; - } - - function _openOffererChannel() { - channel = peer.createDataChannel(options.channel || 'RTCDataChannel', { - reliable: false - }); - - setChannelEvents(); - } - - function setChannelEvents() { - channel.onmessage = function(event) { - if (options.onChannelMessage) options.onChannelMessage(event); - }; - - channel.onopen = function() { - if (options.onChannelOpened) options.onChannelOpened(channel); - }; - channel.onclose = function(event) { - if (options.onChannelClosed) options.onChannelClosed(event); - - console.warn('WebRTC DataChannel closed', event); - }; - channel.onerror = function(event) { - if (options.onChannelError) options.onChannelError(event); - - console.error('WebRTC DataChannel error', event); - }; - } - - function openAnswererChannel() { - peer.ondatachannel = function(event) { - channel = event.channel; - channel.binaryType = 'blob'; - setChannelEvents(); - }; - - return; - } - - // fake:true is also available on chrome under a flag! - function useless() { - log('Error in fake:true'); - } - - function onSdpSuccess() {} - - function onSdpError(e) { - if (options.onChannelError) { - options.onChannelError(e); - } - console.error('sdp error:', e); - } - - return { - addAnswerSDP: function(sdp, cbSuccess, cbError) { - - peer.setRemoteDescription(new window.RTCSessionDescription(sdp), cbSuccess ? cbSuccess : onSdpSuccess, cbError ? cbError : onSdpError); - }, - addICE: function(candidate) { - peer.addIceCandidate(new window.RTCIceCandidate({ - sdpMLineIndex: candidate.sdpMLineIndex, - candidate: candidate.candidate - })); - }, - - peer: peer, - channel: channel, - sendData: function(message) { - if (channel) { - channel.send(message); - } - }, - - stop: function() { - peer.close(); - if (options.attachStream) { - if(typeof options.attachStream.stop == 'function') { - options.attachStream.stop(); - } else { - options.attachStream.active = false; - } - } - } - - }; - } - - // getUserMedia - var video_constraints = { - //mandatory: {}, - //optional: [] - }; - - function activateLocalVideo(el, stream) { - el.srcObject = stream; - el.style.display = 'block'; - } - - function deactivateLocalVideo(el) { - el.srcObject = null; - el.style.display = 'none'; - } - - function getUserMedia(options) { - var n = navigator, - media; - n.getMedia = n.getUserMedia; - n.getMedia(options.constraints || { - audio: true, - video: video_constraints - }, - streaming, options.onerror || - function(e) { - console.error(e); - }); - - function streaming(stream) { - if (options.localVideo) { - activateLocalVideo(options.localVideo, stream); - } - - if (options.onsuccess) { - options.onsuccess(stream); - } - - media = stream; - } - - return media; - } - - $.FSRTC.resSupported = function(w, h) { - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] == w && $.FSRTC.validRes[i][1] == h) { - return true; - } - } - - return false; - } - - $.FSRTC.bestResSupported = function() { - var w = 0, h = 0; - - for (var i in $.FSRTC.validRes) { - if ($.FSRTC.validRes[i][0] >= w && $.FSRTC.validRes[i][1] >= h) { - w = $.FSRTC.validRes[i][0]; - h = $.FSRTC.validRes[i][1]; - } - } - - return [w, h]; - } - - var resList = [[160, 120], [320, 180], [320, 240], [640, 360], [640, 480], [1280, 720], [1920, 1080]]; - var resI = 0; - var ttl = 0; - - var checkRes = function (cam, func) { - - if (resI >= resList.length) { - var res = { - 'validRes': $.FSRTC.validRes, - 'bestResSupported': $.FSRTC.bestResSupported() - }; - - localStorage.setItem("res_" + cam, $.toJSON(res)); - - if (func) return func(res); - return; - } - - w = resList[resI][0]; - h = resList[resI][1]; - resI++; - - var video = { - width: {exact: w}, - height: {exact: h} - }; - - if (cam !== "any") { - video.deviceId = { - exact: cam, - }; - } - - getUserMedia({ - constraints: { - audio: ttl++ == 0, - video: video - }, - onsuccess: function(e) { - e.getTracks().forEach(function(track) {track.stop();}); - console.info(w + "x" + h + " supported."); $.FSRTC.validRes.push([w, h]); checkRes(cam, func);}, - onerror: function(e) {console.warn( w + "x" + h + " not supported."); checkRes(cam, func);} - }); - } - - - $.FSRTC.getValidRes = function (cam, func) { - var used = []; - var cached = localStorage.getItem("res_" + cam); - - if (cached) { - var cache = $.parseJSON(cached); - - if (cache) { - $.FSRTC.validRes = cache.validRes; - console.log("CACHED RES FOR CAM " + cam, cache); - } else { - console.error("INVALID CACHE"); - } - return func ? func(cache) : null; - } - - - $.FSRTC.validRes = []; - resI = 0; - - checkRes(cam, func); - } - - $.FSRTC.checkPerms = function (runtime, check_audio, check_video) { - getUserMedia({ - constraints: { - audio: check_audio, - video: check_video, - }, - onsuccess: function(e) { - - e.getTracks().forEach(function(track) {track.stop();}); - - console.info("media perm init complete"); - if (runtime) { - setTimeout(runtime, 100, true); - } - }, - onerror: function(e) { - if (check_video && check_audio) { - console.error("error, retesting with audio params only"); - return $.FSRTC.checkPerms(runtime, check_audio, false); - } - - console.error("media perm init error"); - - if (runtime) { - runtime(false) - } - } - }); - } - -})(jQuery); -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is jquery.jsonrpclient.js modified for Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Textalk AB http://textalk.se/ - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.jsonrpclient.js - JSON RPC client code - * - */ -/** - * This plugin requires jquery.json.js to be available, or at least the methods $.toJSON and - * $.parseJSON. - * - * The plan is to make use of websockets if they are available, but work just as well with only - * http if not. - * - * Usage example: - * - * var foo = new $.JsonRpcClient({ ajaxUrl: '/backend/jsonrpc' }); - * foo.call( - * 'bar', [ 'A parameter', 'B parameter' ], - * function(result) { alert('Foo bar answered: ' + result.my_answer); }, - * function(error) { console.log('There was an error', error); } - * ); - * - * More examples are available in README.md - */ -(function($) { - /** - * @fn new - * @memberof $.JsonRpcClient - * - * @param options An object stating the backends: - * ajaxUrl A url (relative or absolute) to a http(s) backend. - * socketUrl A url (relative of absolute) to a ws(s) backend. - * onmessage A socket message handler for other messages (non-responses). - * getSocket A function returning a WebSocket or null. - * It must take an onmessage_cb and bind it to the onmessage event - * (or chain it before/after some other onmessage handler). - * Or, it could return null if no socket is available. - * The returned instance must have readyState <= 1, and if less than 1, - * react to onopen binding. - */ - $.JsonRpcClient = function(options) { - var self = this; - this.options = $.extend({ - ajaxUrl : null, - socketUrl : null, ///< The ws-url for default getSocket. - onmessage : null, ///< Other onmessage-handler. - login : null, /// auth login - passwd : null, /// auth passwd - sessid : null, - loginParams : null, - userVariables : null, - getSocket : function(onmessage_cb) { return self._getSocket(onmessage_cb); } - }, options); - - self.ws_cnt = 0; - - // Declare an instance version of the onmessage callback to wrap 'this'. - this.wsOnMessage = function(event) { self._wsOnMessage(event); }; - }; - - /// Holding the WebSocket on default getsocket. - $.JsonRpcClient.prototype._ws_socket = null; - - /// Object : { success_cb: cb, error_cb: cb } - $.JsonRpcClient.prototype._ws_callbacks = {}; - - /// The next JSON-RPC request id. - $.JsonRpcClient.prototype._current_id = 1; - - - $.JsonRpcClient.prototype.speedTest = function (bytes, cb) { - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this.speedCB = cb; - this.speedBytes = bytes; - socket.send("#SPU " + bytes); - - var loops = bytes / 1024; - var rem = bytes % 1024; - var i; - var data = new Array(1024).join("."); - for (i = 0; i < loops; i++) { - socket.send("#SPB " + data); - } - - if (rem) { - socket.send("#SPB " + data); - } - - socket.send("#SPE"); - } - }; - - - - /** - * @fn call - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - * @param success_cb A callback for successful request. - * @param error_cb A callback for error. - */ - $.JsonRpcClient.prototype.call = function(method, params, success_cb, error_cb) { - // Construct the JSON-RPC 2.0 request. - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc : '2.0', - method : method, - params : params, - id : this._current_id++ // Increase the id counter to match request/response - }; - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request, success_cb, error_cb); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.call used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false, - - success : function(data) { - if ('error' in data) error_cb(data.error, this); - success_cb(data.result, this); - }, - - // JSON-RPC Server could return non-200 on error - error : function(jqXHR, textStatus, errorThrown) { - try { - var response = $.parseJSON(jqXHR.responseText); - - if ('console' in window) console.log(response); - - error_cb(response.error, this); - } catch (err) { - // Perhaps the responseText wasn't really a jsonrpc-error. - error_cb({ error: jqXHR.responseText }, this); - } - } - }); - }; - - /** - * Notify sends a command to the server that won't need a response. In http, there is probably - * an empty response - that will be dropped, but in ws there should be no response at all. - * - * This is very similar to call, but has no id and no handling of callbacks. - * - * @fn notify - * @memberof $.JsonRpcClient - * - * @param method The method to run on JSON-RPC server. - * @param params The params; an array or object. - */ - $.JsonRpcClient.prototype.notify = function(method, params) { - // Construct the JSON-RPC 2.0 request. - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - var request = { - jsonrpc: '2.0', - method: method, - params: params - }; - - // Try making a WebSocket call. - var socket = this.options.getSocket(this.wsOnMessage); - if (socket !== null) { - this._wsCall(socket, request); - return; - } - - // No WebSocket, and no HTTP backend? This won't work. - if (this.options.ajaxUrl === null) { - throw "$.JsonRpcClient.notify used with no websocket and no http endpoint."; - } - - $.ajax({ - type : 'POST', - url : this.options.ajaxUrl, - data : $.toJSON(request), - dataType : 'json', - cache : false - }); - }; - - /** - * Make a batch-call by using a callback. - * - * The callback will get an object "batch" as only argument. On batch, you can call the methods - * "call" and "notify" just as if it was a normal $.JsonRpcClient object, and all calls will be - * sent as a batch call then the callback is done. - * - * @fn batch - * @memberof $.JsonRpcClient - * - * @param callback The main function which will get a batch handler to run call and notify on. - * @param all_done_cb A callback function to call after all results have been handled. - * @param error_cb A callback function to call if there is an error from the server. - * Note, that batch calls should always get an overall success, and the - * only error - */ - $.JsonRpcClient.prototype.batch = function(callback, all_done_cb, error_cb) { - var batch = new $.JsonRpcClient._batchObject(this, all_done_cb, error_cb); - callback(batch); - batch._execute(); - }; - - /** - * The default getSocket handler. - * - * @param onmessage_cb The callback to be bound to onmessage events on the socket. - * - * @fn _getSocket - * @memberof $.JsonRpcClient - */ - - $.JsonRpcClient.prototype.socketReady = function() { - if (this._ws_socket === null || this._ws_socket.readyState > 1) { - return false; - } - - return true; - }; - - $.JsonRpcClient.prototype.closeSocket = function() { - var self = this; - if (self.socketReady()) { - self._ws_socket.onclose = function (w) {console.log("Closing Socket");}; - self._ws_socket.close(); - } - }; - - $.JsonRpcClient.prototype.loginData = function(params) { - var self = this; - self.options.login = params.login; - self.options.passwd = params.passwd; - self.options.loginParams = params.loginParams; - self.options.userVariables = params.userVariables; - }; - - $.JsonRpcClient.prototype.connectSocket = function(onmessage_cb) { - var self = this; - - if (self.to) { - clearTimeout(self.to); - } - - if (!self.socketReady()) { - self.authing = false; - - if (self._ws_socket) { - delete self._ws_socket; - } - - // No socket, or dying socket, let's get a new one. - self._ws_socket = new WebSocket(self.options.socketUrl); - - if (self._ws_socket) { - // Set up onmessage handler. - self._ws_socket.onmessage = onmessage_cb; - self._ws_socket.onclose = function (w) { - if (!self.ws_sleep) { - self.ws_sleep = 1000; - } - - if (self.options.onWSClose) { - self.options.onWSClose(self); - } - - if (self.ws_cnt > 10 && self.options.wsFallbackURL) { - self.options.socketUrl = self.options.wsFallbackURL; - } - - console.error("Websocket Lost " + self.ws_cnt + " sleep: " + self.ws_sleep + "msec"); - - self.to = setTimeout(function() { - console.log("Attempting Reconnection...."); - self.connectSocket(onmessage_cb); - }, self.ws_sleep); - - self.ws_cnt++; - - if (self.ws_sleep < 3000 && (self.ws_cnt % 10) === 0) { - self.ws_sleep += 1000; - } - }; - - // Set up sending of message for when the socket is open. - self._ws_socket.onopen = function() { - if (self.to) { - clearTimeout(self.to); - } - self.ws_sleep = 1000; - self.ws_cnt = 0; - if (self.options.onWSConnect) { - self.options.onWSConnect(self); - } - - var req; - // Send the requests. - while ((req = $.JsonRpcClient.q.pop())) { - self._ws_socket.send(req); - } - }; - } - } - - return self._ws_socket ? true : false; - }; - - $.JsonRpcClient.prototype.stopRetrying = function() { - if (self.to) - clearTimeout(self.to); - } - - $.JsonRpcClient.prototype._getSocket = function(onmessage_cb) { - // If there is no ws url set, we don't have a socket. - // Likewise, if there is no window.WebSocket. - if (this.options.socketUrl === null || !("WebSocket" in window)) return null; - - this.connectSocket(onmessage_cb); - - return this._ws_socket; - }; - - /** - * Queue to save messages delivered when websocket is not ready - */ - $.JsonRpcClient.q = []; - - /** - * Internal handler to dispatch a JRON-RPC request through a websocket. - * - * @fn _wsCall - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient.prototype._wsCall = function(socket, request, success_cb, error_cb) { - var request_json = $.toJSON(request); - - if (socket.readyState < 1) { - // The websocket is not open yet; we have to set sending of the message in onopen. - self = this; // In closure below, this is set to the WebSocket. Use self instead. - $.JsonRpcClient.q.push(request_json); - } else { - // We have a socket and it should be ready to send on. - socket.send(request_json); - } - - // Setup callbacks. If there is an id, this is a call and not a notify. - if ('id' in request && typeof success_cb !== 'undefined') { - this._ws_callbacks[request.id] = { request: request_json, request_obj: request, success_cb: success_cb, error_cb: error_cb }; - } - }; - - /** - * Internal handler for the websocket messages. It determines if the message is a JSON-RPC - * response, and if so, tries to couple it with a given callback. Otherwise, it falls back to - * given external onmessage-handler, if any. - * - * @param event The websocket onmessage-event. - */ - $.JsonRpcClient.prototype._wsOnMessage = function(event) { - // Check if this could be a JSON RPC message. - var response; - - // Special sub proto - if (event.data[0] == "#" && event.data[1] == "S" && event.data[2] == "P") { - if (event.data[3] == "U") { - this.up_dur = parseInt(event.data.substring(4)); - } else if (this.speedCB && event.data[3] == "D") { - this.down_dur = parseInt(event.data.substring(4)); - - var up_kps = (((this.speedBytes * 8) / (this.up_dur / 1000)) / 1024).toFixed(0); - var down_kps = (((this.speedBytes * 8) / (this.down_dur / 1000)) / 1024).toFixed(0); - - console.info("Speed Test: Up: " + up_kps + " Down: " + down_kps); - var cb = this.speedCB; - this.speedCB = null; - cb(event, { - upDur: this.up_dur, - downDur: this.down_dur, - upKPS: up_kps, - downKPS: down_kps - }); - } - - return; - } - - - try { - response = $.parseJSON(event.data); - - /// @todo Make using the jsonrcp 2.0 check optional, to use this on JSON-RPC 1 backends. - - if (typeof response === 'object' && - 'jsonrpc' in response && - response.jsonrpc === '2.0') { - - /// @todo Handle bad response (without id). - - // If this is an object with result, it is a response. - if ('result' in response && this._ws_callbacks[response.id]) { - // Get the success callback. - var success_cb = this._ws_callbacks[response.id].success_cb; - - /* - // set the sessid if present - if ('sessid' in response.result && !this.options.sessid || (this.options.sessid != response.result.sessid)) { - this.options.sessid = response.result.sessid; - if (this.options.sessid) { - console.log("setting session UUID to: " + this.options.sessid); - } - } - */ - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with result as parameter. - success_cb(response.result, this); - return; - } else if ('error' in response && this._ws_callbacks[response.id]) { - // If this is an object with error, it is an error response. - - // Get the error callback. - var error_cb = this._ws_callbacks[response.id].error_cb; - var orig_req = this._ws_callbacks[response.id].request; - - // if this is an auth request, send the credentials and resend the failed request - if (!self.authing && response.error.code == -32000 && self.options.login && self.options.passwd) { - self.authing = true; - - this.call("login", { login: self.options.login, passwd: self.options.passwd, loginParams: self.options.loginParams, - userVariables: self.options.userVariables}, - this._ws_callbacks[response.id].request_obj.method == "login" ? - function(e) { - self.authing = false; - console.log("logged in"); - delete self._ws_callbacks[response.id]; - - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - } - - : - - function(e) { - self.authing = false; - console.log("logged in, resending request id: " + response.id); - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send(orig_req); - } - if (self.options.onWSLogin) { - self.options.onWSLogin(true, self); - } - }, - - function(e) { - console.log("error logging in, request id:", response.id); - delete self._ws_callbacks[response.id]; - error_cb(response.error, this); - if (self.options.onWSLogin) { - self.options.onWSLogin(false, self); - } - }); - return; - } - - // Delete the callback from the storage. - delete this._ws_callbacks[response.id]; - - // Run callback with the error object as parameter. - error_cb(response.error, this); - return; - } - } - } catch (err) { - // Probably an error while parsing a non json-string as json. All real JSON-RPC cases are - // handled above, and the fallback method is called below. - console.log("ERROR: "+ err); - return; - } - - // This is not a JSON-RPC response. Call the fallback message handler, if given. - if (typeof this.options.onmessage === 'function') { - event.eventData = response; - if (!event.eventData) { - event.eventData = {}; - } - - var reply = this.options.onmessage(event); - - if (reply && typeof reply === "object" && event.eventData.id) { - var msg = { - jsonrpc: "2.0", - id: event.eventData.id, - result: reply - }; - - var socket = self.options.getSocket(self.wsOnMessage); - if (socket !== null) { - socket.send($.toJSON(msg)); - } - } - } - }; - - - /************************************************************************************************ - * Batch object with methods - ************************************************************************************************/ - - /** - * Handling object for batch calls. - */ - $.JsonRpcClient._batchObject = function(jsonrpcclient, all_done_cb, error_cb) { - // Array of objects to hold the call and notify requests. Each objects will have the request - // object, and unless it is a notify, success_cb and error_cb. - this._requests = []; - - this.jsonrpcclient = jsonrpcclient; - this.all_done_cb = all_done_cb; - this.error_cb = typeof error_cb === 'function' ? error_cb : function() {}; - - }; - - /** - * @sa $.JsonRpcClient.prototype.call - */ - $.JsonRpcClient._batchObject.prototype.call = function(method, params, success_cb, error_cb) { - - if (!params) { - params = {}; - } - - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - if (!success_cb) { - success_cb = function(e){console.log("Success: ", e);}; - } - - if (!error_cb) { - error_cb = function(e){console.log("Error: ", e);}; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params, - id : this.jsonrpcclient._current_id++ // Use the client's id series. - }, - success_cb : success_cb, - error_cb : error_cb - }); - }; - - /** - * @sa $.JsonRpcClient.prototype.notify - */ - $.JsonRpcClient._batchObject.prototype.notify = function(method, params) { - if (this.options.sessid) { - params.sessid = this.options.sessid; - } - - this._requests.push({ - request : { - jsonrpc : '2.0', - method : method, - params : params - } - }); - }; - - /** - * Executes the batched up calls. - */ - $.JsonRpcClient._batchObject.prototype._execute = function() { - var self = this; - - if (this._requests.length === 0) return; // All done :P - - // Collect all request data and sort handlers by request id. - var batch_request = []; - var handlers = {}; - var i = 0; - var call; - var success_cb; - var error_cb; - - // If we have a WebSocket, just send the requests individually like normal calls. - var socket = self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage); - if (socket !== null) { - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - success_cb = ('success_cb' in call) ? call.success_cb : undefined; - error_cb = ('error_cb' in call) ? call.error_cb : undefined; - self.jsonrpcclient._wsCall(socket, call.request, success_cb, error_cb); - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - return; - } - - for (i = 0; i < this._requests.length; i++) { - call = this._requests[i]; - batch_request.push(call.request); - - // If the request has an id, it should handle returns (otherwise it's a notify). - if ('id' in call.request) { - handlers[call.request.id] = { - success_cb : call.success_cb, - error_cb : call.error_cb - }; - } - } - - success_cb = function(data) { self._batchCb(data, handlers, self.all_done_cb); }; - - // No WebSocket, and no HTTP backend? This won't work. - if (self.jsonrpcclient.options.ajaxUrl === null) { - throw "$.JsonRpcClient.batch used with no websocket and no http endpoint."; - } - - // Send request - $.ajax({ - url : self.jsonrpcclient.options.ajaxUrl, - data : $.toJSON(batch_request), - dataType : 'json', - cache : false, - type : 'POST', - - // Batch-requests should always return 200 - error : function(jqXHR, textStatus, errorThrown) { - self.error_cb(jqXHR, textStatus, errorThrown); - }, - success : success_cb - }); - }; - - /** - * Internal helper to match the result array from a batch call to their respective callbacks. - * - * @fn _batchCb - * @memberof $.JsonRpcClient - */ - $.JsonRpcClient._batchObject.prototype._batchCb = function(result, handlers, all_done_cb) { - for (var i = 0; i < result.length; i++) { - var response = result[i]; - - // Handle error - if ('error' in response) { - if (response.id === null || !(response.id in handlers)) { - // An error on a notify? Just log it to the console. - if ('console' in window) console.log(response); - } else { - handlers[response.id].error_cb(response.error, this); - } - } else { - // Here we should always have a correct id and no error. - if (!(response.id in handlers) && 'console' in window) { - console.log(response); - } else { - handlers[response.id].success_cb(response.result, this); - } - } - } - - if (typeof all_done_cb === 'function') all_done_cb(result); - }; - -})(jQuery); - -/* - * Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * Copyright (C) 2005-2014, Anthony Minessale II - * - * Version: MPL 1.1 - * - * The contents of this file are subject to the Mozilla Public License Version - * 1.1 (the "License"); you may not use this file except in compliance with - * the License. You may obtain a copy of the License at - * http://www.mozilla.org/MPL/ - * - * Software distributed under the License is distributed on an "AS IS" basis, - * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License - * for the specific language governing rights and limitations under the - * License. - * - * The Original Code is Verto HTML5/Javascript Telephony Signaling and Control Protocol Stack for FreeSWITCH - * - * The Initial Developer of the Original Code is - * Anthony Minessale II - * Portions created by the Initial Developer are Copyright (C) - * the Initial Developer. All Rights Reserved. - * - * Contributor(s): - * - * Anthony Minessale II - * - * jquery.verto.js - Main interface - * - */ - -(function($) { - var sources = []; - - var generateGUID = (typeof(window.crypto) !== 'undefined' && typeof(window.crypto.getRandomValues) !== 'undefined') ? - function() { - // If we have a cryptographically secure PRNG, use that - // http://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript - var buf = new Uint16Array(8); - window.crypto.getRandomValues(buf); - var S4 = function(num) { - var ret = num.toString(16); - while (ret.length < 4) { - ret = "0" + ret; - } - return ret; - }; - return (S4(buf[0]) + S4(buf[1]) + "-" + S4(buf[2]) + "-" + S4(buf[3]) + "-" + S4(buf[4]) + "-" + S4(buf[5]) + S4(buf[6]) + S4(buf[7])); - } - - : - - function() { - // Otherwise, just use Math.random - // http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523 - return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) { - var r = Math.random() * 16 | 0, - v = c == 'x' ? r : (r & 0x3 | 0x8); - return v.toString(16); - }); - }; - - /// MASTER OBJ - $.verto = function(options, callbacks) { - var verto = this; - - $.verto.saved.push(verto); - - verto.options = $.extend({ - login: null, - passwd: null, - socketUrl: null, - tag: null, - localTag: null, - videoParams: {}, - audioParams: {}, - loginParams: {}, - deviceParams: {onResCheck: null}, - userVariables: {}, - iceServers: false, - ringSleep: 6000, - sessid: null, - useStream: null - }, options); - - if (verto.options.deviceParams.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, verto.options.deviceParams.onResCheck); - } - - if (!verto.options.deviceParams.useMic) { - verto.options.deviceParams.useMic = "any"; - } - - if (!verto.options.deviceParams.useSpeak) { - verto.options.deviceParams.useSpeak = "any"; - } - - if (verto.options.sessid) { - verto.sessid = verto.options.sessid; - } else { - verto.sessid = localStorage.getItem("verto_session_uuid") || generateGUID(); - localStorage.setItem("verto_session_uuid", verto.sessid); - } - - verto.dialogs = {}; - verto.callbacks = callbacks || {}; - verto.eventSUBS = {}; - - verto.rpcClient = new $.JsonRpcClient({ - login: verto.options.login, - passwd: verto.options.passwd, - socketUrl: verto.options.socketUrl, - wsFallbackURL: verto.options.wsFallbackURL, - turnServer: verto.options.turnServer, - loginParams: verto.options.loginParams, - userVariables: verto.options.userVariables, - sessid: verto.sessid, - onmessage: function(e) { - return verto.handleMessage(e.eventData); - }, - onWSConnect: function(o) { - o.call('login', {}); - }, - onWSLogin: function(success) { - if (verto.callbacks.onWSLogin) { - verto.callbacks.onWSLogin(verto, success); - } - }, - onWSClose: function(success) { - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, success); - } - verto.purge(); - } - }); - - var tag = verto.options.tag; - if (typeof(tag) === "function") { - tag = tag(); - } - - if (verto.options.ringFile && verto.options.tag) { - verto.ringer = $("#" + tag); - } - - verto.rpcClient.call('login', {}); - - }; - - - $.verto.prototype.deviceParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.deviceParams[i] = obj[i]; - } - - if (obj.useCamera) { - $.FSRTC.getValidRes(verto.options.deviceParams.useCamera, obj ? obj.onResCheck : undefined); - } - }; - - $.verto.prototype.videoParams = function(obj) { - var verto = this; - - for (var i in obj) { - verto.options.videoParams[i] = obj[i]; - } - }; - - $.verto.prototype.iceServers = function(obj) { - var verto = this; - verto.options.iceServers = obj; - }; - - $.verto.prototype.loginData = function(params) { - var verto = this; - verto.options.login = params.login; - verto.options.passwd = params.passwd; - verto.rpcClient.loginData(params); - }; - - $.verto.prototype.logout = function(msg) { - var verto = this; - verto.rpcClient.closeSocket(); - if (verto.callbacks.onWSClose) { - verto.callbacks.onWSClose(verto, false); - } - verto.purge(); - }; - - $.verto.prototype.login = function(msg) { - var verto = this; - verto.logout(); - verto.rpcClient.call('login', {}); - }; - - $.verto.prototype.message = function(msg) { - var verto = this; - var err = 0; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - verto.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.prototype.processReply = function(method, success, e) { - var verto = this; - var i; - - //console.log("Response: " + method, success, e); - - switch (method) { - case "verto.subscribe": - for (i in e.unauthorizedChannels) { - drop_bad(verto, e.unauthorizedChannels[i]); - } - for (i in e.subscribedChannels) { - mark_ready(verto, e.subscribedChannels[i]); - } - - break; - case "verto.unsubscribe": - //console.error(e); - break; - } - }; - - $.verto.prototype.sendMethod = function(method, params) { - var verto = this; - - verto.rpcClient.call(method, params, - - function(e) { - /* Success */ - verto.processReply(method, true, e); - }, - - function(e) { - /* Error */ - verto.processReply(method, false, e); - }); - }; - - function do_sub(verto, channel, obj) { - - } - - function drop_bad(verto, channel) { - console.error("drop unauthorized channel: " + channel); - delete verto.eventSUBS[channel]; - } - - function mark_ready(verto, channel) { - for (var j in verto.eventSUBS[channel]) { - verto.eventSUBS[channel][j].ready = true; - console.log("subscribed to channel: " + channel); - if (verto.eventSUBS[channel][j].readyHandler) { - verto.eventSUBS[channel][j].readyHandler(verto, channel); - } - } - } - - var SERNO = 1; - - function do_subscribe(verto, channel, subChannels, sparams) { - var params = sparams || {}; - - var local = params.local; - - var obj = { - eventChannel: channel, - userData: params.userData, - handler: params.handler, - ready: false, - readyHandler: params.readyHandler, - serno: SERNO++ - }; - - var isnew = false; - - if (!verto.eventSUBS[channel]) { - verto.eventSUBS[channel] = []; - subChannels.push(channel); - isnew = true; - } - - verto.eventSUBS[channel].push(obj); - - if (local) { - obj.ready = true; - obj.local = true; - } - - if (!isnew && verto.eventSUBS[channel][0].ready) { - obj.ready = true; - if (obj.readyHandler) { - obj.readyHandler(verto, channel); - } - } - - return { - serno: obj.serno, - eventChannel: channel - }; - - } - - $.verto.prototype.subscribe = function(channel, sparams) { - var verto = this; - var r = []; - var subChannels = []; - var params = sparams || {}; - - if (typeof(channel) === "string") { - r.push(do_subscribe(verto, channel, subChannels, params)); - } else { - for (var i in channel) { - r.push(do_subscribe(verto, channel, subChannels, params)); - } - } - - if (subChannels.length) { - verto.sendMethod("verto.subscribe", { - eventChannel: subChannels.length == 1 ? subChannels[0] : subChannels, - subParams: params.subParams - }); - } - - return r; - }; - - $.verto.prototype.unsubscribe = function(handle) { - var verto = this; - var i; - - if (!handle) { - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - verto.unsubscribe(verto.eventSUBS[i]); - } - } - } else { - var unsubChannels = {}; - var sendChannels = []; - var channel; - - if (typeof(handle) == "string") { - delete verto.eventSUBS[handle]; - unsubChannels[handle]++; - } else { - for (i in handle) { - if (typeof(handle[i]) == "string") { - channel = handle[i]; - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } else { - var repl = []; - channel = handle[i].eventChannel; - - for (var j in verto.eventSUBS[channel]) { - if (verto.eventSUBS[channel][j].serno == handle[i].serno) {} else { - repl.push(verto.eventSUBS[channel][j]); - } - } - - verto.eventSUBS[channel] = repl; - - if (verto.eventSUBS[channel].length === 0) { - delete verto.eventSUBS[channel]; - unsubChannels[channel]++; - } - } - } - } - - for (var u in unsubChannels) { - console.log("Sending Unsubscribe for: ", u); - sendChannels.push(u); - } - - if (sendChannels.length) { - verto.sendMethod("verto.unsubscribe", { - eventChannel: sendChannels.length == 1 ? sendChannels[0] : sendChannels - }); - } - } - }; - - $.verto.prototype.broadcast = function(channel, params) { - var verto = this; - var msg = { - eventChannel: channel, - data: {} - }; - for (var i in params) { - msg.data[i] = params[i]; - } - verto.sendMethod("verto.broadcast", msg); - }; - - $.verto.prototype.purge = function(callID) { - var verto = this; - var x = 0; - var i; - - for (i in verto.dialogs) { - if (!x) { - console.log("purging dialogs"); - } - x++; - verto.dialogs[i].setState($.verto.enum.state.purge); - } - - for (i in verto.eventSUBS) { - if (verto.eventSUBS[i]) { - console.log("purging subscription: " + i); - delete verto.eventSUBS[i]; - } - } - }; - - $.verto.prototype.hangup = function(callID) { - var verto = this; - if (callID) { - var dialog = verto.dialogs[callID]; - - if (dialog) { - dialog.hangup(); - } - } else { - for (var i in verto.dialogs) { - verto.dialogs[i].hangup(); - } - } - }; - - $.verto.prototype.newCall = function(args, callbacks) { - var verto = this; - - if (!verto.rpcClient.socketReady()) { - console.error("Not Connected..."); - return; - } - - if (args["useCamera"]) { - verto.options.deviceParams["useCamera"] = args["useCamera"]; - } - - var dialog = new $.verto.dialog($.verto.enum.direction.outbound, this, args); - - if (callbacks) { - dialog.callbacks = callbacks; - } - - dialog.invite(); - - return dialog; - }; - - $.verto.prototype.handleMessage = function(data) { - var verto = this; - - if (!(data && data.method)) { - console.error("Invalid Data", data); - return; - } - - if (data.params.callID) { - var dialog = verto.dialogs[data.params.callID]; - - if (data.method === "verto.attach" && dialog) { - delete dialog.verto.dialogs[dialog.callID]; - dialog.rtc.stop(); - dialog = null; - } - - if (dialog) { - - switch (data.method) { - case 'verto.bye': - dialog.hangup(data.params); - break; - case 'verto.answer': - dialog.handleAnswer(data.params); - break; - case 'verto.media': - dialog.handleMedia(data.params); - break; - case 'verto.display': - dialog.handleDisplay(data.params); - break; - case 'verto.info': - dialog.handleInfo(data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", dialog, data.method); - break; - } - } else { - - switch (data.method) { - case 'verto.attach': - data.params.attach = true; - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.useVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - dialog.setState($.verto.enum.state.recovering); - - break; - case 'verto.invite': - - if (data.params.sdp && data.params.sdp.indexOf("m=video") > 0) { - data.params.wantVideo = true; - } - - if (data.params.sdp && data.params.sdp.indexOf("stereo=1") > 0) { - data.params.useStereo = true; - } - - dialog = new $.verto.dialog($.verto.enum.direction.inbound, verto, data.params); - break; - default: - console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED"); - break; - } - } - - return { - method: data.method - }; - } else { - switch (data.method) { - case 'verto.punt': - verto.purge(); - verto.logout(); - break; - case 'verto.event': - var list = null; - var key = null; - - if (data.params) { - key = data.params.eventChannel; - } - - if (key) { - list = verto.eventSUBS[key]; - - if (!list) { - list = verto.eventSUBS[key.split(".")[0]]; - } - } - - if (!list && key && key === verto.sessid) { - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.pvtEvent, data.params); - } - } else if (!list && key && verto.dialogs[key]) { - verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent, data.params); - } else if (!list) { - if (!key) { - key = "UNDEFINED"; - } - console.error("UNSUBBED or invalid EVENT " + key + " IGNORED"); - } else { - for (var i in list) { - var sub = list[i]; - - if (!sub || !sub.ready) { - console.error("invalid EVENT for " + key + " IGNORED"); - } else if (sub.handler) { - sub.handler(verto, data.params, sub.userData); - } else if (verto.callbacks.onEvent) { - verto.callbacks.onEvent(verto, data.params, sub.userData); - } else { - console.log("EVENT:", data.params); - } - } - } - - break; - - case "verto.info": - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.info, data.params.msg); - } - //console.error(data); - console.debug("MESSAGE from: " + data.params.msg.from, data.params.msg.body); - - break; - - case 'verto.clientReady': - if (verto.callbacks.onMessage) { - verto.callbacks.onMessage(verto, null, $.verto.enum.message.clientReady, data.params); - } - console.debug("CLIENT READY", data.params); - break; - - default: - console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED", data.method); - break; - } - } - }; - - var del_array = function(array, name) { - var r = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] != name) { - r.push(array[i]); - } - } - - return r; - }; - - var hashArray = function() { - var vha = this; - - var hash = {}; - var array = []; - - vha.reorder = function(a) { - array = a; - var h = hash; - hash = {}; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - if (h[key]) { - hash[key] = h[key]; - delete h[key]; - } - } - h = undefined; - }; - - vha.clear = function() { - hash = undefined; - array = undefined; - hash = {}; - array = []; - }; - - vha.add = function(name, val, insertAt) { - var redraw = false; - - if (!hash[name]) { - if (insertAt === undefined || insertAt < 0 || insertAt >= array.length) { - array.push(name); - } else { - var x = 0; - var n = []; - var len = array.length; - - for (var i = 0; i < len; i++) { - if (x++==insertAt) { - n.push(name); - } - n.push(array[i]); - } - - array = undefined; - array = n; - n = undefined; - redraw = true; - } - } - - hash[name] = val; - - return redraw; - }; - - vha.del = function(name) { - var r = false; - - if (hash[name]) { - array = del_array(array, name); - delete hash[name]; - r = true; - } else { - console.error("can't del nonexistant key " + name); - } - - return r; - }; - - vha.get = function(name) { - return hash[name]; - }; - - vha.order = function() { - return array; - }; - - vha.hash = function() { - return hash; - }; - - vha.indexOf = function(name) { - var len = array.length; - - for (var i = 0; i < len; i++) { - if (array[i] == name) { - return i; - } - } - }; - - vha.arrayLen = function() { - return array.length; - }; - - vha.asArray = function() { - var r = []; - - var len = array.length; - - for (var i = 0; i < len; i++) { - var key = array[i]; - r.push(hash[key]); - } - - return r; - }; - - vha.each = function(cb) { - var len = array.length; - - for (var i = 0; i < len; i++) { - cb(array[i], hash[array[i]]); - } - }; - - vha.dump = function(html) { - var str = ""; - - vha.each(function(name, val) { - str += "name: " + name + " val: " + JSON.stringify(val) + (html ? "
" : "\n"); - }); - - return str; - }; - - }; - - $.verto.liveArray = function(verto, context, name, config) { - var la = this; - var lastSerno = 0; - var binding = null; - var user_obj = config.userObj; - var local = false; - - // Inherit methods of hashArray - hashArray.call(la); - - // Save the hashArray add, del, reorder, clear methods so we can make our own. - la._add = la.add; - la._del = la.del; - la._reorder = la.reorder; - la._clear = la.clear; - - la.context = context; - la.name = name; - la.user_obj = user_obj; - - la.verto = verto; - la.broadcast = function(channel, obj) { - verto.broadcast(channel, obj); - }; - la.errs = 0; - - la.clear = function() { - la._clear(); - lastSerno = 0; - - if (la.onChange) { - la.onChange(la, { - action: "clear" - }); - } - }; - - la.checkSerno = function(serno) { - if (serno < 0) { - return true; - } - - if (lastSerno > 0 && serno != (lastSerno + 1)) { - if (la.onErr) { - la.onErr(la, { - lastSerno: lastSerno, - serno: serno - }); - } - la.errs++; - console.debug(la.errs); - if (la.errs < 3) { - la.bootstrap(la.user_obj); - } - return false; - } else { - lastSerno = serno; - return true; - } - }; - - la.reorder = function(serno, a) { - if (la.checkSerno(serno)) { - la._reorder(a); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "reorder" - }); - } - } - }; - - la.init = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "init", - index: index, - key: key, - data: val - }); - } - } - }; - - la.bootObj = function(serno, val) { - if (la.checkSerno(serno)) { - - //la.clear(); - for (var i in val) { - la._add(val[i][0], val[i][1]); - } - - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "bootObj", - data: val, - redraw: true - }); - } - } - }; - - // @param serno La is the serial number for la particular request. - // @param key If looking at it as a hash table, la represents the key in the hashArray object where you want to store the val object. - // @param index If looking at it as an array, la represents the position in the array where you want to store the val object. - // @param val La is the object you want to store at the key or index location in the hash table / array. - la.add = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - var redraw = la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "add", - index: index, - key: key, - data: val, - redraw: redraw - }); - } - } - }; - - la.modify = function(serno, val, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - la._add(key, val, index); - if (la.onChange) { - la.onChange(la, { - serno: serno, - action: "modify", - key: key, - data: val, - index: index - }); - } - } - }; - - la.del = function(serno, key, index) { - if (key === null || key === undefined) { - key = serno; - } - if (la.checkSerno(serno)) { - if (index === null || index < 0 || index === undefined) { - index = la.indexOf(key); - } - var ok = la._del(key); - - if (ok && la.onChange) { - la.onChange(la, { - serno: serno, - action: "del", - key: key, - index: index - }); - } - } - }; - - var eventHandler = function(v, e, la) { - var packet = e.data; - - //console.error("READ:", packet); - - if (packet.name != la.name) { - return; - } - - switch (packet.action) { - - case "init": - la.init(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "bootObj": - la.bootObj(packet.wireSerno, packet.data); - break; - case "add": - la.add(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - break; - - case "modify": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.modify(packet.wireSerno, packet.data, packet.hashKey, packet.arrIndex); - } - break; - case "del": - if (! (packet.arrIndex || packet.hashKey)) { - console.error("Invalid Packet", packet); - } else { - la.del(packet.wireSerno, packet.hashKey, packet.arrIndex); - } - break; - - case "clear": - la.clear(); - break; - - case "reorder": - la.reorder(packet.wireSerno, packet.order); - break; - - default: - if (la.checkSerno(packet.wireSerno)) { - if (la.onChange) { - la.onChange(la, { - serno: packet.wireSerno, - action: packet.action, - data: packet.data - }); - } - } - break; - } - }; - - if (la.context) { - binding = la.verto.subscribe(la.context, { - handler: eventHandler, - userData: la, - subParams: config.subParams - }); - } - - la.destroy = function() { - la._clear(); - la.verto.unsubscribe(binding); - }; - - la.sendCommand = function(cmd, obj) { - var self = la; - self.broadcast(self.context, { - liveArray: { - command: cmd, - context: self.context, - name: self.name, - obj: obj - } - }); - }; - - la.bootstrap = function(obj) { - var self = la; - la.sendCommand("bootstrap", obj); - //self.heartbeat(); - }; - - la.changepage = function(obj) { - var self = la; - self.clear(); - self.broadcast(self.context, { - liveArray: { - command: "changepage", - context: la.context, - name: la.name, - obj: obj - } - }); - }; - - la.heartbeat = function(obj) { - var self = la; - - var callback = function() { - self.heartbeat.call(self, obj); - }; - self.broadcast(self.context, { - liveArray: { - command: "heartbeat", - context: self.context, - name: self.name, - obj: obj - } - }); - self.hb_pid = setTimeout(callback, 30000); - }; - - la.bootstrap(la.user_obj); - }; - - $.verto.liveTable = function(verto, context, name, jq, config) { - var dt; - var la = new $.verto.liveArray(verto, context, name, { - subParams: config.subParams - }); - var lt = this; - - lt.liveArray = la; - lt.dataTable = dt; - lt.verto = verto; - - lt.destroy = function() { - if (dt) { - dt.fnDestroy(); - } - if (la) { - la.destroy(); - } - - dt = null; - la = null; - }; - - la.onErr = function(obj, args) { - console.error("Error: ", obj, args); - }; - - /* back compat so jsonstatus can always be enabled */ - function genRow(data) { - if (typeof(data[4]) === "string" && data[4].indexOf("{") > -1) { - var tmp = $.parseJSON(data[4]); - data[4] = tmp.oldStatus; - data[5] = null; - } - return data; - } - - function genArray(obj) { - var data = obj.asArray(); - - for (var i in data) { - data[i] = genRow(data[i]); - } - - return data; - } - - - la.onChange = function(obj, args) { - var index = 0; - var iserr = 0; - - if (!dt) { - if (!config.aoColumns) { - if (args.action != "init") { - return; - } - - config.aoColumns = []; - - for (var i in args.data) { - config.aoColumns.push({ - "sTitle": args.data[i] - }); - } - } - - dt = jq.dataTable(config); - } - - if (dt && (args.action == "del" || args.action == "modify")) { - index = args.index; - - if (index === undefined && args.key) { - index = la.indexOf(args.key); - } - - if (index === undefined) { - console.error("INVALID PACKET Missing INDEX\n", args); - return; - } - } - - if (config.onChange) { - config.onChange(obj, args); - } - - try { - switch (args.action) { - case "bootObj": - if (!args.data) { - console.error("missing data"); - return; - } - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - dt.fnAdjustColumnSizing(); - break; - case "add": - if (!args.data) { - console.error("missing data"); - return; - } - if (args.redraw > -1) { - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - } else { - dt.fnAddData(genRow(args.data)); - } - dt.fnAdjustColumnSizing(); - break; - case "modify": - if (!args.data) { - return; - } - //console.debug(args, index); - dt.fnUpdate(genRow(args.data), index); - dt.fnAdjustColumnSizing(); - break; - case "del": - dt.fnDeleteRow(index); - dt.fnAdjustColumnSizing(); - break; - case "clear": - dt.fnClearTable(); - break; - case "reorder": - // specific position, more costly - dt.fnClearTable(); - dt.fnAddData(genArray(obj)); - break; - case "hide": - jq.hide(); - break; - - case "show": - jq.show(); - break; - - } - } catch(err) { - console.error("ERROR: " + err); - iserr++; - } - - if (iserr) { - obj.errs++; - if (obj.errs < 3) { - obj.bootstrap(obj.user_obj); - } - } else { - obj.errs = 0; - } - - }; - - la.onChange(la, { - action: "init" - }); - - }; - - var CONFMAN_SERNO = 1; - - /* - Conference Manager without jQuery table. - */ - - $.verto.conf = function(verto, params) { - var conf = this; - - conf.params = $.extend({ - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - conf.verto = verto; - conf.serno = CONFMAN_SERNO++; - - createMainModeratorMethods(); - - verto.subscribe(conf.params.laData.modChannel, { - handler: function(v, e) { - if (conf.params.onBroadcast) { - conf.params.onBroadcast(verto, conf, e.data); - } - } - }); - - verto.subscribe(conf.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(conf.params.infoCallback) === "function") { - conf.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(conf.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(conf.params.chatCallback) === "function") { - conf.params.chatCallback(v,e); - } - } - }); - }; - - $.verto.conf.prototype.modCommand = function(cmd, id, value) { - var conf = this; - - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.conf.prototype.destroy = function() { - var conf = this; - - conf.destroyed = true; - conf.params.onBroadcast(conf.verto, conf, 'destroy'); - - if (conf.params.laData.modChannel) { - conf.verto.unsubscribe(conf.params.laData.modChannel); - } - - if (conf.params.laData.chatChannel) { - conf.verto.unsubscribe(conf.params.laData.chatChannel); - } - - if (conf.params.laData.infoChannel) { - conf.verto.unsubscribe(conf.params.laData.infoChannel); - } - }; - - function createMainModeratorMethods() { - $.verto.conf.prototype.listVideoLayouts = function() { - this.modCommand("list-videoLayouts", null, null); - }; - - $.verto.conf.prototype.play = function(file) { - this.modCommand("play", null, file); - }; - - $.verto.conf.prototype.stop = function() { - this.modCommand("stop", null, "all"); - }; - - $.verto.conf.prototype.deaf = function(memberID) { - this.modCommand("deaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.undeaf = function(memberID) { - this.modCommand("undeaf", parseInt(memberID)); - }; - - $.verto.conf.prototype.record = function(file) { - this.modCommand("recording", null, ["start", file]); - }; - - $.verto.conf.prototype.stopRecord = function() { - this.modCommand("recording", null, ["stop", "all"]); - }; - - $.verto.conf.prototype.snapshot = function(file) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-write-png", null, file); - }; - - $.verto.conf.prototype.setVideoLayout = function(layout, canvasID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - if (canvasID) { - this.modCommand("vid-layout", null, [layout, canvasID]); - } else { - this.modCommand("vid-layout", null, layout); - } - }; - - $.verto.conf.prototype.kick = function(memberID) { - this.modCommand("kick", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteMic = function(memberID) { - this.modCommand("tmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.muteVideo = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("tvmute", parseInt(memberID)); - }; - - $.verto.conf.prototype.presenter = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-res-id", parseInt(memberID), "presenter"); - }; - - $.verto.conf.prototype.videoFloor = function(memberID) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-floor", parseInt(memberID), "force"); - }; - - $.verto.conf.prototype.banner = function(memberID, text) { - if (!this.params.hasVid) { - throw 'Conference has no video'; - } - this.modCommand("vid-banner", parseInt(memberID), escape(text)); - }; - - $.verto.conf.prototype.volumeDown = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.volumeUp = function(memberID) { - this.modCommand("volume_out", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.gainDown = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "down"); - }; - - $.verto.conf.prototype.gainUp = function(memberID) { - this.modCommand("volume_in", parseInt(memberID), "up"); - }; - - $.verto.conf.prototype.transfer = function(memberID, exten) { - this.modCommand("transfer", parseInt(memberID), exten); - }; - - $.verto.conf.prototype.sendChat = function(message, type) { - var conf = this; - conf.verto.rpcClient.call("verto.broadcast", { - "eventChannel": conf.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - } - - $.verto.modfuncs = {}; - - $.verto.confMan = function(verto, params) { - var confMan = this; - - confMan.params = $.extend({ - tableID: null, - statusID: null, - mainModID: null, - dialog: null, - hasVid: false, - laData: null, - onBroadcast: null, - onLaChange: null, - onLaRow: null - }, params); - - confMan.verto = verto; - confMan.serno = CONFMAN_SERNO++; - confMan.canvasCount = confMan.params.laData.canvasCount; - - function genMainMod(jq) { - var play_id = "play_" + confMan.serno; - var stop_id = "stop_" + confMan.serno; - var recording_id = "recording_" + confMan.serno; - var snapshot_id = "snapshot_" + confMan.serno; - var rec_stop_id = "recording_stop" + confMan.serno; - var div_id = "confman_" + confMan.serno; - - var html = "

" + - "" + - "" + - "" + - "" + - (confMan.params.hasVid ? "" : "") + - "

"; - - jq.html(html); - - $.verto.modfuncs.change_video_layout = function(id, canvas_id) { - var val = $("#" + id + " option:selected").text(); - if (val !== "none") { - confMan.modCommand("vid-layout", null, [val, canvas_id]); - } - }; - - if (confMan.params.hasVid) { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlayout_id = "confman_vid_layout_" + j + "_" + confMan.serno; - var vlselect_id = "confman_vl_select_" + j + "_" + confMan.serno; - - - var vlhtml = "

" + - "Video Layout Canvas " + (j+1) + - " " + - "

"; - jq.append(vlhtml); - } - - $("#" + snapshot_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("vid-write-png", null, file); - } - }); - } - - $("#" + play_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("play", null, file); - } - }); - - $("#" + stop_id).click(function() { - confMan.modCommand("stop", null, "all"); - }); - - $("#" + recording_id).click(function() { - var file = prompt("Please enter file name", ""); - if (file) { - confMan.modCommand("recording", null, ["start", file]); - } - }); - - $("#" + rec_stop_id).click(function() { - confMan.modCommand("recording", null, ["stop", "all"]); - }); - - } - - function genControls(jq, rowid) { - var x = parseInt(rowid); - var kick_id = "kick_" + x; - var canvas_in_next_id = "canvas_in_next_" + x; - var canvas_in_prev_id = "canvas_in_prev_" + x; - var canvas_out_next_id = "canvas_out_next_" + x; - var canvas_out_prev_id = "canvas_out_prev_" + x; - - var canvas_in_set_id = "canvas_in_set_" + x; - var canvas_out_set_id = "canvas_out_set_" + x; - - var layer_set_id = "layer_set_" + x; - var layer_next_id = "layer_next_" + x; - var layer_prev_id = "layer_prev_" + x; - - var tmute_id = "tmute_" + x; - var tvmute_id = "tvmute_" + x; - var vbanner_id = "vbanner_" + x; - var tvpresenter_id = "tvpresenter_" + x; - var tvfloor_id = "tvfloor_" + x; - var box_id = "box_" + x; - var gainup_id = "gain_in_up" + x; - var gaindn_id = "gain_in_dn" + x; - var volup_id = "vol_in_up" + x; - var voldn_id = "vol_in_dn" + x; - var transfer_id = "transfer" + x; - - - var html = "
"; - - html += "General Controls
"; - - html += "" + - "" + - "" + - "" + - "" + - "" + - ""; - - if (confMan.params.hasVid) { - html += "

Video Controls
"; - - - html += "" + - "" + - "" + - ""; - - if (confMan.canvasCount > 1) { - html += "

Canvas Controls
" + - "" + - "" + - "" + - - "
" + - - "" + - "" + - ""; - } - - html += "
" + - - "" + - "" + - "" + - - - - "
"; - } - - jq.html(html); - - - if (!jq.data("mouse")) { - $("#" + box_id).hide(); - } - - jq.mouseover(function(e) { - jq.data({"mouse": true}); - $("#" + box_id).show(); - }); - - jq.mouseout(function(e) { - jq.data({"mouse": false}); - $("#" + box_id).hide(); - }); - - $("#" + transfer_id).click(function() { - var xten = prompt("Enter Extension"); - if (xten) { - confMan.modCommand("transfer", x, xten); - } - }); - - $("#" + kick_id).click(function() { - confMan.modCommand("kick", x); - }); - - - $("#" + layer_set_id).click(function() { - var cid = prompt("Please enter layer ID", ""); - if (cid) { - confMan.modCommand("vid-layer", x, cid); - } - }); - - $("#" + layer_next_id).click(function() { - confMan.modCommand("vid-layer", x, "next"); - }); - $("#" + layer_prev_id).click(function() { - confMan.modCommand("vid-layer", x, "prev"); - }); - - $("#" + canvas_in_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-canvas", x, cid); - } - }); - - $("#" + canvas_out_set_id).click(function() { - var cid = prompt("Please enter canvas ID", ""); - if (cid) { - confMan.modCommand("vid-watching-canvas", x, cid); - } - }); - - $("#" + canvas_in_next_id).click(function() { - confMan.modCommand("vid-canvas", x, "next"); - }); - $("#" + canvas_in_prev_id).click(function() { - confMan.modCommand("vid-canvas", x, "prev"); - }); - - - $("#" + canvas_out_next_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "next"); - }); - $("#" + canvas_out_prev_id).click(function() { - confMan.modCommand("vid-watching-canvas", x, "prev"); - }); - - $("#" + tmute_id).click(function() { - confMan.modCommand("tmute", x); - }); - - if (confMan.params.hasVid) { - $("#" + tvmute_id).click(function() { - confMan.modCommand("tvmute", x); - }); - $("#" + tvpresenter_id).click(function() { - confMan.modCommand("vid-res-id", x, "presenter"); - }); - $("#" + tvfloor_id).click(function() { - confMan.modCommand("vid-floor", x, "force"); - }); - $("#" + vbanner_id).click(function() { - var text = prompt("Please enter text", ""); - if (text) { - confMan.modCommand("vid-banner", x, escape(text)); - } - }); - } - - $("#" + gainup_id).click(function() { - confMan.modCommand("volume_in", x, "up"); - }); - - $("#" + gaindn_id).click(function() { - confMan.modCommand("volume_in", x, "down"); - }); - - $("#" + volup_id).click(function() { - confMan.modCommand("volume_out", x, "up"); - }); - - $("#" + voldn_id).click(function() { - confMan.modCommand("volume_out", x, "down"); - }); - - return html; - } - - var atitle = ""; - var awidth = 0; - - //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px"); - - verto.subscribe(confMan.params.laData.infoChannel, { - handler: function(v, e) { - if (typeof(confMan.params.infoCallback) === "function") { - confMan.params.infoCallback(v,e); - } - } - }); - - verto.subscribe(confMan.params.laData.chatChannel, { - handler: function(v, e) { - if (typeof(confMan.params.chatCallback) === "function") { - confMan.params.chatCallback(v,e); - } - } - }); - - if (confMan.params.laData.role === "moderator") { - atitle = "Action"; - awidth = 600; - - if (confMan.params.mainModID) { - genMainMod($(confMan.params.mainModID)); - $(confMan.params.displayID).html("Moderator Controls Ready

"); - } else { - $(confMan.params.mainModID).html(""); - } - - verto.subscribe(confMan.params.laData.modChannel, { - handler: function(v, e) { - //console.error("MODDATA:", e.data); - if (confMan.params.onBroadcast) { - confMan.params.onBroadcast(verto, confMan, e.data); - } - - if (e.data["conf-command"] === "list-videoLayouts") { - for (var j = 0; j < confMan.canvasCount; j++) { - var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno; - var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno; - - var x = 0; - var options; - - $(vlselect_id).selectmenu({}); - $(vlselect_id).selectmenu("enable"); - $(vlselect_id).empty(); - - $(vlselect_id).append(new Option("Choose a Layout", "none")); - - if (e.data.responseData) { - var rdata = []; - - for (var i in e.data.responseData) { - rdata.push(e.data.responseData[i].name); - } - - options = rdata.sort(function(a, b) { - var ga = a.substring(0, 6) == "group:" ? true : false; - var gb = b.substring(0, 6) == "group:" ? true : false; - - if ((ga || gb) && ga != gb) { - return ga ? -1 : 1; - } - - return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) ); - }); - - for (var i in options) { - $(vlselect_id).append(new Option(options[i], options[i])); - x++; - } - } - - if (x) { - $(vlselect_id).selectmenu('refresh', true); - } else { - $(vlayout_id).hide(); - } - } - } else { - - if (!confMan.destroyed && confMan.params.displayID) { - $(confMan.params.displayID).html(e.data.response + "

"); - if (confMan.lastTimeout) { - clearTimeout(confMan.lastTimeout); - confMan.lastTimeout = 0; - } - confMan.lastTimeout = setTimeout(function() { $(confMan.params.displayID).html(confMan.destroyed ? "" : "Moderator Controls Ready

");}, 4000); - } - } - } - }); - - - if (confMan.params.hasVid) { - confMan.modCommand("list-videoLayouts", null, null); - } - } - - var row_callback = null; - - if (confMan.params.laData.role === "moderator") { - row_callback = function(nRow, aData, iDisplayIndex, iDisplayIndexFull) { - if (!aData[5]) { - var $row = $('td:eq(5)', nRow); - genControls($row, aData); - - if (confMan.params.onLaRow) { - confMan.params.onLaRow(verto, confMan, $row, aData); - } - } - }; - } - - confMan.lt = new $.verto.liveTable(verto, confMan.params.laData.laChannel, confMan.params.laData.laName, $(confMan.params.tableID), { - subParams: { - callID: confMan.params.dialog ? confMan.params.dialog.callID : null - }, - - "onChange": function(obj, args) { - $(confMan.params.statusID).text("Conference Members: " + " (" + obj.arrayLen() + " Total)"); - if (confMan.params.onLaChange) { - confMan.params.onLaChange(verto, confMan, $.verto.enum.confEvent.laChange, obj, args); - } - }, - - "aaData": [], - "aoColumns": [ - { - "sTitle": "ID", - "sWidth": "50" - }, - { - "sTitle": "Number", - "sWidth": "250" - }, - { - "sTitle": "Name", - "sWidth": "250" - }, - { - "sTitle": "Codec", - "sWidth": "100" - }, - { - "sTitle": "Status", - "sWidth": confMan.params.hasVid ? "200px" : "150px" - }, - { - "sTitle": atitle, - "sWidth": awidth, - } - ], - "bAutoWidth": true, - "bDestroy": true, - "bSort": false, - "bInfo": false, - "bFilter": false, - "bLengthChange": false, - "bPaginate": false, - "iDisplayLength": 1400, - - "oLanguage": { - "sEmptyTable": "The Conference is Empty....." - }, - - "fnRowCallback": row_callback - - }); - }; - - $.verto.confMan.prototype.modCommand = function(cmd, id, value) { - var confMan = this; - - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.modChannel, - "data": { - "application": "conf-control", - "command": cmd, - "id": id, - "value": value - } - }); - }; - - $.verto.confMan.prototype.sendChat = function(message, type) { - var confMan = this; - confMan.verto.rpcClient.call("verto.broadcast", { - "eventChannel": confMan.params.laData.chatChannel, - "data": { - "action": "send", - "message": message, - "type": type - } - }); - }; - - - $.verto.confMan.prototype.destroy = function() { - var confMan = this; - - confMan.destroyed = true; - - if (confMan.lt) { - confMan.lt.destroy(); - } - - if (confMan.params.laData.chatChannel) { - confMan.verto.unsubscribe(confMan.params.laData.chatChannel); - } - - if (confMan.params.laData.modChannel) { - confMan.verto.unsubscribe(confMan.params.laData.modChannel); - } - - if (confMan.params.mainModID) { - $(confMan.params.mainModID).html(""); - } - }; - - $.verto.dialog = function(direction, verto, params) { - var dialog = this; - - dialog.params = $.extend({ - useVideo: verto.options.useVideo, - useStereo: verto.options.useStereo, - screenShare: false, - useCamera: false, - useMic: verto.options.deviceParams.useMic, - useSpeak: verto.options.deviceParams.useSpeak, - tag: verto.options.tag, - localTag: verto.options.localTag, - login: verto.options.login, - videoParams: verto.options.videoParams, - useStream: verto.options.useStream, - }, params); - - - if (!dialog.params.screenShare) { - dialog.params.useCamera = verto.options.deviceParams.useCamera; - } - - dialog.verto = verto; - dialog.direction = direction; - dialog.lastState = null; - dialog.state = dialog.lastState = $.verto.enum.state.new; - dialog.callbacks = verto.callbacks; - dialog.answered = false; - dialog.attach = params.attach || false; - dialog.screenShare = params.screenShare || false; - dialog.useCamera = dialog.params.useCamera; - dialog.useMic = dialog.params.useMic; - dialog.useSpeak = dialog.params.useSpeak; - - if (dialog.params.callID) { - dialog.callID = dialog.params.callID; - } else { - dialog.callID = dialog.params.callID = generateGUID(); - } - - if (typeof(dialog.params.tag) === "function") { - dialog.params.tag = dialog.params.tag(); - } - - if (dialog.params.tag) { - dialog.audioStream = document.getElementById(dialog.params.tag); - - if (dialog.params.useVideo) { - dialog.videoStream = dialog.audioStream; - } - } //else conjure one TBD - - if (dialog.params.localTag) { - dialog.localVideo = document.getElementById(dialog.params.localTag); - } - - dialog.verto.dialogs[dialog.callID] = dialog; - - var RTCcallbacks = {}; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.params.display_direction === "outbound") { - dialog.params.remote_caller_id_name = dialog.params.caller_id_name; - dialog.params.remote_caller_id_number = dialog.params.caller_id_number; - } else { - dialog.params.remote_caller_id_name = dialog.params.callee_id_name; - dialog.params.remote_caller_id_number = dialog.params.callee_id_number; - } - - if (!dialog.params.remote_caller_id_name) { - dialog.params.remote_caller_id_name = "Nobody"; - } - - if (!dialog.params.remote_caller_id_number) { - dialog.params.remote_caller_id_number = "UNKNOWN"; - } - - RTCcallbacks.onMessage = function(rtc, msg) { - console.debug(msg); - }; - - RTCcallbacks.onAnswerSDP = function(rtc, sdp) { - console.error("answer sdp", sdp); - }; - } else { - dialog.params.remote_caller_id_name = "Outbound Call"; - dialog.params.remote_caller_id_number = dialog.params.destination_number; - } - - RTCcallbacks.onICESDP = function(rtc) { - console.log("RECV " + rtc.type + " SDP", rtc.mediaData.SDP); - - if (dialog.state == $.verto.enum.state.requesting || dialog.state == $.verto.enum.state.answering || dialog.state == $.verto.enum.state.active) { - location.reload(); - return; - } - - if (rtc.type == "offer") { - if (dialog.state == $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.requesting); - dialog.sendMethod("verto.attach", { - sdp: rtc.mediaData.SDP - }); - } else { - dialog.setState($.verto.enum.state.requesting); - - dialog.sendMethod("verto.invite", { - sdp: rtc.mediaData.SDP - }); - } - } else { //answer - dialog.setState($.verto.enum.state.answering); - - dialog.sendMethod(dialog.attach ? "verto.attach" : "verto.answer", { - sdp: dialog.rtc.mediaData.SDP - }); - } - }; - - RTCcallbacks.onICE = function(rtc) { - //console.log("cand", rtc.mediaData.candidate); - if (rtc.type == "offer") { - console.log("offer", rtc.mediaData.candidate); - return; - } - }; - - RTCcallbacks.onStream = function(rtc, stream) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onGranted === 'function') { - dialog.callbacks.permissionCallback.onGranted(stream); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onGranted === 'function'){ - dialog.verto.options.permissionCallback.onGranted(stream); - } - console.log("stream started"); - }; - - RTCcallbacks.onRemoteStream = function(rtc, stream) { - if (typeof dialog.callbacks.onRemoteStream === 'function') { - dialog.callbacks.onRemoteStream(stream, dialog); - } - console.log("remote stream started"); - }; - - RTCcallbacks.onError = function(e) { - if (dialog.callbacks.permissionCallback && - typeof dialog.callbacks.permissionCallback.onDenied === 'function') { - dialog.callbacks.permissionCallback.onDenied(); - } - else if (dialog.verto.options.permissionCallback && - typeof dialog.verto.options.permissionCallback.onDenied === 'function'){ - dialog.verto.options.permissionCallback.onDenied(); - } - console.error("ERROR:", e); - dialog.hangup({cause: "Device or Permission Error"}); - }; - - dialog.rtc = new $.FSRTC({ - callbacks: RTCcallbacks, - localVideo: dialog.screenShare ? null : dialog.localVideo, - useVideo: dialog.params.useVideo ? dialog.videoStream : null, - useAudio: dialog.audioStream, - useStereo: dialog.params.useStereo, - videoParams: dialog.params.videoParams, - audioParams: verto.options.audioParams, - iceServers: verto.options.iceServers, - screenShare: dialog.screenShare, - useCamera: dialog.useCamera, - useMic: dialog.useMic, - useSpeak: dialog.useSpeak, - turnServer: verto.options.turnServer, - useStream: dialog.params.useStream - }); - - dialog.rtc.verto = dialog.verto; - - if (dialog.direction == $.verto.enum.direction.inbound) { - if (dialog.attach) { - dialog.answer(); - } else { - dialog.ring(); - } - } - }; - - $.verto.dialog.prototype.invite = function() { - var dialog = this; - dialog.rtc.call(); - }; - - $.verto.dialog.prototype.sendMethod = function(method, obj) { - var dialog = this; - obj.dialogParams = {}; - - for (var i in dialog.params) { - if (i == "sdp" && method != "verto.invite" && method != "verto.attach") { - continue; - } - - if ((obj.noDialogParams && i != "callID")) { - continue; - } - - obj.dialogParams[i] = dialog.params[i]; - } - - delete obj.noDialogParams; - - dialog.verto.rpcClient.call(method, obj, - - function(e) { - /* Success */ - dialog.processReply(method, true, e); - }, - - function(e) { - /* Error */ - dialog.processReply(method, false, e); - }); - }; - - function checkStateChange(oldS, newS) { - - if (newS == $.verto.enum.state.purge || $.verto.enum.states[oldS.name][newS.name]) { - return true; - } - - return false; - } - - - // Attach audio output device to video element using device/sink ID. - function find_name(id) { - for (var i in $.verto.audioOutDevices) { - var source = $.verto.audioOutDevices[i]; - if (source.id === id) { - return(source.label); - } - } - - return id; - } - - $.verto.dialog.prototype.setAudioPlaybackDevice = function(sinkId, callback, arg) { - var dialog = this; - var element = dialog.audioStream; - - if (typeof element.sinkId !== 'undefined') { - var devname = find_name(sinkId); - console.info("Dialog: " + dialog.callID + " Setting speaker:", element, devname); - - element.setSinkId(sinkId) - .then(function() { - console.log("Dialog: " + dialog.callID + ' Success, audio output device attached: ' + sinkId); - if (callback) { - callback(true, devname, arg); - } - }) - .catch(function(error) { - var errorMessage = error; - if (error.name === 'SecurityError') { - errorMessage = "Dialog: " + dialog.callID + ' You need to use HTTPS for selecting audio output ' + - 'device: ' + error; - } - if (callback) { - callback(false, null, arg); - } - console.error(errorMessage); - }); - } else { - console.warn("Dialog: " + dialog.callID + ' Browser does not support output device selection.'); - if (callback) { - callback(false, null, arg); - } - } - } - - $.verto.dialog.prototype.setState = function(state) { - var dialog = this; - - if (dialog.state == $.verto.enum.state.ringing) { - dialog.stopRinging(); - } - - if (dialog.state == state || !checkStateChange(dialog.state, state)) { - console.error("Dialog " + dialog.callID + ": INVALID state change from " + dialog.state.name + " to " + state.name); - dialog.hangup(); - return false; - } - - console.log("Dialog " + dialog.callID + ": state change from " + dialog.state.name + " to " + state.name); - - dialog.lastState = dialog.state; - dialog.state = state; - - if (dialog.callbacks.onDialogState) { - dialog.callbacks.onDialogState(this); - } - - switch (dialog.state) { - - case $.verto.enum.state.early: - case $.verto.enum.state.active: - - var speaker = dialog.useSpeak; - console.info("Using Speaker: ", speaker); - - if (speaker && speaker !== "any" && speaker !== "none") { - setTimeout(function() { - dialog.setAudioPlaybackDevice(speaker); - }, 500); - } - - break; - - case $.verto.enum.state.trying: - setTimeout(function() { - if (dialog.state == $.verto.enum.state.trying) { - dialog.setState($.verto.enum.state.hangup); - } - }, 30000); - break; - case $.verto.enum.state.purge: - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.hangup: - - if (dialog.lastState.val > $.verto.enum.state.requesting.val && dialog.lastState.val < $.verto.enum.state.hangup.val) { - dialog.sendMethod("verto.bye", {}); - } - - dialog.setState($.verto.enum.state.destroy); - break; - case $.verto.enum.state.destroy: - - if (typeof(dialog.verto.options.tag) === "function") { - $('#' + dialog.params.tag).remove(); - } - - delete dialog.verto.dialogs[dialog.callID]; - if (dialog.params.screenShare) { - dialog.rtc.stopPeer(); - } else { - dialog.rtc.stop(); - } - break; - } - - return true; - }; - - $.verto.dialog.prototype.processReply = function(method, success, e) { - var dialog = this; - - //console.log("Response: " + method + " State:" + dialog.state.name, success, e); - - switch (method) { - - case "verto.answer": - case "verto.attach": - if (success) { - dialog.setState($.verto.enum.state.active); - } else { - dialog.hangup(); - } - break; - case "verto.invite": - if (success) { - dialog.setState($.verto.enum.state.trying); - } else { - dialog.setState($.verto.enum.state.destroy); - } - break; - - case "verto.bye": - dialog.hangup(); - break; - - case "verto.modify": - if (e.holdState) { - if (e.holdState == "held") { - if (dialog.state != $.verto.enum.state.held) { - dialog.setState($.verto.enum.state.held); - } - } else if (e.holdState == "active") { - if (dialog.state != $.verto.enum.state.active) { - dialog.setState($.verto.enum.state.active); - } - } - } - - if (success) {} - - break; - - default: - break; - } - - }; - - $.verto.dialog.prototype.hangup = function(params) { - var dialog = this; - - if (params) { - if (params.causeCode) { - dialog.causeCode = params.causeCode; - } - - if (params.cause) { - dialog.cause = params.cause; - } - } - - if (!dialog.cause && !dialog.causeCode) { - dialog.cause = "NORMAL_CLEARING"; - } - - if (dialog.state.val >= $.verto.enum.state.new.val && dialog.state.val < $.verto.enum.state.hangup.val) { - dialog.setState($.verto.enum.state.hangup); - } else if (dialog.state.val < $.verto.enum.state.destroy) { - dialog.setState($.verto.enum.state.destroy); - } - }; - - $.verto.dialog.prototype.stopRinging = function() { - var dialog = this; - if (dialog.verto.ringer) { - dialog.verto.ringer.stop(); - } - }; - - $.verto.dialog.prototype.indicateRing = function() { - var dialog = this; - - if (dialog.verto.ringer) { - dialog.verto.ringer.attr("src", dialog.verto.options.ringFile)[0].play(); - - setTimeout(function() { - dialog.stopRinging(); - if (dialog.state == $.verto.enum.state.ringing) { - dialog.indicateRing(); - } - }, - dialog.verto.options.ringSleep); - } - }; - - $.verto.dialog.prototype.ring = function() { - var dialog = this; - - dialog.setState($.verto.enum.state.ringing); - dialog.indicateRing(); - }; - - $.verto.dialog.prototype.useVideo = function(on) { - var dialog = this; - - dialog.params.useVideo = on; - - if (on) { - dialog.videoStream = dialog.audioStream; - } else { - dialog.videoStream = null; - } - - dialog.rtc.useVideo(dialog.videoStream, dialog.localVideo); - - }; - - $.verto.dialog.prototype.setMute = function(what) { - var dialog = this; - return dialog.rtc.setMute(what); - }; - - $.verto.dialog.prototype.getMute = function() { - var dialog = this; - return dialog.rtc.getMute(); - }; - - $.verto.dialog.prototype.setVideoMute = function(what) { - var dialog = this; - return dialog.rtc.setVideoMute(what); - }; - - $.verto.dialog.prototype.getVideoMute = function() { - var dialog = this; - return dialog.rtc.getVideoMute(); - }; - - $.verto.dialog.prototype.useStereo = function(on) { - var dialog = this; - - dialog.params.useStereo = on; - dialog.rtc.useStereo(on); - }; - - $.verto.dialog.prototype.dtmf = function(digits) { - var dialog = this; - if (digits) { - dialog.sendMethod("verto.info", { - dtmf: digits - }); - } - }; - - $.verto.dialog.prototype.rtt = function(obj) { - var dialog = this; - var pobj = {}; - - if (!obj) { - return false; - } - - pobj.code = obj.code; - pobj.chars = obj.chars; - - - if (pobj.chars || pobj.code) { - dialog.sendMethod("verto.info", { - txt: obj, - noDialogParams: true - }); - } - }; - - $.verto.dialog.prototype.transfer = function(dest, params) { - var dialog = this; - if (dest) { - dialog.sendMethod("verto.modify", { - action: "transfer", - destination: dest, - params: params - }); - } - }; - - $.verto.dialog.prototype.replace = function(replaceCallID, params) { - var dialog = this; - if (replaceCallID) { - dialog.sendMethod("verto.modify", { - action: "replace", - replaceCallID: replaceCallID, - params: params - }); - } - }; - - $.verto.dialog.prototype.hold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "hold", - params: params - }); - }; - - $.verto.dialog.prototype.unhold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "unhold", - params: params - }); - }; - - $.verto.dialog.prototype.toggleHold = function(params) { - var dialog = this; - - dialog.sendMethod("verto.modify", { - action: "toggleHold", - params: params - }); - }; - - $.verto.dialog.prototype.message = function(msg) { - var dialog = this; - var err = 0; - - msg.from = dialog.params.login; - - if (!msg.to) { - console.error("Missing To"); - err++; - } - - if (!msg.body) { - console.error("Missing Body"); - err++; - } - - if (err) { - return false; - } - - dialog.sendMethod("verto.info", { - msg: msg - }); - - return true; - }; - - $.verto.dialog.prototype.answer = function(params) { - var dialog = this; - - if (!dialog.answered) { - if (!params) { - params = {}; - } - - params.sdp = dialog.params.sdp; - - if (params) { - if (params.useVideo) { - dialog.useVideo(true); - } - dialog.params.callee_id_name = params.callee_id_name; - dialog.params.callee_id_number = params.callee_id_number; - - if (params.useCamera) { - dialog.useCamera = params.useCamera; - } - - if (params.useMic) { - dialog.useMic = params.useMic; - } - - if (params.useSpeak) { - dialog.useSpeak = params.useSpeak; - } - } - - dialog.rtc.createAnswer(params); - dialog.answered = true; - } - }; - - $.verto.dialog.prototype.handleAnswer = function(params) { - var dialog = this; - - dialog.gotAnswer = true; - - if (dialog.state.val >= $.verto.enum.state.active.val) { - return; - } - - if (dialog.state.val >= $.verto.enum.state.early.val) { - dialog.setState($.verto.enum.state.active); - } else { - if (dialog.gotEarly) { - console.log("Dialog " + dialog.callID + " Got answer while still establishing early media, delaying..."); - } else { - console.log("Dialog " + dialog.callID + " Answering Channel"); - dialog.rtc.answer(params.sdp, function() { - dialog.setState($.verto.enum.state.active); - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "ANSWER SDP", params.sdp); - } - } - - - }; - - $.verto.dialog.prototype.cidString = function(enc) { - var dialog = this; - var party = dialog.params.remote_caller_id_name + (enc ? " <" : " <") + dialog.params.remote_caller_id_number + (enc ? ">" : ">"); - return party; - }; - - $.verto.dialog.prototype.sendMessage = function(msg, params) { - var dialog = this; - - if (dialog.callbacks.onMessage) { - dialog.callbacks.onMessage(dialog.verto, dialog, msg, params); - } - }; - - $.verto.dialog.prototype.handleInfo = function(params) { - var dialog = this; - - dialog.sendMessage($.verto.enum.message.info, params); - - }; - - $.verto.dialog.prototype.handleDisplay = function(params) { - var dialog = this; - - if (params.display_name) { - dialog.params.remote_caller_id_name = params.display_name; - } - if (params.display_number) { - dialog.params.remote_caller_id_number = params.display_number; - } - - dialog.sendMessage($.verto.enum.message.display, {}); - }; - - $.verto.dialog.prototype.handleMedia = function(params) { - var dialog = this; - - if (dialog.state.val >= $.verto.enum.state.early.val) { - return; - } - - dialog.gotEarly = true; - - dialog.rtc.answer(params.sdp, function() { - console.log("Dialog " + dialog.callID + "Establishing early media"); - dialog.setState($.verto.enum.state.early); - - if (dialog.gotAnswer) { - console.log("Dialog " + dialog.callID + "Answering Channel"); - dialog.setState($.verto.enum.state.active); - } - }, function(e) { - console.error(e); - dialog.hangup(); - }); - console.log("Dialog " + dialog.callID + "EARLY SDP", params.sdp); - }; - - $.verto.ENUM = function(s) { - var i = 0, - o = {}; - s.split(" ").map(function(x) { - o[x] = { - name: x, - val: i++ - }; - }); - return Object.freeze(o); - }; - - $.verto.enum = {}; - - $.verto.enum.states = Object.freeze({ - new: { - requesting: 1, - recovering: 1, - ringing: 1, - destroy: 1, - answering: 1, - hangup: 1 - }, - requesting: { - trying: 1, - hangup: 1, - active: 1 - }, - recovering: { - answering: 1, - hangup: 1 - }, - trying: { - active: 1, - early: 1, - hangup: 1 - }, - ringing: { - answering: 1, - hangup: 1 - }, - answering: { - active: 1, - hangup: 1 - }, - active: { - answering: 1, - requesting: 1, - hangup: 1, - held: 1 - }, - held: { - hangup: 1, - active: 1 - }, - early: { - hangup: 1, - active: 1 - }, - hangup: { - destroy: 1 - }, - destroy: {}, - purge: { - destroy: 1 - } - }); - - $.verto.enum.state = $.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge"); - $.verto.enum.direction = $.verto.ENUM("inbound outbound"); - $.verto.enum.message = $.verto.ENUM("display info pvtEvent clientReady"); - - $.verto.enum = Object.freeze($.verto.enum); - - $.verto.saved = []; - - $.verto.unloadJobs = []; - - var unloadEventName = 'beforeunload'; - // Hacks for Mobile Safari - var iOS = ['iPad', 'iPhone', 'iPod'].indexOf(navigator.platform) >= 0; - if (iOS) { - unloadEventName = 'pagehide'; - } - - $(window).bind(unloadEventName, function() { - for (var f in $.verto.unloadJobs) { - $.verto.unloadJobs[f](); - } - - if ($.verto.haltClosure) - return $.verto.haltClosure(); - - for (var i in $.verto.saved) { - var verto = $.verto.saved[i]; - if (verto) { - verto.purge(); - verto.logout(); - } - } - - return $.verto.warnOnUnload; - }); - - $.verto.videoDevices = []; - $.verto.audioInDevices = []; - $.verto.audioOutDevices = []; - - var checkDevices = function(runtime) { - console.info("enumerating devices"); - var aud_in = [], aud_out = [], vid = []; - var has_video = 0, has_audio = 0; - var Xstream; - - function gotDevices(deviceInfos) { - // Handles being called several times to update labels. Preserve values. - for (var i = 0; i !== deviceInfos.length; ++i) { - var deviceInfo = deviceInfos[i]; - var text = ""; - - console.log(deviceInfo); - console.log(deviceInfo.kind + ": " + deviceInfo.label + " id = " + deviceInfo.deviceId); - - if (deviceInfo.kind === 'audioinput') { - text = deviceInfo.label || 'microphone ' + (aud_in.length + 1); - aud_in.push({id: deviceInfo.deviceId, kind: "audio_in", label: text}); - } else if (deviceInfo.kind === 'audiooutput') { - text = deviceInfo.label || 'speaker ' + (aud_out.length + 1); - aud_out.push({id: deviceInfo.deviceId, kind: "audio_out", label: text}); - } else if (deviceInfo.kind === 'videoinput') { - text = deviceInfo.label || 'camera ' + (vid.length + 1); - vid.push({id: deviceInfo.deviceId, kind: "video", label: text}); - } else { - console.log('Some other kind of source/device: ', deviceInfo); - } - } - - - $.verto.videoDevices = vid; - $.verto.audioInDevices = aud_in; - $.verto.audioOutDevices = aud_out; - - console.info("Audio IN Devices", $.verto.audioInDevices); - console.info("Audio Out Devices", $.verto.audioOutDevices); - console.info("Video Devices", $.verto.videoDevices); - - if (Xstream) { - Xstream.getTracks().forEach(function(track) {track.stop();}); - } - - if (runtime) { - runtime(true); - } - } - - - - - function handleError(error) { - console.log('device enumeration error: ', error); - if (runtime) runtime(false); - } - - - function checkTypes(devs) { - for (var i = 0; i !== devs.length; ++i) { - - if (devs[i].kind === 'audioinput') { - has_audio++; - } else if (devs[i].kind === 'videoinput') { - has_video++; - } - } - - navigator.getUserMedia({ audio: (has_audio > 0 ? true : false), video: (has_video > 0 ? true : false)}, - function(stream) { - Xstream = stream; - navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError); - }, - function(err) { - console.log("The following error occurred: " + err.name); - } - ); - } - - navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError); - - }; - - $.verto.refreshDevices = function(runtime) { - checkDevices(runtime); - } - - $.verto.init = function(obj, runtime) { - if (!obj) { - obj = {}; - } - - if (!obj.skipPermCheck && !obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - checkDevices(runtime); - }, true, true); - } else if (obj.skipPermCheck && !obj.skipDeviceCheck) { - checkDevices(runtime); - } else if (!obj.skipPermCheck && obj.skipDeviceCheck) { - $.FSRTC.checkPerms(function(status) { - runtime(status); - }, true, true); - } else { - runtime(null); - } - - } - - $.verto.genUUID = function () { - return generateGUID(); - } - - -})(jQuery); -(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o= 14393 && - url.indexOf('?transport=udp') === -1; - }); - - delete server.url; - server.urls = isString ? urls[0] : urls; - return !!urls.length; - } - }); -} - -// Determines the intersection of local and remote capabilities. -function getCommonCapabilities(localCapabilities, remoteCapabilities) { - var commonCapabilities = { - codecs: [], - headerExtensions: [], - fecMechanisms: [] - }; - - var findCodecByPayloadType = function(pt, codecs) { - pt = parseInt(pt, 10); - for (var i = 0; i < codecs.length; i++) { - if (codecs[i].payloadType === pt || - codecs[i].preferredPayloadType === pt) { - return codecs[i]; - } - } - }; - - var rtxCapabilityMatches = function(lRtx, rRtx, lCodecs, rCodecs) { - var lCodec = findCodecByPayloadType(lRtx.parameters.apt, lCodecs); - var rCodec = findCodecByPayloadType(rRtx.parameters.apt, rCodecs); - return lCodec && rCodec && - lCodec.name.toLowerCase() === rCodec.name.toLowerCase(); - }; - - localCapabilities.codecs.forEach(function(lCodec) { - for (var i = 0; i < remoteCapabilities.codecs.length; i++) { - var rCodec = remoteCapabilities.codecs[i]; - if (lCodec.name.toLowerCase() === rCodec.name.toLowerCase() && - lCodec.clockRate === rCodec.clockRate) { - if (lCodec.name.toLowerCase() === 'rtx' && - lCodec.parameters && rCodec.parameters.apt) { - // for RTX we need to find the local rtx that has a apt - // which points to the same local codec as the remote one. - if (!rtxCapabilityMatches(lCodec, rCodec, - localCapabilities.codecs, remoteCapabilities.codecs)) { - continue; - } - } - rCodec = JSON.parse(JSON.stringify(rCodec)); // deepcopy - // number of channels is the highest common number of channels - rCodec.numChannels = Math.min(lCodec.numChannels, - rCodec.numChannels); - // push rCodec so we reply with offerer payload type - commonCapabilities.codecs.push(rCodec); - - // determine common feedback mechanisms - rCodec.rtcpFeedback = rCodec.rtcpFeedback.filter(function(fb) { - for (var j = 0; j < lCodec.rtcpFeedback.length; j++) { - if (lCodec.rtcpFeedback[j].type === fb.type && - lCodec.rtcpFeedback[j].parameter === fb.parameter) { - return true; - } - } - return false; - }); - // FIXME: also need to determine .parameters - // see https://github.com/openpeer/ortc/issues/569 - break; - } - } - }); - - localCapabilities.headerExtensions.forEach(function(lHeaderExtension) { - for (var i = 0; i < remoteCapabilities.headerExtensions.length; - i++) { - var rHeaderExtension = remoteCapabilities.headerExtensions[i]; - if (lHeaderExtension.uri === rHeaderExtension.uri) { - commonCapabilities.headerExtensions.push(rHeaderExtension); - break; - } - } - }); - - // FIXME: fecMechanisms - return commonCapabilities; -} - -// is action=setLocalDescription with type allowed in signalingState -function isActionAllowedInSignalingState(action, type, signalingState) { - return { - offer: { - setLocalDescription: ['stable', 'have-local-offer'], - setRemoteDescription: ['stable', 'have-remote-offer'] - }, - answer: { - setLocalDescription: ['have-remote-offer', 'have-local-pranswer'], - setRemoteDescription: ['have-local-offer', 'have-remote-pranswer'] - } - }[type][action].indexOf(signalingState) !== -1; -} - -function maybeAddCandidate(iceTransport, candidate) { - // Edge's internal representation adds some fields therefore - // not all fieldѕ are taken into account. - var alreadyAdded = iceTransport.getRemoteCandidates() - .find(function(remoteCandidate) { - return candidate.foundation === remoteCandidate.foundation && - candidate.ip === remoteCandidate.ip && - candidate.port === remoteCandidate.port && - candidate.priority === remoteCandidate.priority && - candidate.protocol === remoteCandidate.protocol && - candidate.type === remoteCandidate.type; - }); - if (!alreadyAdded) { - iceTransport.addRemoteCandidate(candidate); - } - return !alreadyAdded; -} - - -// https://w3c.github.io/mediacapture-main/#mediastream -// Helper function to add the track to the stream and -// dispatch the event ourselves. -function addTrackToStreamAndFireEvent(track, stream) { - stream.addTrack(track); - var e = new Event('addtrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function removeTrackFromStreamAndFireEvent(track, stream) { - stream.removeTrack(track); - var e = new Event('removetrack'); // TODO: MediaStreamTrackEvent - e.track = track; - stream.dispatchEvent(e); -} - -function fireAddTrack(pc, track, receiver, streams) { - var trackEvent = new Event('track'); - trackEvent.track = track; - trackEvent.receiver = receiver; - trackEvent.transceiver = {receiver: receiver}; - trackEvent.streams = streams; - window.setTimeout(function() { - pc._dispatchEvent('track', trackEvent); - }); -} - -function makeError(name, description) { - var e = new Error(description); - e.name = name; - return e; -} - -module.exports = function(window, edgeVersion) { - var RTCPeerConnection = function(config) { - var pc = this; - - var _eventTarget = document.createDocumentFragment(); - ['addEventListener', 'removeEventListener', 'dispatchEvent'] - .forEach(function(method) { - pc[method] = _eventTarget[method].bind(_eventTarget); - }); - - this.canTrickleIceCandidates = null; - - this.needNegotiation = false; - - this.localStreams = []; - this.remoteStreams = []; - - this.localDescription = null; - this.remoteDescription = null; - - this.signalingState = 'stable'; - this.iceConnectionState = 'new'; - this.iceGatheringState = 'new'; - - config = JSON.parse(JSON.stringify(config || {})); - - this.usingBundle = config.bundlePolicy === 'max-bundle'; - if (config.rtcpMuxPolicy === 'negotiate') { - throw(makeError('NotSupportedError', - 'rtcpMuxPolicy \'negotiate\' is not supported')); - } else if (!config.rtcpMuxPolicy) { - config.rtcpMuxPolicy = 'require'; - } - - switch (config.iceTransportPolicy) { - case 'all': - case 'relay': - break; - default: - config.iceTransportPolicy = 'all'; - break; - } - - switch (config.bundlePolicy) { - case 'balanced': - case 'max-compat': - case 'max-bundle': - break; - default: - config.bundlePolicy = 'balanced'; - break; - } - - config.iceServers = filterIceServers(config.iceServers || [], edgeVersion); - - this._iceGatherers = []; - if (config.iceCandidatePoolSize) { - for (var i = config.iceCandidatePoolSize; i > 0; i--) { - this._iceGatherers = new window.RTCIceGatherer({ - iceServers: config.iceServers, - gatherPolicy: config.iceTransportPolicy - }); - } - } else { - config.iceCandidatePoolSize = 0; - } - - this._config = config; - - // per-track iceGathers, iceTransports, dtlsTransports, rtpSenders, ... - // everything that is needed to describe a SDP m-line. - this.transceivers = []; - - this._sdpSessionId = SDPUtils.generateSessionId(); - this._sdpSessionVersion = 0; - - this._dtlsRole = undefined; // role for a=setup to use in answers. - - this._isClosed = false; - }; - - // set up event handlers on prototype - RTCPeerConnection.prototype.onicecandidate = null; - RTCPeerConnection.prototype.onaddstream = null; - RTCPeerConnection.prototype.ontrack = null; - RTCPeerConnection.prototype.onremovestream = null; - RTCPeerConnection.prototype.onsignalingstatechange = null; - RTCPeerConnection.prototype.oniceconnectionstatechange = null; - RTCPeerConnection.prototype.onicegatheringstatechange = null; - RTCPeerConnection.prototype.onnegotiationneeded = null; - RTCPeerConnection.prototype.ondatachannel = null; - - RTCPeerConnection.prototype._dispatchEvent = function(name, event) { - if (this._isClosed) { - return; - } - this.dispatchEvent(event); - if (typeof this['on' + name] === 'function') { - this['on' + name](event); - } - }; - - RTCPeerConnection.prototype._emitGatheringStateChange = function() { - var event = new Event('icegatheringstatechange'); - this._dispatchEvent('icegatheringstatechange', event); - }; - - RTCPeerConnection.prototype.getConfiguration = function() { - return this._config; - }; - - RTCPeerConnection.prototype.getLocalStreams = function() { - return this.localStreams; - }; - - RTCPeerConnection.prototype.getRemoteStreams = function() { - return this.remoteStreams; - }; - - // internal helper to create a transceiver object. - // (whih is not yet the same as the WebRTC 1.0 transceiver) - RTCPeerConnection.prototype._createTransceiver = function(kind) { - var hasBundleTransport = this.transceivers.length > 0; - var transceiver = { - track: null, - iceGatherer: null, - iceTransport: null, - dtlsTransport: null, - localCapabilities: null, - remoteCapabilities: null, - rtpSender: null, - rtpReceiver: null, - kind: kind, - mid: null, - sendEncodingParameters: null, - recvEncodingParameters: null, - stream: null, - associatedRemoteMediaStreams: [], - wantReceive: true - }; - if (this.usingBundle && hasBundleTransport) { - transceiver.iceTransport = this.transceivers[0].iceTransport; - transceiver.dtlsTransport = this.transceivers[0].dtlsTransport; - } else { - var transports = this._createIceAndDtlsTransports(); - transceiver.iceTransport = transports.iceTransport; - transceiver.dtlsTransport = transports.dtlsTransport; - } - this.transceivers.push(transceiver); - return transceiver; - }; - - RTCPeerConnection.prototype.addTrack = function(track, stream) { - var alreadyExists = this.transceivers.find(function(s) { - return s.track === track; - }); - - if (alreadyExists) { - throw makeError('InvalidAccessError', 'Track already exists.'); - } - - if (this.signalingState === 'closed') { - throw makeError('InvalidStateError', - 'Attempted to call addTrack on a closed peerconnection.'); - } - - var transceiver; - for (var i = 0; i < this.transceivers.length; i++) { - if (!this.transceivers[i].track && - this.transceivers[i].kind === track.kind) { - transceiver = this.transceivers[i]; - } - } - if (!transceiver) { - transceiver = this._createTransceiver(track.kind); - } - - this._maybeFireNegotiationNeeded(); - - if (this.localStreams.indexOf(stream) === -1) { - this.localStreams.push(stream); - } - - transceiver.track = track; - transceiver.stream = stream; - transceiver.rtpSender = new window.RTCRtpSender(track, - transceiver.dtlsTransport); - return transceiver.rtpSender; - }; - - RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - if (edgeVersion >= 15025) { - stream.getTracks().forEach(function(track) { - pc.addTrack(track, stream); - }); - } else { - // Clone is necessary for local demos mostly, attaching directly - // to two different senders does not work (build 10547). - // Fixed in 15025 (or earlier) - var clonedStream = stream.clone(); - stream.getTracks().forEach(function(track, idx) { - var clonedTrack = clonedStream.getTracks()[idx]; - track.addEventListener('enabled', function(event) { - clonedTrack.enabled = event.enabled; - }); - }); - clonedStream.getTracks().forEach(function(track) { - pc.addTrack(track, clonedStream); - }); - } - }; - - RTCPeerConnection.prototype.removeTrack = function(sender) { - if (!(sender instanceof window.RTCRtpSender)) { - throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.'); - } - - var transceiver = this.transceivers.find(function(t) { - return t.rtpSender === sender; - }); - - if (!transceiver) { - throw makeError('InvalidAccessError', - 'Sender was not created by this connection.'); - } - var stream = transceiver.stream; - - transceiver.rtpSender.stop(); - transceiver.rtpSender = null; - transceiver.track = null; - transceiver.stream = null; - - // remove the stream from the set of local streams - var localStreams = this.transceivers.map(function(t) { - return t.stream; - }); - if (localStreams.indexOf(stream) === -1 && - this.localStreams.indexOf(stream) > -1) { - this.localStreams.splice(this.localStreams.indexOf(stream), 1); - } - - this._maybeFireNegotiationNeeded(); - }; - - RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - stream.getTracks().forEach(function(track) { - var sender = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (sender) { - pc.removeTrack(sender); - } - }); - }; - - RTCPeerConnection.prototype.getSenders = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpSender; - }) - .map(function(transceiver) { - return transceiver.rtpSender; - }); - }; - - RTCPeerConnection.prototype.getReceivers = function() { - return this.transceivers.filter(function(transceiver) { - return !!transceiver.rtpReceiver; - }) - .map(function(transceiver) { - return transceiver.rtpReceiver; - }); - }; - - - RTCPeerConnection.prototype._createIceGatherer = function(sdpMLineIndex, - usingBundle) { - var pc = this; - if (usingBundle && sdpMLineIndex > 0) { - return this.transceivers[0].iceGatherer; - } else if (this._iceGatherers.length) { - return this._iceGatherers.shift(); - } - var iceGatherer = new window.RTCIceGatherer({ - iceServers: this._config.iceServers, - gatherPolicy: this._config.iceTransportPolicy - }); - Object.defineProperty(iceGatherer, 'state', - {value: 'new', writable: true} - ); - - this.transceivers[sdpMLineIndex].candidates = []; - this.transceivers[sdpMLineIndex].bufferCandidates = function(event) { - var end = !event.candidate || Object.keys(event.candidate).length === 0; - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - iceGatherer.state = end ? 'completed' : 'gathering'; - if (pc.transceivers[sdpMLineIndex].candidates !== null) { - pc.transceivers[sdpMLineIndex].candidates.push(event.candidate); - } - }; - iceGatherer.addEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - return iceGatherer; - }; - - // start gathering from an RTCIceGatherer. - RTCPeerConnection.prototype._gather = function(mid, sdpMLineIndex) { - var pc = this; - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer.onlocalcandidate) { - return; - } - var candidates = this.transceivers[sdpMLineIndex].candidates; - this.transceivers[sdpMLineIndex].candidates = null; - iceGatherer.removeEventListener('localcandidate', - this.transceivers[sdpMLineIndex].bufferCandidates); - iceGatherer.onlocalcandidate = function(evt) { - if (pc.usingBundle && sdpMLineIndex > 0) { - // if we know that we use bundle we can drop candidates with - // ѕdpMLineIndex > 0. If we don't do this then our state gets - // confused since we dispose the extra ice gatherer. - return; - } - var event = new Event('icecandidate'); - event.candidate = {sdpMid: mid, sdpMLineIndex: sdpMLineIndex}; - - var cand = evt.candidate; - // Edge emits an empty object for RTCIceCandidateComplete‥ - var end = !cand || Object.keys(cand).length === 0; - if (end) { - // polyfill since RTCIceGatherer.state is not implemented in - // Edge 10547 yet. - if (iceGatherer.state === 'new' || iceGatherer.state === 'gathering') { - iceGatherer.state = 'completed'; - } - } else { - if (iceGatherer.state === 'new') { - iceGatherer.state = 'gathering'; - } - // RTCIceCandidate doesn't have a component, needs to be added - cand.component = 1; - event.candidate.candidate = SDPUtils.writeCandidate(cand); - } - - // update local description. - var sections = SDPUtils.splitSections(pc.localDescription.sdp); - if (!end) { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=' + event.candidate.candidate + '\r\n'; - } else { - sections[event.candidate.sdpMLineIndex + 1] += - 'a=end-of-candidates\r\n'; - } - pc.localDescription.sdp = sections.join(''); - var complete = pc.transceivers.every(function(transceiver) { - return transceiver.iceGatherer && - transceiver.iceGatherer.state === 'completed'; - }); - - if (pc.iceGatheringState !== 'gathering') { - pc.iceGatheringState = 'gathering'; - pc._emitGatheringStateChange(); - } - - // Emit candidate. Also emit null candidate when all gatherers are - // complete. - if (!end) { - pc._dispatchEvent('icecandidate', event); - } - if (complete) { - pc._dispatchEvent('icecandidate', new Event('icecandidate')); - pc.iceGatheringState = 'complete'; - pc._emitGatheringStateChange(); - } - }; - - // emit already gathered candidates. - window.setTimeout(function() { - candidates.forEach(function(candidate) { - var e = new Event('RTCIceGatherEvent'); - e.candidate = candidate; - iceGatherer.onlocalcandidate(e); - }); - }, 0); - }; - - // Create ICE transport and DTLS transport. - RTCPeerConnection.prototype._createIceAndDtlsTransports = function() { - var pc = this; - var iceTransport = new window.RTCIceTransport(null); - iceTransport.onicestatechange = function() { - pc._updateConnectionState(); - }; - - var dtlsTransport = new window.RTCDtlsTransport(iceTransport); - dtlsTransport.ondtlsstatechange = function() { - pc._updateConnectionState(); - }; - dtlsTransport.onerror = function() { - // onerror does not set state to failed by itpc. - Object.defineProperty(dtlsTransport, 'state', - {value: 'failed', writable: true}); - pc._updateConnectionState(); - }; - - return { - iceTransport: iceTransport, - dtlsTransport: dtlsTransport - }; - }; - - // Destroy ICE gatherer, ICE transport and DTLS transport. - // Without triggering the callbacks. - RTCPeerConnection.prototype._disposeIceAndDtlsTransports = function( - sdpMLineIndex) { - var iceGatherer = this.transceivers[sdpMLineIndex].iceGatherer; - if (iceGatherer) { - delete iceGatherer.onlocalcandidate; - delete this.transceivers[sdpMLineIndex].iceGatherer; - } - var iceTransport = this.transceivers[sdpMLineIndex].iceTransport; - if (iceTransport) { - delete iceTransport.onicestatechange; - delete this.transceivers[sdpMLineIndex].iceTransport; - } - var dtlsTransport = this.transceivers[sdpMLineIndex].dtlsTransport; - if (dtlsTransport) { - delete dtlsTransport.ondtlsstatechange; - delete dtlsTransport.onerror; - delete this.transceivers[sdpMLineIndex].dtlsTransport; - } - }; - - // Start the RTP Sender and Receiver for a transceiver. - RTCPeerConnection.prototype._transceive = function(transceiver, - send, recv) { - var params = getCommonCapabilities(transceiver.localCapabilities, - transceiver.remoteCapabilities); - if (send && transceiver.rtpSender) { - params.encodings = transceiver.sendEncodingParameters; - params.rtcp = { - cname: SDPUtils.localCName, - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.recvEncodingParameters.length) { - params.rtcp.ssrc = transceiver.recvEncodingParameters[0].ssrc; - } - transceiver.rtpSender.send(params); - } - if (recv && transceiver.rtpReceiver && params.codecs.length > 0) { - // remove RTX field in Edge 14942 - if (transceiver.kind === 'video' - && transceiver.recvEncodingParameters - && edgeVersion < 15019) { - transceiver.recvEncodingParameters.forEach(function(p) { - delete p.rtx; - }); - } - if (transceiver.recvEncodingParameters.length) { - params.encodings = transceiver.recvEncodingParameters; - } - params.rtcp = { - compound: transceiver.rtcpParameters.compound - }; - if (transceiver.rtcpParameters.cname) { - params.rtcp.cname = transceiver.rtcpParameters.cname; - } - if (transceiver.sendEncodingParameters.length) { - params.rtcp.ssrc = transceiver.sendEncodingParameters[0].ssrc; - } - transceiver.rtpReceiver.receive(params); - } - }; - - RTCPeerConnection.prototype.setLocalDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setLocalDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set local ' + description.type + - ' in state ' + pc.signalingState)); - } - - var sections; - var sessionpart; - if (description.type === 'offer') { - // VERY limited support for SDP munging. Limited to: - // * changing the order of codecs - sections = SDPUtils.splitSections(description.sdp); - sessionpart = sections.shift(); - sections.forEach(function(mediaSection, sdpMLineIndex) { - var caps = SDPUtils.parseRtpParameters(mediaSection); - pc.transceivers[sdpMLineIndex].localCapabilities = caps; - }); - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - pc._gather(transceiver.mid, sdpMLineIndex); - }); - } else if (description.type === 'answer') { - sections = SDPUtils.splitSections(pc.remoteDescription.sdp); - sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - sections.forEach(function(mediaSection, sdpMLineIndex) { - var transceiver = pc.transceivers[sdpMLineIndex]; - var iceGatherer = transceiver.iceGatherer; - var iceTransport = transceiver.iceTransport; - var dtlsTransport = transceiver.dtlsTransport; - var localCapabilities = transceiver.localCapabilities; - var remoteCapabilities = transceiver.remoteCapabilities; - - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - - if (!rejected && !transceiver.isDatachannel) { - var remoteIceParameters = SDPUtils.getIceParameters( - mediaSection, sessionpart); - var remoteDtlsParameters = SDPUtils.getDtlsParameters( - mediaSection, sessionpart); - if (isIceLite) { - remoteDtlsParameters.role = 'server'; - } - - if (!pc.usingBundle || sdpMLineIndex === 0) { - pc._gather(transceiver.mid, sdpMLineIndex); - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - isIceLite ? 'controlling' : 'controlled'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - // Calculate intersection of capabilities. - var params = getCommonCapabilities(localCapabilities, - remoteCapabilities); - - // Start the RTCRtpSender. The RTCRtpReceiver for this - // transceiver has already been started in setRemoteDescription. - pc._transceive(transceiver, - params.codecs.length > 0, - false); - } - }); - } - - this.localDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-local-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.setRemoteDescription = function(description) { - var pc = this; - - if (!isActionAllowedInSignalingState('setRemoteDescription', - description.type, this.signalingState) || this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not set remote ' + description.type + - ' in state ' + pc.signalingState)); - } - - var streams = {}; - this.remoteStreams.forEach(function(stream) { - streams[stream.id] = stream; - }); - var receiverList = []; - var sections = SDPUtils.splitSections(description.sdp); - var sessionpart = sections.shift(); - var isIceLite = SDPUtils.matchPrefix(sessionpart, - 'a=ice-lite').length > 0; - var usingBundle = SDPUtils.matchPrefix(sessionpart, - 'a=group:BUNDLE ').length > 0; - this.usingBundle = usingBundle; - var iceOptions = SDPUtils.matchPrefix(sessionpart, - 'a=ice-options:')[0]; - if (iceOptions) { - this.canTrickleIceCandidates = iceOptions.substr(14).split(' ') - .indexOf('trickle') >= 0; - } else { - this.canTrickleIceCandidates = false; - } - - sections.forEach(function(mediaSection, sdpMLineIndex) { - var lines = SDPUtils.splitLines(mediaSection); - var kind = SDPUtils.getKind(mediaSection); - // treat bundle-only as not-rejected. - var rejected = SDPUtils.isRejected(mediaSection) && - SDPUtils.matchPrefix(mediaSection, 'a=bundle-only').length === 0; - var protocol = lines[0].substr(2).split(' ')[2]; - - var direction = SDPUtils.getDirection(mediaSection, sessionpart); - var remoteMsid = SDPUtils.parseMsid(mediaSection); - - var mid = SDPUtils.getMid(mediaSection) || SDPUtils.generateIdentifier(); - - // Reject datachannels which are not implemented yet. - if (kind === 'application' && protocol === 'DTLS/SCTP') { - pc.transceivers[sdpMLineIndex] = { - mid: mid, - isDatachannel: true - }; - return; - } - - var transceiver; - var iceGatherer; - var iceTransport; - var dtlsTransport; - var rtpReceiver; - var sendEncodingParameters; - var recvEncodingParameters; - var localCapabilities; - - var track; - // FIXME: ensure the mediaSection has rtcp-mux set. - var remoteCapabilities = SDPUtils.parseRtpParameters(mediaSection); - var remoteIceParameters; - var remoteDtlsParameters; - if (!rejected) { - remoteIceParameters = SDPUtils.getIceParameters(mediaSection, - sessionpart); - remoteDtlsParameters = SDPUtils.getDtlsParameters(mediaSection, - sessionpart); - remoteDtlsParameters.role = 'client'; - } - recvEncodingParameters = - SDPUtils.parseRtpEncodingParameters(mediaSection); - - var rtcpParameters = SDPUtils.parseRtcpParameters(mediaSection); - - var isComplete = SDPUtils.matchPrefix(mediaSection, - 'a=end-of-candidates', sessionpart).length > 0; - var cands = SDPUtils.matchPrefix(mediaSection, 'a=candidate:') - .map(function(cand) { - return SDPUtils.parseCandidate(cand); - }) - .filter(function(cand) { - return cand.component === 1; - }); - - // Check if we can use BUNDLE and dispose transports. - if ((description.type === 'offer' || description.type === 'answer') && - !rejected && usingBundle && sdpMLineIndex > 0 && - pc.transceivers[sdpMLineIndex]) { - pc._disposeIceAndDtlsTransports(sdpMLineIndex); - pc.transceivers[sdpMLineIndex].iceGatherer = - pc.transceivers[0].iceGatherer; - pc.transceivers[sdpMLineIndex].iceTransport = - pc.transceivers[0].iceTransport; - pc.transceivers[sdpMLineIndex].dtlsTransport = - pc.transceivers[0].dtlsTransport; - if (pc.transceivers[sdpMLineIndex].rtpSender) { - pc.transceivers[sdpMLineIndex].rtpSender.setTransport( - pc.transceivers[0].dtlsTransport); - } - if (pc.transceivers[sdpMLineIndex].rtpReceiver) { - pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport( - pc.transceivers[0].dtlsTransport); - } - } - if (description.type === 'offer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex] || - pc._createTransceiver(kind); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - usingBundle); - } - - if (cands.length && transceiver.iceTransport.state === 'new') { - if (isComplete && (!usingBundle || sdpMLineIndex === 0)) { - transceiver.iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - localCapabilities = window.RTCRtpReceiver.getCapabilities(kind); - - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - - sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 2) * 1001 - }]; - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - var isNewTrack = false; - if (direction === 'sendrecv' || direction === 'sendonly') { - isNewTrack = !transceiver.rtpReceiver; - rtpReceiver = transceiver.rtpReceiver || - new window.RTCRtpReceiver(transceiver.dtlsTransport, kind); - - if (isNewTrack) { - var stream; - track = rtpReceiver.track; - // FIXME: does not work with Plan B. - if (remoteMsid && remoteMsid.stream === '-') { - // no-op. a stream id of '-' means: no associated stream. - } else if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - Object.defineProperty(streams[remoteMsid.stream], 'id', { - get: function() { - return remoteMsid.stream; - } - }); - } - Object.defineProperty(track, 'id', { - get: function() { - return remoteMsid.track; - } - }); - stream = streams[remoteMsid.stream]; - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - stream = streams.default; - } - if (stream) { - addTrackToStreamAndFireEvent(track, stream); - transceiver.associatedRemoteMediaStreams.push(stream); - } - receiverList.push([track, rtpReceiver, stream]); - } - } else if (transceiver.rtpReceiver && transceiver.rtpReceiver.track) { - transceiver.associatedRemoteMediaStreams.forEach(function(s) { - var nativeTrack = s.getTracks().find(function(t) { - return t.id === transceiver.rtpReceiver.track.id; - }); - if (nativeTrack) { - removeTrackFromStreamAndFireEvent(nativeTrack, s); - } - }); - transceiver.associatedRemoteMediaStreams = []; - } - - transceiver.localCapabilities = localCapabilities; - transceiver.remoteCapabilities = remoteCapabilities; - transceiver.rtpReceiver = rtpReceiver; - transceiver.rtcpParameters = rtcpParameters; - transceiver.sendEncodingParameters = sendEncodingParameters; - transceiver.recvEncodingParameters = recvEncodingParameters; - - // Start the RTCRtpReceiver now. The RTPSender is started in - // setLocalDescription. - pc._transceive(pc.transceivers[sdpMLineIndex], - false, - isNewTrack); - } else if (description.type === 'answer' && !rejected) { - transceiver = pc.transceivers[sdpMLineIndex]; - iceGatherer = transceiver.iceGatherer; - iceTransport = transceiver.iceTransport; - dtlsTransport = transceiver.dtlsTransport; - rtpReceiver = transceiver.rtpReceiver; - sendEncodingParameters = transceiver.sendEncodingParameters; - localCapabilities = transceiver.localCapabilities; - - pc.transceivers[sdpMLineIndex].recvEncodingParameters = - recvEncodingParameters; - pc.transceivers[sdpMLineIndex].remoteCapabilities = - remoteCapabilities; - pc.transceivers[sdpMLineIndex].rtcpParameters = rtcpParameters; - - if (cands.length && iceTransport.state === 'new') { - if ((isIceLite || isComplete) && - (!usingBundle || sdpMLineIndex === 0)) { - iceTransport.setRemoteCandidates(cands); - } else { - cands.forEach(function(candidate) { - maybeAddCandidate(transceiver.iceTransport, candidate); - }); - } - } - - if (!usingBundle || sdpMLineIndex === 0) { - if (iceTransport.state === 'new') { - iceTransport.start(iceGatherer, remoteIceParameters, - 'controlling'); - } - if (dtlsTransport.state === 'new') { - dtlsTransport.start(remoteDtlsParameters); - } - } - - pc._transceive(transceiver, - direction === 'sendrecv' || direction === 'recvonly', - direction === 'sendrecv' || direction === 'sendonly'); - - // TODO: rewrite to use http://w3c.github.io/webrtc-pc/#set-associated-remote-streams - if (rtpReceiver && - (direction === 'sendrecv' || direction === 'sendonly')) { - track = rtpReceiver.track; - if (remoteMsid) { - if (!streams[remoteMsid.stream]) { - streams[remoteMsid.stream] = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams[remoteMsid.stream]); - receiverList.push([track, rtpReceiver, streams[remoteMsid.stream]]); - } else { - if (!streams.default) { - streams.default = new window.MediaStream(); - } - addTrackToStreamAndFireEvent(track, streams.default); - receiverList.push([track, rtpReceiver, streams.default]); - } - } else { - // FIXME: actually the receiver should be created later. - delete transceiver.rtpReceiver; - } - } - }); - - if (this._dtlsRole === undefined) { - this._dtlsRole = description.type === 'offer' ? 'active' : 'passive'; - } - - this.remoteDescription = { - type: description.type, - sdp: description.sdp - }; - switch (description.type) { - case 'offer': - this._updateSignalingState('have-remote-offer'); - break; - case 'answer': - this._updateSignalingState('stable'); - break; - default: - throw new TypeError('unsupported type "' + description.type + - '"'); - } - Object.keys(streams).forEach(function(sid) { - var stream = streams[sid]; - if (stream.getTracks().length) { - if (pc.remoteStreams.indexOf(stream) === -1) { - pc.remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - window.setTimeout(function() { - pc._dispatchEvent('addstream', event); - }); - } - - receiverList.forEach(function(item) { - var track = item[0]; - var receiver = item[1]; - if (stream.id !== item[2].id) { - return; - } - fireAddTrack(pc, track, receiver, [stream]); - }); - } - }); - receiverList.forEach(function(item) { - if (item[2]) { - return; - } - fireAddTrack(pc, item[0], item[1], []); - }); - - // check whether addIceCandidate({}) was called within four seconds after - // setRemoteDescription. - window.setTimeout(function() { - if (!(pc && pc.transceivers)) { - return; - } - pc.transceivers.forEach(function(transceiver) { - if (transceiver.iceTransport && - transceiver.iceTransport.state === 'new' && - transceiver.iceTransport.getRemoteCandidates().length > 0) { - console.warn('Timeout for addRemoteCandidate. Consider sending ' + - 'an end-of-candidates notification'); - transceiver.iceTransport.addRemoteCandidate({}); - } - }); - }, 4000); - - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.close = function() { - this.transceivers.forEach(function(transceiver) { - /* not yet - if (transceiver.iceGatherer) { - transceiver.iceGatherer.close(); - } - */ - if (transceiver.iceTransport) { - transceiver.iceTransport.stop(); - } - if (transceiver.dtlsTransport) { - transceiver.dtlsTransport.stop(); - } - if (transceiver.rtpSender) { - transceiver.rtpSender.stop(); - } - if (transceiver.rtpReceiver) { - transceiver.rtpReceiver.stop(); - } - }); - // FIXME: clean up tracks, local streams, remote streams, etc - this._isClosed = true; - this._updateSignalingState('closed'); - }; - - // Update the signaling state. - RTCPeerConnection.prototype._updateSignalingState = function(newState) { - this.signalingState = newState; - var event = new Event('signalingstatechange'); - this._dispatchEvent('signalingstatechange', event); - }; - - // Determine whether to fire the negotiationneeded event. - RTCPeerConnection.prototype._maybeFireNegotiationNeeded = function() { - var pc = this; - if (this.signalingState !== 'stable' || this.needNegotiation === true) { - return; - } - this.needNegotiation = true; - window.setTimeout(function() { - if (pc.needNegotiation === false) { - return; - } - pc.needNegotiation = false; - var event = new Event('negotiationneeded'); - pc._dispatchEvent('negotiationneeded', event); - }, 0); - }; - - // Update the connection state. - RTCPeerConnection.prototype._updateConnectionState = function() { - var newState; - var states = { - 'new': 0, - closed: 0, - connecting: 0, - checking: 0, - connected: 0, - completed: 0, - disconnected: 0, - failed: 0 - }; - this.transceivers.forEach(function(transceiver) { - states[transceiver.iceTransport.state]++; - states[transceiver.dtlsTransport.state]++; - }); - // ICETransport.completed and connected are the same for this purpose. - states.connected += states.completed; - - newState = 'new'; - if (states.failed > 0) { - newState = 'failed'; - } else if (states.connecting > 0 || states.checking > 0) { - newState = 'connecting'; - } else if (states.disconnected > 0) { - newState = 'disconnected'; - } else if (states.new > 0) { - newState = 'new'; - } else if (states.connected > 0 || states.completed > 0) { - newState = 'connected'; - } - - if (newState !== this.iceConnectionState) { - this.iceConnectionState = newState; - var event = new Event('iceconnectionstatechange'); - this._dispatchEvent('iceconnectionstatechange', event); - } - }; - - RTCPeerConnection.prototype.createOffer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createOffer after close')); - } - - var numAudioTracks = this.transceivers.filter(function(t) { - return t.kind === 'audio'; - }).length; - var numVideoTracks = this.transceivers.filter(function(t) { - return t.kind === 'video'; - }).length; - - // Determine number of audio and video tracks we need to send/recv. - var offerOptions = arguments[0]; - if (offerOptions) { - // Reject Chrome legacy constraints. - if (offerOptions.mandatory || offerOptions.optional) { - throw new TypeError( - 'Legacy mandatory/optional constraints not supported.'); - } - if (offerOptions.offerToReceiveAudio !== undefined) { - if (offerOptions.offerToReceiveAudio === true) { - numAudioTracks = 1; - } else if (offerOptions.offerToReceiveAudio === false) { - numAudioTracks = 0; - } else { - numAudioTracks = offerOptions.offerToReceiveAudio; - } - } - if (offerOptions.offerToReceiveVideo !== undefined) { - if (offerOptions.offerToReceiveVideo === true) { - numVideoTracks = 1; - } else if (offerOptions.offerToReceiveVideo === false) { - numVideoTracks = 0; - } else { - numVideoTracks = offerOptions.offerToReceiveVideo; - } - } - } - - this.transceivers.forEach(function(transceiver) { - if (transceiver.kind === 'audio') { - numAudioTracks--; - if (numAudioTracks < 0) { - transceiver.wantReceive = false; - } - } else if (transceiver.kind === 'video') { - numVideoTracks--; - if (numVideoTracks < 0) { - transceiver.wantReceive = false; - } - } - }); - - // Create M-lines for recvonly streams. - while (numAudioTracks > 0 || numVideoTracks > 0) { - if (numAudioTracks > 0) { - this._createTransceiver('audio'); - numAudioTracks--; - } - if (numVideoTracks > 0) { - this._createTransceiver('video'); - numVideoTracks--; - } - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - // For each track, create an ice gatherer, ice transport, - // dtls transport, potentially rtpsender and rtpreceiver. - var track = transceiver.track; - var kind = transceiver.kind; - var mid = SDPUtils.generateIdentifier(); - transceiver.mid = mid; - - if (!transceiver.iceGatherer) { - transceiver.iceGatherer = pc._createIceGatherer(sdpMLineIndex, - pc.usingBundle); - } - - var localCapabilities = window.RTCRtpSender.getCapabilities(kind); - // filter RTX until additional stuff needed for RTX is implemented - // in adapter.js - if (edgeVersion < 15019) { - localCapabilities.codecs = localCapabilities.codecs.filter( - function(codec) { - return codec.name !== 'rtx'; - }); - } - localCapabilities.codecs.forEach(function(codec) { - // work around https://bugs.chromium.org/p/webrtc/issues/detail?id=6552 - // by adding level-asymmetry-allowed=1 - if (codec.name === 'H264' && - codec.parameters['level-asymmetry-allowed'] === undefined) { - codec.parameters['level-asymmetry-allowed'] = '1'; - } - }); - - // generate an ssrc now, to be used later in rtpSender.send - var sendEncodingParameters = transceiver.sendEncodingParameters || [{ - ssrc: (2 * sdpMLineIndex + 1) * 1001 - }]; - if (track) { - // add RTX - if (edgeVersion >= 15019 && kind === 'video' && - !sendEncodingParameters[0].rtx) { - sendEncodingParameters[0].rtx = { - ssrc: sendEncodingParameters[0].ssrc + 1 - }; - } - } - - if (transceiver.wantReceive) { - transceiver.rtpReceiver = new window.RTCRtpReceiver( - transceiver.dtlsTransport, kind); - } - - transceiver.localCapabilities = localCapabilities; - transceiver.sendEncodingParameters = sendEncodingParameters; - }); - - // always offer BUNDLE and dispose on return if not supported. - if (this._config.bundlePolicy !== 'max-compat') { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - sdp += 'a=ice-options:trickle\r\n'; - - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - sdp += writeMediaSection(transceiver, transceiver.localCapabilities, - 'offer', transceiver.stream, pc._dtlsRole); - sdp += 'a=rtcp-rsize\r\n'; - - if (transceiver.iceGatherer && pc.iceGatheringState !== 'new' && - (sdpMLineIndex === 0 || !pc.usingBundle)) { - transceiver.iceGatherer.getLocalCandidates().forEach(function(cand) { - cand.component = 1; - sdp += 'a=' + SDPUtils.writeCandidate(cand) + '\r\n'; - }); - - if (transceiver.iceGatherer.state === 'completed') { - sdp += 'a=end-of-candidates\r\n'; - } - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'offer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.createAnswer = function() { - var pc = this; - - if (this._isClosed) { - return Promise.reject(makeError('InvalidStateError', - 'Can not call createAnswer after close')); - } - - var sdp = SDPUtils.writeSessionBoilerplate(this._sdpSessionId, - this._sdpSessionVersion++); - if (this.usingBundle) { - sdp += 'a=group:BUNDLE ' + this.transceivers.map(function(t) { - return t.mid; - }).join(' ') + '\r\n'; - } - var mediaSectionsInOffer = SDPUtils.splitSections( - this.remoteDescription.sdp).length - 1; - this.transceivers.forEach(function(transceiver, sdpMLineIndex) { - if (sdpMLineIndex + 1 > mediaSectionsInOffer) { - return; - } - if (transceiver.isDatachannel) { - sdp += 'm=application 0 DTLS/SCTP 5000\r\n' + - 'c=IN IP4 0.0.0.0\r\n' + - 'a=mid:' + transceiver.mid + '\r\n'; - return; - } - - // FIXME: look at direction. - if (transceiver.stream) { - var localTrack; - if (transceiver.kind === 'audio') { - localTrack = transceiver.stream.getAudioTracks()[0]; - } else if (transceiver.kind === 'video') { - localTrack = transceiver.stream.getVideoTracks()[0]; - } - if (localTrack) { - // add RTX - if (edgeVersion >= 15019 && transceiver.kind === 'video' && - !transceiver.sendEncodingParameters[0].rtx) { - transceiver.sendEncodingParameters[0].rtx = { - ssrc: transceiver.sendEncodingParameters[0].ssrc + 1 - }; - } - } - } - - // Calculate intersection of capabilities. - var commonCapabilities = getCommonCapabilities( - transceiver.localCapabilities, - transceiver.remoteCapabilities); - - var hasRtx = commonCapabilities.codecs.filter(function(c) { - return c.name.toLowerCase() === 'rtx'; - }).length; - if (!hasRtx && transceiver.sendEncodingParameters[0].rtx) { - delete transceiver.sendEncodingParameters[0].rtx; - } - - sdp += writeMediaSection(transceiver, commonCapabilities, - 'answer', transceiver.stream, pc._dtlsRole); - if (transceiver.rtcpParameters && - transceiver.rtcpParameters.reducedSize) { - sdp += 'a=rtcp-rsize\r\n'; - } - }); - - var desc = new window.RTCSessionDescription({ - type: 'answer', - sdp: sdp - }); - return Promise.resolve(desc); - }; - - RTCPeerConnection.prototype.addIceCandidate = function(candidate) { - var sections; - if (!candidate || candidate.candidate === '') { - for (var j = 0; j < this.transceivers.length; j++) { - if (this.transceivers[j].isDatachannel) { - continue; - } - this.transceivers[j].iceTransport.addRemoteCandidate({}); - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[j + 1] += 'a=end-of-candidates\r\n'; - this.remoteDescription.sdp = sections.join(''); - if (this.usingBundle) { - break; - } - } - } else if (!(candidate.sdpMLineIndex !== undefined || candidate.sdpMid)) { - throw new TypeError('sdpMLineIndex or sdpMid required'); - } else if (!this.remoteDescription) { - return Promise.reject(makeError('InvalidStateError', - 'Can not add ICE candidate without a remote description')); - } else { - var sdpMLineIndex = candidate.sdpMLineIndex; - if (candidate.sdpMid) { - for (var i = 0; i < this.transceivers.length; i++) { - if (this.transceivers[i].mid === candidate.sdpMid) { - sdpMLineIndex = i; - break; - } - } - } - var transceiver = this.transceivers[sdpMLineIndex]; - if (transceiver) { - if (transceiver.isDatachannel) { - return Promise.resolve(); - } - var cand = Object.keys(candidate.candidate).length > 0 ? - SDPUtils.parseCandidate(candidate.candidate) : {}; - // Ignore Chrome's invalid candidates since Edge does not like them. - if (cand.protocol === 'tcp' && (cand.port === 0 || cand.port === 9)) { - return Promise.resolve(); - } - // Ignore RTCP candidates, we assume RTCP-MUX. - if (cand.component && cand.component !== 1) { - return Promise.resolve(); - } - // when using bundle, avoid adding candidates to the wrong - // ice transport. And avoid adding candidates added in the SDP. - if (sdpMLineIndex === 0 || (sdpMLineIndex > 0 && - transceiver.iceTransport !== this.transceivers[0].iceTransport)) { - if (!maybeAddCandidate(transceiver.iceTransport, cand)) { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - - // update the remoteDescription. - var candidateString = candidate.candidate.trim(); - if (candidateString.indexOf('a=') === 0) { - candidateString = candidateString.substr(2); - } - sections = SDPUtils.splitSections(this.remoteDescription.sdp); - sections[sdpMLineIndex + 1] += 'a=' + - (cand.type ? candidateString : 'end-of-candidates') - + '\r\n'; - this.remoteDescription.sdp = sections.join(''); - } else { - return Promise.reject(makeError('OperationError', - 'Can not add ICE candidate')); - } - } - return Promise.resolve(); - }; - - RTCPeerConnection.prototype.getStats = function() { - var promises = []; - this.transceivers.forEach(function(transceiver) { - ['rtpSender', 'rtpReceiver', 'iceGatherer', 'iceTransport', - 'dtlsTransport'].forEach(function(method) { - if (transceiver[method]) { - promises.push(transceiver[method].getStats()); - } - }); - }); - var fixStatsType = function(stat) { - return { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[stat.type] || stat.type; - }; - return new Promise(function(resolve) { - // shim getStats with maplike support - var results = new Map(); - Promise.all(promises).then(function(res) { - res.forEach(function(result) { - Object.keys(result).forEach(function(id) { - result[id].type = fixStatsType(result[id]); - results.set(id, result[id]); - }); - }); - resolve(results); - }); - }); - }; - - // legacy callback shims. Should be moved to adapter.js some days. - var methods = ['createOffer', 'createAnswer']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[0] === 'function' || - typeof args[1] === 'function') { // legacy - return nativeMethod.apply(this, [arguments[2]]) - .then(function(description) { - if (typeof args[0] === 'function') { - args[0].apply(null, [description]); - } - }, function(error) { - if (typeof args[1] === 'function') { - args[1].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - methods = ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate']; - methods.forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function' || - typeof args[2] === 'function') { // legacy - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }, function(error) { - if (typeof args[2] === 'function') { - args[2].apply(null, [error]); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - // getStats is special. It doesn't have a spec legacy method yet we support - // getStats(something, cb) without error callbacks. - ['getStats'].forEach(function(method) { - var nativeMethod = RTCPeerConnection.prototype[method]; - RTCPeerConnection.prototype[method] = function() { - var args = arguments; - if (typeof args[1] === 'function') { - return nativeMethod.apply(this, arguments) - .then(function() { - if (typeof args[1] === 'function') { - args[1].apply(null); - } - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - - return RTCPeerConnection; -}; - -},{"sdp":2}],2:[function(require,module,exports){ - /* eslint-env node */ -'use strict'; - -// SDP helpers. -var SDPUtils = {}; - -// Generate an alphanumeric identifier for cname or mids. -// TODO: use UUIDs instead? https://gist.github.com/jed/982883 -SDPUtils.generateIdentifier = function() { - return Math.random().toString(36).substr(2, 10); -}; - -// The RTCP CNAME used by all peerconnections from the same JS. -SDPUtils.localCName = SDPUtils.generateIdentifier(); - -// Splits SDP into lines, dealing with both CRLF and LF. -SDPUtils.splitLines = function(blob) { - return blob.trim().split('\n').map(function(line) { - return line.trim(); - }); -}; -// Splits SDP into sessionpart and mediasections. Ensures CRLF. -SDPUtils.splitSections = function(blob) { - var parts = blob.split('\nm='); - return parts.map(function(part, index) { - return (index > 0 ? 'm=' + part : part).trim() + '\r\n'; - }); -}; - -// Returns lines that start with a certain prefix. -SDPUtils.matchPrefix = function(blob, prefix) { - return SDPUtils.splitLines(blob).filter(function(line) { - return line.indexOf(prefix) === 0; - }); -}; - -// Parses an ICE candidate line. Sample input: -// candidate:702786350 2 udp 41819902 8.8.8.8 60769 typ relay raddr 8.8.8.8 -// rport 55996" -SDPUtils.parseCandidate = function(line) { - var parts; - // Parse both variants. - if (line.indexOf('a=candidate:') === 0) { - parts = line.substring(12).split(' '); - } else { - parts = line.substring(10).split(' '); - } - - var candidate = { - foundation: parts[0], - component: parseInt(parts[1], 10), - protocol: parts[2].toLowerCase(), - priority: parseInt(parts[3], 10), - ip: parts[4], - port: parseInt(parts[5], 10), - // skip parts[6] == 'typ' - type: parts[7] - }; - - for (var i = 8; i < parts.length; i += 2) { - switch (parts[i]) { - case 'raddr': - candidate.relatedAddress = parts[i + 1]; - break; - case 'rport': - candidate.relatedPort = parseInt(parts[i + 1], 10); - break; - case 'tcptype': - candidate.tcpType = parts[i + 1]; - break; - case 'ufrag': - candidate.ufrag = parts[i + 1]; // for backward compability. - candidate.usernameFragment = parts[i + 1]; - break; - default: // extension handling, in particular ufrag - candidate[parts[i]] = parts[i + 1]; - break; - } - } - return candidate; -}; - -// Translates a candidate object into SDP candidate attribute. -SDPUtils.writeCandidate = function(candidate) { - var sdp = []; - sdp.push(candidate.foundation); - sdp.push(candidate.component); - sdp.push(candidate.protocol.toUpperCase()); - sdp.push(candidate.priority); - sdp.push(candidate.ip); - sdp.push(candidate.port); - - var type = candidate.type; - sdp.push('typ'); - sdp.push(type); - if (type !== 'host' && candidate.relatedAddress && - candidate.relatedPort) { - sdp.push('raddr'); - sdp.push(candidate.relatedAddress); // was: relAddr - sdp.push('rport'); - sdp.push(candidate.relatedPort); // was: relPort - } - if (candidate.tcpType && candidate.protocol.toLowerCase() === 'tcp') { - sdp.push('tcptype'); - sdp.push(candidate.tcpType); - } - if (candidate.ufrag) { - sdp.push('ufrag'); - sdp.push(candidate.ufrag); - } - return 'candidate:' + sdp.join(' '); -}; - -// Parses an ice-options line, returns an array of option tags. -// a=ice-options:foo bar -SDPUtils.parseIceOptions = function(line) { - return line.substr(14).split(' '); -} - -// Parses an rtpmap line, returns RTCRtpCoddecParameters. Sample input: -// a=rtpmap:111 opus/48000/2 -SDPUtils.parseRtpMap = function(line) { - var parts = line.substr(9).split(' '); - var parsed = { - payloadType: parseInt(parts.shift(), 10) // was: id - }; - - parts = parts[0].split('/'); - - parsed.name = parts[0]; - parsed.clockRate = parseInt(parts[1], 10); // was: clockrate - // was: channels - parsed.numChannels = parts.length === 3 ? parseInt(parts[2], 10) : 1; - return parsed; -}; - -// Generate an a=rtpmap line from RTCRtpCodecCapability or -// RTCRtpCodecParameters. -SDPUtils.writeRtpMap = function(codec) { - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - return 'a=rtpmap:' + pt + ' ' + codec.name + '/' + codec.clockRate + - (codec.numChannels !== 1 ? '/' + codec.numChannels : '') + '\r\n'; -}; - -// Parses an a=extmap line (headerextension from RFC 5285). Sample input: -// a=extmap:2 urn:ietf:params:rtp-hdrext:toffset -// a=extmap:2/sendonly urn:ietf:params:rtp-hdrext:toffset -SDPUtils.parseExtmap = function(line) { - var parts = line.substr(9).split(' '); - return { - id: parseInt(parts[0], 10), - direction: parts[0].indexOf('/') > 0 ? parts[0].split('/')[1] : 'sendrecv', - uri: parts[1] - }; -}; - -// Generates a=extmap line from RTCRtpHeaderExtensionParameters or -// RTCRtpHeaderExtension. -SDPUtils.writeExtmap = function(headerExtension) { - return 'a=extmap:' + (headerExtension.id || headerExtension.preferredId) + - (headerExtension.direction && headerExtension.direction !== 'sendrecv' - ? '/' + headerExtension.direction - : '') + - ' ' + headerExtension.uri + '\r\n'; -}; - -// Parses an ftmp line, returns dictionary. Sample input: -// a=fmtp:96 vbr=on;cng=on -// Also deals with vbr=on; cng=on -SDPUtils.parseFmtp = function(line) { - var parsed = {}; - var kv; - var parts = line.substr(line.indexOf(' ') + 1).split(';'); - for (var j = 0; j < parts.length; j++) { - kv = parts[j].trim().split('='); - parsed[kv[0].trim()] = kv[1]; - } - return parsed; -}; - -// Generates an a=ftmp line from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeFmtp = function(codec) { - var line = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.parameters && Object.keys(codec.parameters).length) { - var params = []; - Object.keys(codec.parameters).forEach(function(param) { - params.push(param + '=' + codec.parameters[param]); - }); - line += 'a=fmtp:' + pt + ' ' + params.join(';') + '\r\n'; - } - return line; -}; - -// Parses an rtcp-fb line, returns RTCPRtcpFeedback object. Sample input: -// a=rtcp-fb:98 nack rpsi -SDPUtils.parseRtcpFb = function(line) { - var parts = line.substr(line.indexOf(' ') + 1).split(' '); - return { - type: parts.shift(), - parameter: parts.join(' ') - }; -}; -// Generate a=rtcp-fb lines from RTCRtpCodecCapability or RTCRtpCodecParameters. -SDPUtils.writeRtcpFb = function(codec) { - var lines = ''; - var pt = codec.payloadType; - if (codec.preferredPayloadType !== undefined) { - pt = codec.preferredPayloadType; - } - if (codec.rtcpFeedback && codec.rtcpFeedback.length) { - // FIXME: special handling for trr-int? - codec.rtcpFeedback.forEach(function(fb) { - lines += 'a=rtcp-fb:' + pt + ' ' + fb.type + - (fb.parameter && fb.parameter.length ? ' ' + fb.parameter : '') + - '\r\n'; - }); - } - return lines; -}; - -// Parses an RFC 5576 ssrc media attribute. Sample input: -// a=ssrc:3735928559 cname:something -SDPUtils.parseSsrcMedia = function(line) { - var sp = line.indexOf(' '); - var parts = { - ssrc: parseInt(line.substr(7, sp - 7), 10) - }; - var colon = line.indexOf(':', sp); - if (colon > -1) { - parts.attribute = line.substr(sp + 1, colon - sp - 1); - parts.value = line.substr(colon + 1); - } else { - parts.attribute = line.substr(sp + 1); - } - return parts; -}; - -// Extracts the MID (RFC 5888) from a media section. -// returns the MID or undefined if no mid line was found. -SDPUtils.getMid = function(mediaSection) { - var mid = SDPUtils.matchPrefix(mediaSection, 'a=mid:')[0]; - if (mid) { - return mid.substr(6); - } -} - -SDPUtils.parseFingerprint = function(line) { - var parts = line.substr(14).split(' '); - return { - algorithm: parts[0].toLowerCase(), // algorithm is case-sensitive in Edge. - value: parts[1] - }; -}; - -// Extracts DTLS parameters from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the fingerprint line as input. See also getIceParameters. -SDPUtils.getDtlsParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.matchPrefix(mediaSection + sessionpart, - 'a=fingerprint:'); - // Note: a=setup line is ignored since we use the 'auto' role. - // Note2: 'algorithm' is not case sensitive except in Edge. - return { - role: 'auto', - fingerprints: lines.map(SDPUtils.parseFingerprint) - }; -}; - -// Serializes DTLS parameters to SDP. -SDPUtils.writeDtlsParameters = function(params, setupType) { - var sdp = 'a=setup:' + setupType + '\r\n'; - params.fingerprints.forEach(function(fp) { - sdp += 'a=fingerprint:' + fp.algorithm + ' ' + fp.value + '\r\n'; - }); - return sdp; -}; -// Parses ICE information from SDP media section or sessionpart. -// FIXME: for consistency with other functions this should only -// get the ice-ufrag and ice-pwd lines as input. -SDPUtils.getIceParameters = function(mediaSection, sessionpart) { - var lines = SDPUtils.splitLines(mediaSection); - // Search in session part, too. - lines = lines.concat(SDPUtils.splitLines(sessionpart)); - var iceParameters = { - usernameFragment: lines.filter(function(line) { - return line.indexOf('a=ice-ufrag:') === 0; - })[0].substr(12), - password: lines.filter(function(line) { - return line.indexOf('a=ice-pwd:') === 0; - })[0].substr(10) - }; - return iceParameters; -}; - -// Serializes ICE parameters to SDP. -SDPUtils.writeIceParameters = function(params) { - return 'a=ice-ufrag:' + params.usernameFragment + '\r\n' + - 'a=ice-pwd:' + params.password + '\r\n'; -}; - -// Parses the SDP media section and returns RTCRtpParameters. -SDPUtils.parseRtpParameters = function(mediaSection) { - var description = { - codecs: [], - headerExtensions: [], - fecMechanisms: [], - rtcp: [] - }; - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - for (var i = 3; i < mline.length; i++) { // find all codecs from mline[3..] - var pt = mline[i]; - var rtpmapline = SDPUtils.matchPrefix( - mediaSection, 'a=rtpmap:' + pt + ' ')[0]; - if (rtpmapline) { - var codec = SDPUtils.parseRtpMap(rtpmapline); - var fmtps = SDPUtils.matchPrefix( - mediaSection, 'a=fmtp:' + pt + ' '); - // Only the first a=fmtp: is considered. - codec.parameters = fmtps.length ? SDPUtils.parseFmtp(fmtps[0]) : {}; - codec.rtcpFeedback = SDPUtils.matchPrefix( - mediaSection, 'a=rtcp-fb:' + pt + ' ') - .map(SDPUtils.parseRtcpFb); - description.codecs.push(codec); - // parse FEC mechanisms from rtpmap lines. - switch (codec.name.toUpperCase()) { - case 'RED': - case 'ULPFEC': - description.fecMechanisms.push(codec.name.toUpperCase()); - break; - default: // only RED and ULPFEC are recognized as FEC mechanisms. - break; - } - } - } - SDPUtils.matchPrefix(mediaSection, 'a=extmap:').forEach(function(line) { - description.headerExtensions.push(SDPUtils.parseExtmap(line)); - }); - // FIXME: parse rtcp. - return description; -}; - -// Generates parts of the SDP media section describing the capabilities / -// parameters. -SDPUtils.writeRtpDescription = function(kind, caps) { - var sdp = ''; - - // Build the mline. - sdp += 'm=' + kind + ' '; - sdp += caps.codecs.length > 0 ? '9' : '0'; // reject if no codecs. - sdp += ' UDP/TLS/RTP/SAVPF '; - sdp += caps.codecs.map(function(codec) { - if (codec.preferredPayloadType !== undefined) { - return codec.preferredPayloadType; - } - return codec.payloadType; - }).join(' ') + '\r\n'; - - sdp += 'c=IN IP4 0.0.0.0\r\n'; - sdp += 'a=rtcp:9 IN IP4 0.0.0.0\r\n'; - - // Add a=rtpmap lines for each codec. Also fmtp and rtcp-fb. - caps.codecs.forEach(function(codec) { - sdp += SDPUtils.writeRtpMap(codec); - sdp += SDPUtils.writeFmtp(codec); - sdp += SDPUtils.writeRtcpFb(codec); - }); - var maxptime = 0; - caps.codecs.forEach(function(codec) { - if (codec.maxptime > maxptime) { - maxptime = codec.maxptime; - } - }); - if (maxptime > 0) { - sdp += 'a=maxptime:' + maxptime + '\r\n'; - } - sdp += 'a=rtcp-mux\r\n'; - - caps.headerExtensions.forEach(function(extension) { - sdp += SDPUtils.writeExtmap(extension); - }); - // FIXME: write fecMechanisms. - return sdp; -}; - -// Parses the SDP media section and returns an array of -// RTCRtpEncodingParameters. -SDPUtils.parseRtpEncodingParameters = function(mediaSection) { - var encodingParameters = []; - var description = SDPUtils.parseRtpParameters(mediaSection); - var hasRed = description.fecMechanisms.indexOf('RED') !== -1; - var hasUlpfec = description.fecMechanisms.indexOf('ULPFEC') !== -1; - - // filter a=ssrc:... cname:, ignore PlanB-msid - var ssrcs = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'cname'; - }); - var primarySsrc = ssrcs.length > 0 && ssrcs[0].ssrc; - var secondarySsrc; - - var flows = SDPUtils.matchPrefix(mediaSection, 'a=ssrc-group:FID') - .map(function(line) { - var parts = line.split(' '); - parts.shift(); - return parts.map(function(part) { - return parseInt(part, 10); - }); - }); - if (flows.length > 0 && flows[0].length > 1 && flows[0][0] === primarySsrc) { - secondarySsrc = flows[0][1]; - } - - description.codecs.forEach(function(codec) { - if (codec.name.toUpperCase() === 'RTX' && codec.parameters.apt) { - var encParam = { - ssrc: primarySsrc, - codecPayloadType: parseInt(codec.parameters.apt, 10), - rtx: { - ssrc: secondarySsrc - } - }; - encodingParameters.push(encParam); - if (hasRed) { - encParam = JSON.parse(JSON.stringify(encParam)); - encParam.fec = { - ssrc: secondarySsrc, - mechanism: hasUlpfec ? 'red+ulpfec' : 'red' - }; - encodingParameters.push(encParam); - } - } - }); - if (encodingParameters.length === 0 && primarySsrc) { - encodingParameters.push({ - ssrc: primarySsrc - }); - } - - // we support both b=AS and b=TIAS but interpret AS as TIAS. - var bandwidth = SDPUtils.matchPrefix(mediaSection, 'b='); - if (bandwidth.length) { - if (bandwidth[0].indexOf('b=TIAS:') === 0) { - bandwidth = parseInt(bandwidth[0].substr(7), 10); - } else if (bandwidth[0].indexOf('b=AS:') === 0) { - // use formula from JSEP to convert b=AS to TIAS value. - bandwidth = parseInt(bandwidth[0].substr(5), 10) * 1000 * 0.95 - - (50 * 40 * 8); - } else { - bandwidth = undefined; - } - encodingParameters.forEach(function(params) { - params.maxBitrate = bandwidth; - }); - } - return encodingParameters; -}; - -// parses http://draft.ortc.org/#rtcrtcpparameters* -SDPUtils.parseRtcpParameters = function(mediaSection) { - var rtcpParameters = {}; - - var cname; - // Gets the first SSRC. Note that with RTX there might be multiple - // SSRCs. - var remoteSsrc = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(obj) { - return obj.attribute === 'cname'; - })[0]; - if (remoteSsrc) { - rtcpParameters.cname = remoteSsrc.value; - rtcpParameters.ssrc = remoteSsrc.ssrc; - } - - // Edge uses the compound attribute instead of reducedSize - // compound is !reducedSize - var rsize = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-rsize'); - rtcpParameters.reducedSize = rsize.length > 0; - rtcpParameters.compound = rsize.length === 0; - - // parses the rtcp-mux attrіbute. - // Note that Edge does not support unmuxed RTCP. - var mux = SDPUtils.matchPrefix(mediaSection, 'a=rtcp-mux'); - rtcpParameters.mux = mux.length > 0; - - return rtcpParameters; -}; - -// parses either a=msid: or a=ssrc:... msid lines and returns -// the id of the MediaStream and MediaStreamTrack. -SDPUtils.parseMsid = function(mediaSection) { - var parts; - var spec = SDPUtils.matchPrefix(mediaSection, 'a=msid:'); - if (spec.length === 1) { - parts = spec[0].substr(7).split(' '); - return {stream: parts[0], track: parts[1]}; - } - var planB = SDPUtils.matchPrefix(mediaSection, 'a=ssrc:') - .map(function(line) { - return SDPUtils.parseSsrcMedia(line); - }) - .filter(function(parts) { - return parts.attribute === 'msid'; - }); - if (planB.length > 0) { - parts = planB[0].value.split(' '); - return {stream: parts[0], track: parts[1]}; - } -}; - -// Generate a session ID for SDP. -// https://tools.ietf.org/html/draft-ietf-rtcweb-jsep-20#section-5.2.1 -// recommends using a cryptographically random +ve 64-bit value -// but right now this should be acceptable and within the right range -SDPUtils.generateSessionId = function() { - return Math.random().toString().substr(2, 21); -}; - -// Write boilder plate for start of SDP -// sessId argument is optional - if not supplied it will -// be generated randomly -// sessVersion is optional and defaults to 2 -SDPUtils.writeSessionBoilerplate = function(sessId, sessVer) { - var sessionId; - var version = sessVer !== undefined ? sessVer : 2; - if (sessId) { - sessionId = sessId; - } else { - sessionId = SDPUtils.generateSessionId(); - } - // FIXME: sess-id should be an NTP timestamp. - return 'v=0\r\n' + - 'o=thisisadapterortc ' + sessionId + ' ' + version + ' IN IP4 127.0.0.1\r\n' + - 's=-\r\n' + - 't=0 0\r\n'; -}; - -SDPUtils.writeMediaSection = function(transceiver, caps, type, stream) { - var sdp = SDPUtils.writeRtpDescription(transceiver.kind, caps); - - // Map ICE parameters (ufrag, pwd) to SDP. - sdp += SDPUtils.writeIceParameters( - transceiver.iceGatherer.getLocalParameters()); - - // Map DTLS parameters to SDP. - sdp += SDPUtils.writeDtlsParameters( - transceiver.dtlsTransport.getLocalParameters(), - type === 'offer' ? 'actpass' : 'active'); - - sdp += 'a=mid:' + transceiver.mid + '\r\n'; - - if (transceiver.direction) { - sdp += 'a=' + transceiver.direction + '\r\n'; - } else if (transceiver.rtpSender && transceiver.rtpReceiver) { - sdp += 'a=sendrecv\r\n'; - } else if (transceiver.rtpSender) { - sdp += 'a=sendonly\r\n'; - } else if (transceiver.rtpReceiver) { - sdp += 'a=recvonly\r\n'; - } else { - sdp += 'a=inactive\r\n'; - } - - if (transceiver.rtpSender) { - // spec. - var msid = 'msid:' + stream.id + ' ' + - transceiver.rtpSender.track.id + '\r\n'; - sdp += 'a=' + msid; - - // for Chrome. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' ' + msid; - if (transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' ' + msid; - sdp += 'a=ssrc-group:FID ' + - transceiver.sendEncodingParameters[0].ssrc + ' ' + - transceiver.sendEncodingParameters[0].rtx.ssrc + - '\r\n'; - } - } - // FIXME: this should be written by writeRtpDescription. - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - if (transceiver.rtpSender && transceiver.sendEncodingParameters[0].rtx) { - sdp += 'a=ssrc:' + transceiver.sendEncodingParameters[0].rtx.ssrc + - ' cname:' + SDPUtils.localCName + '\r\n'; - } - return sdp; -}; - -// Gets the direction from the mediaSection or the sessionpart. -SDPUtils.getDirection = function(mediaSection, sessionpart) { - // Look for sendrecv, sendonly, recvonly, inactive, default to sendrecv. - var lines = SDPUtils.splitLines(mediaSection); - for (var i = 0; i < lines.length; i++) { - switch (lines[i]) { - case 'a=sendrecv': - case 'a=sendonly': - case 'a=recvonly': - case 'a=inactive': - return lines[i].substr(2); - default: - // FIXME: What should happen here? - } - } - if (sessionpart) { - return SDPUtils.getDirection(sessionpart); - } - return 'sendrecv'; -}; - -SDPUtils.getKind = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return mline[0].substr(2); -}; - -SDPUtils.isRejected = function(mediaSection) { - return mediaSection.split(' ', 2)[1] === '0'; -}; - -SDPUtils.parseMLine = function(mediaSection) { - var lines = SDPUtils.splitLines(mediaSection); - var mline = lines[0].split(' '); - return { - kind: mline[0].substr(2), - port: parseInt(mline[1], 10), - protocol: mline[2], - fmt: mline.slice(3).join(' ') - }; -}; - -// Expose public methods. -if (typeof module === 'object') { - module.exports = SDPUtils; -} - -},{}],3:[function(require,module,exports){ -(function (global){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var adapterFactory = require('./adapter_factory.js'); -module.exports = adapterFactory({window: global.window}); - -}).call(this,typeof global !== "undefined" ? global : typeof self !== "undefined" ? self : typeof window !== "undefined" ? window : {}) -},{"./adapter_factory.js":4}],4:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ - -'use strict'; - -var utils = require('./utils'); -// Shimming starts here. -module.exports = function(dependencies, opts) { - var window = dependencies && dependencies.window; - - var options = { - shimChrome: true, - shimFirefox: true, - shimEdge: true, - shimSafari: true, - }; - - for (var key in opts) { - if (hasOwnProperty.call(opts, key)) { - options[key] = opts[key]; - } - } - - // Utils. - var logging = utils.log; - var browserDetails = utils.detectBrowser(window); - - // Uncomment the line below if you want logging to occur, including logging - // for the switch statement below. Can also be turned on in the browser via - // adapter.disableLog(false), but then logging from the switch statement below - // will not appear. - // require('./utils').disableLog(false); - - // Browser shims. - var chromeShim = require('./chrome/chrome_shim') || null; - var edgeShim = require('./edge/edge_shim') || null; - var firefoxShim = require('./firefox/firefox_shim') || null; - var safariShim = require('./safari/safari_shim') || null; - var commonShim = require('./common_shim') || null; - - // Export to the adapter global object visible in the browser. - var adapter = { - browserDetails: browserDetails, - commonShim: commonShim, - extractVersion: utils.extractVersion, - disableLog: utils.disableLog, - disableWarnings: utils.disableWarnings - }; - - // Shim browser if found. - switch (browserDetails.browser) { - case 'chrome': - if (!chromeShim || !chromeShim.shimPeerConnection || - !options.shimChrome) { - logging('Chrome shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming chrome.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = chromeShim; - commonShim.shimCreateObjectURL(window); - - chromeShim.shimGetUserMedia(window); - chromeShim.shimMediaStream(window); - chromeShim.shimSourceObject(window); - chromeShim.shimPeerConnection(window); - chromeShim.shimOnTrack(window); - chromeShim.shimAddTrackRemoveTrack(window); - chromeShim.shimGetSendersWithDtmf(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'firefox': - if (!firefoxShim || !firefoxShim.shimPeerConnection || - !options.shimFirefox) { - logging('Firefox shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming firefox.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = firefoxShim; - commonShim.shimCreateObjectURL(window); - - firefoxShim.shimGetUserMedia(window); - firefoxShim.shimSourceObject(window); - firefoxShim.shimPeerConnection(window); - firefoxShim.shimOnTrack(window); - firefoxShim.shimRemoveStream(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'edge': - if (!edgeShim || !edgeShim.shimPeerConnection || !options.shimEdge) { - logging('MS edge shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming edge.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = edgeShim; - commonShim.shimCreateObjectURL(window); - - edgeShim.shimGetUserMedia(window); - edgeShim.shimPeerConnection(window); - edgeShim.shimReplaceTrack(window); - - // the edge shim implements the full RTCIceCandidate object. - - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - case 'safari': - if (!safariShim || !options.shimSafari) { - logging('Safari shim is not included in this adapter release.'); - return adapter; - } - logging('adapter.js shimming safari.'); - // Export to the adapter global object visible in the browser. - adapter.browserShim = safariShim; - commonShim.shimCreateObjectURL(window); - - safariShim.shimRTCIceServerUrls(window); - safariShim.shimCallbacksAPI(window); - safariShim.shimLocalStreamsAPI(window); - safariShim.shimRemoteStreamsAPI(window); - safariShim.shimTrackEventTransceiver(window); - safariShim.shimGetUserMedia(window); - safariShim.shimCreateOfferLegacy(window); - - commonShim.shimRTCIceCandidate(window); - commonShim.shimMaxMessageSize(window); - commonShim.shimSendThrowTypeError(window); - break; - default: - logging('Unsupported browser!'); - break; - } - - return adapter; -}; - -},{"./chrome/chrome_shim":5,"./common_shim":7,"./edge/edge_shim":8,"./firefox/firefox_shim":10,"./safari/safari_shim":12,"./utils":13}],5:[function(require,module,exports){ - -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimMediaStream: function(window) { - window.MediaStream = window.MediaStream || window.webkitMediaStream; - }, - - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - } - this.addEventListener('track', this._ontrack = f); - } - }); - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - if (!pc._ontrackpoly) { - pc._ontrackpoly = function(e) { - // onaddstream does not fire when a track is added to an existing - // stream. But stream.onaddtrack is implemented so we use that. - e.stream.addEventListener('addtrack', function(te) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === te.track.id; - }); - } else { - receiver = {track: te.track}; - } - - var event = new Event('track'); - event.track = te.track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - e.stream.getTracks().forEach(function(track) { - var receiver; - if (window.RTCPeerConnection.prototype.getReceivers) { - receiver = pc.getReceivers().find(function(r) { - return r.track && r.track.id === track.id; - }); - } else { - receiver = {track: track}; - } - var event = new Event('track'); - event.track = track; - event.receiver = receiver; - event.transceiver = {receiver: receiver}; - event.streams = [e.stream]; - pc.dispatchEvent(event); - }); - }; - pc.addEventListener('addstream', pc._ontrackpoly); - } - return origSetRemoteDescription.apply(pc, arguments); - }; - } else if (!('RTCRtpTransceiver' in window)) { - utils.wrapPeerConnectionEvent(window, 'track', function(e) { - if (!e.transceiver) { - e.transceiver = {receiver: e.receiver}; - } - return e; - }); - } - }, - - shimGetSendersWithDtmf: function(window) { - // Overrides addTrack/removeTrack, depends on shimAddTrackRemoveTrack. - if (typeof window === 'object' && window.RTCPeerConnection && - !('getSenders' in window.RTCPeerConnection.prototype) && - 'createDTMFSender' in window.RTCPeerConnection.prototype) { - var shimSenderWithDtmf = function(pc, track) { - return { - track: track, - get dtmf() { - if (this._dtmf === undefined) { - if (track.kind === 'audio') { - this._dtmf = pc.createDTMFSender(track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - }, - _pc: pc - }; - }; - - // augment addTrack when getSenders is not available. - if (!window.RTCPeerConnection.prototype.getSenders) { - window.RTCPeerConnection.prototype.getSenders = function() { - this._senders = this._senders || []; - return this._senders.slice(); // return a copy of the internal state. - }; - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - var sender = origAddTrack.apply(pc, arguments); - if (!sender) { - sender = shimSenderWithDtmf(pc, track); - pc._senders.push(sender); - } - return sender; - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - origRemoveTrack.apply(pc, arguments); - var idx = pc._senders.indexOf(sender); - if (idx !== -1) { - pc._senders.splice(idx, 1); - } - }; - } - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origAddStream.apply(pc, [stream]); - stream.getTracks().forEach(function(track) { - pc._senders.push(shimSenderWithDtmf(pc, track)); - }); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._senders = pc._senders || []; - origRemoveStream.apply(pc, [stream]); - - stream.getTracks().forEach(function(track) { - var sender = pc._senders.find(function(s) { - return s.track === track; - }); - if (sender) { - pc._senders.splice(pc._senders.indexOf(sender), 1); // remove sender - } - }); - }; - } else if (typeof window === 'object' && window.RTCPeerConnection && - 'getSenders' in window.RTCPeerConnection.prototype && - 'createDTMFSender' in window.RTCPeerConnection.prototype && - window.RTCRtpSender && - !('dtmf' in window.RTCRtpSender.prototype)) { - var origGetSenders = window.RTCPeerConnection.prototype.getSenders; - window.RTCPeerConnection.prototype.getSenders = function() { - var pc = this; - var senders = origGetSenders.apply(pc, []); - senders.forEach(function(sender) { - sender._pc = pc; - }); - return senders; - }; - - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = this._pc.createDTMFSender(this.track); - } else { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - }, - - shimSourceObject: function(window) { - var URL = window && window.URL; - - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this._srcObject; - }, - set: function(stream) { - var self = this; - // Use _srcObject as a private property for this shim - this._srcObject = stream; - if (this.src) { - URL.revokeObjectURL(this.src); - } - - if (!stream) { - this.src = ''; - return undefined; - } - this.src = URL.createObjectURL(stream); - // We need to recreate the blob url when a track is added or - // removed. Doing it manually since we want to avoid a recursion. - stream.addEventListener('addtrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - stream.addEventListener('removetrack', function() { - if (self.src) { - URL.revokeObjectURL(self.src); - } - self.src = URL.createObjectURL(stream); - }); - } - }); - } - } - }, - - shimAddTrackRemoveTrackWithNative: function(window) { - // shim addTrack/removeTrack with native variants in order to make - // the interactions with legacy getLocalStreams behave as in other browsers. - // Keeps a mapping stream.id => [stream, rtpsenders...] - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - return Object.keys(this._shimmedLocalStreams).map(function(streamId) { - return pc._shimmedLocalStreams[streamId][0]; - }); - }; - - var origAddTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (!stream) { - return origAddTrack.apply(this, arguments); - } - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - var sender = origAddTrack.apply(this, arguments); - if (!this._shimmedLocalStreams[stream.id]) { - this._shimmedLocalStreams[stream.id] = [stream, sender]; - } else if (this._shimmedLocalStreams[stream.id].indexOf(sender) === -1) { - this._shimmedLocalStreams[stream.id].push(sender); - } - return sender; - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - var existingSenders = pc.getSenders(); - origAddStream.apply(this, arguments); - var newSenders = pc.getSenders().filter(function(newSender) { - return existingSenders.indexOf(newSender) === -1; - }); - this._shimmedLocalStreams[stream.id] = [stream].concat(newSenders); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - delete this._shimmedLocalStreams[stream.id]; - return origRemoveStream.apply(this, arguments); - }; - - var origRemoveTrack = window.RTCPeerConnection.prototype.removeTrack; - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - this._shimmedLocalStreams = this._shimmedLocalStreams || {}; - if (sender) { - Object.keys(this._shimmedLocalStreams).forEach(function(streamId) { - var idx = pc._shimmedLocalStreams[streamId].indexOf(sender); - if (idx !== -1) { - pc._shimmedLocalStreams[streamId].splice(idx, 1); - } - if (pc._shimmedLocalStreams[streamId].length === 1) { - delete pc._shimmedLocalStreams[streamId]; - } - }); - } - return origRemoveTrack.apply(this, arguments); - }; - }, - - shimAddTrackRemoveTrack: function(window) { - var browserDetails = utils.detectBrowser(window); - // shim addTrack and removeTrack. - if (window.RTCPeerConnection.prototype.addTrack && - browserDetails.version >= 65) { - return this.shimAddTrackRemoveTrackWithNative(window); - } - - // also shim pc.getLocalStreams when addTrack is shimmed - // to return the original streams. - var origGetLocalStreams = window.RTCPeerConnection.prototype - .getLocalStreams; - window.RTCPeerConnection.prototype.getLocalStreams = function() { - var pc = this; - var nativeStreams = origGetLocalStreams.apply(this); - pc._reverseStreams = pc._reverseStreams || {}; - return nativeStreams.map(function(stream) { - return pc._reverseStreams[stream.id]; - }); - }; - - var origAddStream = window.RTCPeerConnection.prototype.addStream; - window.RTCPeerConnection.prototype.addStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - stream.getTracks().forEach(function(track) { - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - }); - // Add identity mapping for consistency with addTrack. - // Unless this is being used with a stream from addTrack. - if (!pc._reverseStreams[stream.id]) { - var newStream = new window.MediaStream(stream.getTracks()); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - stream = newStream; - } - origAddStream.apply(pc, [stream]); - }; - - var origRemoveStream = window.RTCPeerConnection.prototype.removeStream; - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - - origRemoveStream.apply(pc, [(pc._streams[stream.id] || stream)]); - delete pc._reverseStreams[(pc._streams[stream.id] ? - pc._streams[stream.id].id : stream.id)]; - delete pc._streams[stream.id]; - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - var streams = [].slice.call(arguments, 1); - if (streams.length !== 1 || - !streams[0].getTracks().find(function(t) { - return t === track; - })) { - // this is not fully correct but all we can manage without - // [[associated MediaStreams]] internal slot. - throw new DOMException( - 'The adapter.js addTrack polyfill only supports a single ' + - ' stream which is associated with the specified track.', - 'NotSupportedError'); - } - - var alreadyExists = pc.getSenders().find(function(s) { - return s.track === track; - }); - if (alreadyExists) { - throw new DOMException('Track already exists.', - 'InvalidAccessError'); - } - - pc._streams = pc._streams || {}; - pc._reverseStreams = pc._reverseStreams || {}; - var oldStream = pc._streams[stream.id]; - if (oldStream) { - // this is using odd Chrome behaviour, use with caution: - // https://bugs.chromium.org/p/webrtc/issues/detail?id=7815 - // Note: we rely on the high-level addTrack/dtmf shim to - // create the sender with a dtmf sender. - oldStream.addTrack(track); - - // Trigger ONN async. - Promise.resolve().then(function() { - pc.dispatchEvent(new Event('negotiationneeded')); - }); - } else { - var newStream = new window.MediaStream([track]); - pc._streams[stream.id] = newStream; - pc._reverseStreams[newStream.id] = stream; - pc.addStream(newStream); - } - return pc.getSenders().find(function(s) { - return s.track === track; - }); - }; - - // replace the internal stream id with the external one and - // vice versa. - function replaceInternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(internalStream.id, 'g'), - externalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - function replaceExternalStreamId(pc, description) { - var sdp = description.sdp; - Object.keys(pc._reverseStreams || []).forEach(function(internalId) { - var externalStream = pc._reverseStreams[internalId]; - var internalStream = pc._streams[externalStream.id]; - sdp = sdp.replace(new RegExp(externalStream.id, 'g'), - internalStream.id); - }); - return new RTCSessionDescription({ - type: description.type, - sdp: sdp - }); - } - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - var args = arguments; - var isLegacyCall = arguments.length && - typeof arguments[0] === 'function'; - if (isLegacyCall) { - return nativeMethod.apply(pc, [ - function(description) { - var desc = replaceInternalStreamId(pc, description); - args[0].apply(null, [desc]); - }, - function(err) { - if (args[1]) { - args[1].apply(null, err); - } - }, arguments[2] - ]); - } - return nativeMethod.apply(pc, arguments) - .then(function(description) { - return replaceInternalStreamId(pc, description); - }); - }; - }); - - var origSetLocalDescription = - window.RTCPeerConnection.prototype.setLocalDescription; - window.RTCPeerConnection.prototype.setLocalDescription = function() { - var pc = this; - if (!arguments.length || !arguments[0].type) { - return origSetLocalDescription.apply(pc, arguments); - } - arguments[0] = replaceExternalStreamId(pc, arguments[0]); - return origSetLocalDescription.apply(pc, arguments); - }; - - // TODO: mangle getStats: https://w3c.github.io/webrtc-stats/#dom-rtcmediastreamstats-streamidentifier - - var origLocalDescription = Object.getOwnPropertyDescriptor( - window.RTCPeerConnection.prototype, 'localDescription'); - Object.defineProperty(window.RTCPeerConnection.prototype, - 'localDescription', { - get: function() { - var pc = this; - var description = origLocalDescription.get.apply(this); - if (description.type === '') { - return description; - } - return replaceInternalStreamId(pc, description); - } - }); - - window.RTCPeerConnection.prototype.removeTrack = function(sender) { - var pc = this; - if (pc.signalingState === 'closed') { - throw new DOMException( - 'The RTCPeerConnection\'s signalingState is \'closed\'.', - 'InvalidStateError'); - } - // We can not yet check for sender instanceof RTCRtpSender - // since we shim RTPSender. So we check if sender._pc is set. - if (!sender._pc) { - throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack ' + - 'does not implement interface RTCRtpSender.', 'TypeError'); - } - var isLocal = sender._pc === pc; - if (!isLocal) { - throw new DOMException('Sender was not created by this connection.', - 'InvalidAccessError'); - } - - // Search for the native stream the senders track belongs to. - pc._streams = pc._streams || {}; - var stream; - Object.keys(pc._streams).forEach(function(streamid) { - var hasTrack = pc._streams[streamid].getTracks().find(function(track) { - return sender.track === track; - }); - if (hasTrack) { - stream = pc._streams[streamid]; - } - }); - - if (stream) { - if (stream.getTracks().length === 1) { - // if this is the last track of the stream, remove the stream. This - // takes care of any shimmed _senders. - pc.removeStream(pc._reverseStreams[stream.id]); - } else { - // relying on the same odd chrome behaviour as above. - stream.removeTrack(sender.track); - } - pc.dispatchEvent(new Event('negotiationneeded')); - } - }; - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - // The RTCPeerConnection object. - if (!window.RTCPeerConnection && window.webkitRTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - // Translate iceTransportPolicy to iceTransports, - // see https://code.google.com/p/webrtc/issues/detail?id=4869 - // this was fixed in M56 along with unprefixing RTCPeerConnection. - logging('PeerConnection'); - if (pcConfig && pcConfig.iceTransportPolicy) { - pcConfig.iceTransports = pcConfig.iceTransportPolicy; - } - - return new window.webkitRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.webkitRTCPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if (window.webkitRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.webkitRTCPeerConnection.generateCertificate; - } - }); - } - } else { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - - var origGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function(selector, - successCallback, errorCallback) { - var pc = this; - var args = arguments; - - // If selector is a function then we are in the old style stats so just - // pass back the original getStats format to avoid breaking old users. - if (arguments.length > 0 && typeof selector === 'function') { - return origGetStats.apply(this, arguments); - } - - // When spec-style getStats is supported, return those when called with - // either no arguments or the selector argument is null. - if (origGetStats.length === 0 && (arguments.length === 0 || - typeof arguments[0] !== 'function')) { - return origGetStats.apply(this, []); - } - - var fixChromeStats_ = function(response) { - var standardReport = {}; - var reports = response.result(); - reports.forEach(function(report) { - var standardStats = { - id: report.id, - timestamp: report.timestamp, - type: { - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }[report.type] || report.type - }; - report.names().forEach(function(name) { - standardStats[name] = report.stat(name); - }); - standardReport[standardStats.id] = standardStats; - }); - - return standardReport; - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - return new Map(Object.keys(stats).map(function(key) { - return [key, stats[key]]; - })); - }; - - if (arguments.length >= 2) { - var successCallbackWrapper_ = function(response) { - args[1](makeMapStats(fixChromeStats_(response))); - }; - - return origGetStats.apply(this, [successCallbackWrapper_, - arguments[0]]); - } - - // promise-support - return new Promise(function(resolve, reject) { - origGetStats.apply(pc, [ - function(response) { - resolve(makeMapStats(fixChromeStats_(response))); - }, reject]); - }).then(successCallback, errorCallback); - }; - - // add promise support -- natively available in Chrome 51 - if (browserDetails.version < 51) { - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var args = arguments; - var pc = this; - var promise = new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [args[0], resolve, reject]); - }); - if (args.length < 2) { - return promise; - } - return promise.then(function() { - args[1].apply(null, []); - }, - function(err) { - if (args.length >= 3) { - args[2].apply(null, [err]); - } - }); - }; - }); - } - - // promise support for createOffer and createAnswer. Available (without - // bugs) since M52: crbug/619289 - if (browserDetails.version < 52) { - ['createOffer', 'createAnswer'].forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - var pc = this; - if (arguments.length < 1 || (arguments.length === 1 && - typeof arguments[0] === 'object')) { - var opts = arguments.length === 1 ? arguments[0] : undefined; - return new Promise(function(resolve, reject) { - nativeMethod.apply(pc, [resolve, reject, opts]); - }); - } - return nativeMethod.apply(this, arguments); - }; - }); - } - - // shim implicit creation of RTCSessionDescription/RTCIceCandidate - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - } -}; - -},{"../utils.js":13,"./getusermedia":6}],6:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; -var utils = require('../utils.js'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - - var constraintsToChrome_ = function(c) { - if (typeof c !== 'object' || c.mandatory || c.optional) { - return c; - } - var cc = {}; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = (typeof c[key] === 'object') ? c[key] : {ideal: c[key]}; - if (r.exact !== undefined && typeof r.exact === 'number') { - r.min = r.max = r.exact; - } - var oldname_ = function(prefix, name) { - if (prefix) { - return prefix + name.charAt(0).toUpperCase() + name.slice(1); - } - return (name === 'deviceId') ? 'sourceId' : name; - }; - if (r.ideal !== undefined) { - cc.optional = cc.optional || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[oldname_('min', key)] = r.ideal; - cc.optional.push(oc); - oc = {}; - oc[oldname_('max', key)] = r.ideal; - cc.optional.push(oc); - } else { - oc[oldname_('', key)] = r.ideal; - cc.optional.push(oc); - } - } - if (r.exact !== undefined && typeof r.exact !== 'number') { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_('', key)] = r.exact; - } else { - ['min', 'max'].forEach(function(mix) { - if (r[mix] !== undefined) { - cc.mandatory = cc.mandatory || {}; - cc.mandatory[oldname_(mix, key)] = r[mix]; - } - }); - } - }); - if (c.advanced) { - cc.optional = (cc.optional || []).concat(c.advanced); - } - return cc; - }; - - var shimConstraints_ = function(constraints, func) { - if (browserDetails.version >= 61) { - return func(constraints); - } - constraints = JSON.parse(JSON.stringify(constraints)); - if (constraints && typeof constraints.audio === 'object') { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - constraints = JSON.parse(JSON.stringify(constraints)); - remap(constraints.audio, 'autoGainControl', 'googAutoGainControl'); - remap(constraints.audio, 'noiseSuppression', 'googNoiseSuppression'); - constraints.audio = constraintsToChrome_(constraints.audio); - } - if (constraints && typeof constraints.video === 'object') { - // Shim facingMode for mobile & surface pro. - var face = constraints.video.facingMode; - face = face && ((typeof face === 'object') ? face : {ideal: face}); - var getSupportedFacingModeLies = browserDetails.version < 66; - - if ((face && (face.exact === 'user' || face.exact === 'environment' || - face.ideal === 'user' || face.ideal === 'environment')) && - !(navigator.mediaDevices.getSupportedConstraints && - navigator.mediaDevices.getSupportedConstraints().facingMode && - !getSupportedFacingModeLies)) { - delete constraints.video.facingMode; - var matches; - if (face.exact === 'environment' || face.ideal === 'environment') { - matches = ['back', 'rear']; - } else if (face.exact === 'user' || face.ideal === 'user') { - matches = ['front']; - } - if (matches) { - // Look for matches in label, or use last cam for back (typical). - return navigator.mediaDevices.enumerateDevices() - .then(function(devices) { - devices = devices.filter(function(d) { - return d.kind === 'videoinput'; - }); - var dev = devices.find(function(d) { - return matches.some(function(match) { - return d.label.toLowerCase().indexOf(match) !== -1; - }); - }); - if (!dev && devices.length && matches.indexOf('back') !== -1) { - dev = devices[devices.length - 1]; // more likely the back cam - } - if (dev) { - constraints.video.deviceId = face.exact ? {exact: dev.deviceId} : - {ideal: dev.deviceId}; - } - constraints.video = constraintsToChrome_(constraints.video); - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }); - } - } - constraints.video = constraintsToChrome_(constraints.video); - } - logging('chrome: ' + JSON.stringify(constraints)); - return func(constraints); - }; - - var shimError_ = function(e) { - return { - name: { - PermissionDeniedError: 'NotAllowedError', - InvalidStateError: 'NotReadableError', - DevicesNotFoundError: 'NotFoundError', - ConstraintNotSatisfiedError: 'OverconstrainedError', - TrackStartError: 'NotReadableError', - MediaDeviceFailedDueToShutdown: 'NotReadableError', - MediaDeviceKillSwitchOn: 'NotReadableError' - }[e.name] || e.name, - message: e.message, - constraint: e.constraintName, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - var getUserMedia_ = function(constraints, onSuccess, onError) { - shimConstraints_(constraints, function(c) { - navigator.webkitGetUserMedia(c, onSuccess, function(e) { - if (onError) { - onError(shimError_(e)); - } - }); - }); - }; - - navigator.getUserMedia = getUserMedia_; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - navigator.getUserMedia(constraints, resolve, reject); - }); - }; - - if (!navigator.mediaDevices) { - navigator.mediaDevices = { - getUserMedia: getUserMediaPromise_, - enumerateDevices: function() { - return new Promise(function(resolve) { - var kinds = {audio: 'audioinput', video: 'videoinput'}; - return window.MediaStreamTrack.getSources(function(devices) { - resolve(devices.map(function(device) { - return {label: device.label, - kind: kinds[device.kind], - deviceId: device.id, - groupId: ''}; - })); - }); - }); - }, - getSupportedConstraints: function() { - return { - deviceId: true, echoCancellation: true, facingMode: true, - frameRate: true, height: true, width: true - }; - } - }; - } - - // A shim for getUserMedia method on the mediaDevices object. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (!navigator.mediaDevices.getUserMedia) { - navigator.mediaDevices.getUserMedia = function(constraints) { - return getUserMediaPromise_(constraints); - }; - } else { - // Even though Chrome 45 has navigator.mediaDevices and a getUserMedia - // function which returns a Promise, it does not accept spec-style - // constraints. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(cs) { - return shimConstraints_(cs, function(c) { - return origGetUserMedia(c).then(function(stream) { - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('', 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }); - }; - } - - // Dummy devicechange event methods. - // TODO(KaptenJansson) remove once implemented in Chrome stable. - if (typeof navigator.mediaDevices.addEventListener === 'undefined') { - navigator.mediaDevices.addEventListener = function() { - logging('Dummy mediaDevices.addEventListener called.'); - }; - } - if (typeof navigator.mediaDevices.removeEventListener === 'undefined') { - navigator.mediaDevices.removeEventListener = function() { - logging('Dummy mediaDevices.removeEventListener called.'); - }; - } -}; - -},{"../utils.js":13}],7:[function(require,module,exports){ -/* - * Copyright (c) 2017 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var SDPUtils = require('sdp'); -var utils = require('./utils'); - -module.exports = { - shimRTCIceCandidate: function(window) { - // foundation is arbitrarily chosen as an indicator for full support for - // https://w3c.github.io/webrtc-pc/#rtcicecandidate-interface - if (window.RTCIceCandidate && 'foundation' in - window.RTCIceCandidate.prototype) { - return; - } - - var NativeRTCIceCandidate = window.RTCIceCandidate; - window.RTCIceCandidate = function(args) { - // Remove the a= which shouldn't be part of the candidate string. - if (typeof args === 'object' && args.candidate && - args.candidate.indexOf('a=') === 0) { - args = JSON.parse(JSON.stringify(args)); - args.candidate = args.candidate.substr(2); - } - - // Augment the native candidate with the parsed fields. - var nativeCandidate = new NativeRTCIceCandidate(args); - var parsedCandidate = SDPUtils.parseCandidate(args.candidate); - var augmentedCandidate = Object.assign(nativeCandidate, - parsedCandidate); - - // Add a serializer that does not serialize the extra attributes. - augmentedCandidate.toJSON = function() { - return { - candidate: augmentedCandidate.candidate, - sdpMid: augmentedCandidate.sdpMid, - sdpMLineIndex: augmentedCandidate.sdpMLineIndex, - usernameFragment: augmentedCandidate.usernameFragment, - }; - }; - return augmentedCandidate; - }; - - // Hook up the augmented candidate in onicecandidate and - // addEventListener('icecandidate', ...) - utils.wrapPeerConnectionEvent(window, 'icecandidate', function(e) { - if (e.candidate) { - Object.defineProperty(e, 'candidate', { - value: new window.RTCIceCandidate(e.candidate), - writable: 'false' - }); - } - return e; - }); - }, - - // shimCreateObjectURL must be called before shimSourceObject to avoid loop. - - shimCreateObjectURL: function(window) { - var URL = window && window.URL; - - if (!(typeof window === 'object' && window.HTMLMediaElement && - 'srcObject' in window.HTMLMediaElement.prototype && - URL.createObjectURL && URL.revokeObjectURL)) { - // Only shim CreateObjectURL using srcObject if srcObject exists. - return undefined; - } - - var nativeCreateObjectURL = URL.createObjectURL.bind(URL); - var nativeRevokeObjectURL = URL.revokeObjectURL.bind(URL); - var streams = new Map(), newId = 0; - - URL.createObjectURL = function(stream) { - if ('getTracks' in stream) { - var url = 'polyblob:' + (++newId); - streams.set(url, stream); - utils.deprecated('URL.createObjectURL(stream)', - 'elem.srcObject = stream'); - return url; - } - return nativeCreateObjectURL(stream); - }; - URL.revokeObjectURL = function(url) { - nativeRevokeObjectURL(url); - streams.delete(url); - }; - - var dsc = Object.getOwnPropertyDescriptor(window.HTMLMediaElement.prototype, - 'src'); - Object.defineProperty(window.HTMLMediaElement.prototype, 'src', { - get: function() { - return dsc.get.apply(this); - }, - set: function(url) { - this.srcObject = streams.get(url) || null; - return dsc.set.apply(this, [url]); - } - }); - - var nativeSetAttribute = window.HTMLMediaElement.prototype.setAttribute; - window.HTMLMediaElement.prototype.setAttribute = function() { - if (arguments.length === 2 && - ('' + arguments[0]).toLowerCase() === 'src') { - this.srcObject = streams.get(arguments[1]) || null; - } - return nativeSetAttribute.apply(this, arguments); - }; - }, - - shimMaxMessageSize: function(window) { - if (window.RTCSctpTransport || !window.RTCPeerConnection) { - return; - } - var browserDetails = utils.detectBrowser(window); - - if (!('sctp' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'sctp', { - get: function() { - return typeof this._sctp === 'undefined' ? null : this._sctp; - } - }); - } - - var sctpInDescription = function(description) { - var sections = SDPUtils.splitSections(description.sdp); - sections.shift(); - return sections.some(function(mediaSection) { - var mLine = SDPUtils.parseMLine(mediaSection); - return mLine && mLine.kind === 'application' - && mLine.protocol.indexOf('SCTP') !== -1; - }); - }; - - var getRemoteFirefoxVersion = function(description) { - // TODO: Is there a better solution for detecting Firefox? - var match = description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/); - if (match === null || match.length < 2) { - return -1; - } - var version = parseInt(match[1], 10); - // Test for NaN (yes, this is ugly) - return version !== version ? -1 : version; - }; - - var getCanSendMaxMessageSize = function(remoteIsFirefox) { - // Every implementation we know can send at least 64 KiB. - // Note: Although Chrome is technically able to send up to 256 KiB, the - // data does not reach the other peer reliably. - // See: https://bugs.chromium.org/p/webrtc/issues/detail?id=8419 - var canSendMaxMessageSize = 65536; - if (browserDetails.browser === 'firefox') { - if (browserDetails.version < 57) { - if (remoteIsFirefox === -1) { - // FF < 57 will send in 16 KiB chunks using the deprecated PPID - // fragmentation. - canSendMaxMessageSize = 16384; - } else { - // However, other FF (and RAWRTC) can reassemble PPID-fragmented - // messages. Thus, supporting ~2 GiB when sending. - canSendMaxMessageSize = 2147483637; - } - } else { - // Currently, all FF >= 57 will reset the remote maximum message size - // to the default value when a data channel is created at a later - // stage. :( - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - canSendMaxMessageSize = - browserDetails.version === 57 ? 65535 : 65536; - } - } - return canSendMaxMessageSize; - }; - - var getMaxMessageSize = function(description, remoteIsFirefox) { - // Note: 65536 bytes is the default value from the SDP spec. Also, - // every implementation we know supports receiving 65536 bytes. - var maxMessageSize = 65536; - - // FF 57 has a slightly incorrect default remote max message size, so - // we need to adjust it here to avoid a failure when sending. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1425697 - if (browserDetails.browser === 'firefox' - && browserDetails.version === 57) { - maxMessageSize = 65535; - } - - var match = SDPUtils.matchPrefix(description.sdp, 'a=max-message-size:'); - if (match.length > 0) { - maxMessageSize = parseInt(match[0].substr(19), 10); - } else if (browserDetails.browser === 'firefox' && - remoteIsFirefox !== -1) { - // If the maximum message size is not present in the remote SDP and - // both local and remote are Firefox, the remote peer can receive - // ~2 GiB. - maxMessageSize = 2147483637; - } - return maxMessageSize; - }; - - var origSetRemoteDescription = - window.RTCPeerConnection.prototype.setRemoteDescription; - window.RTCPeerConnection.prototype.setRemoteDescription = function() { - var pc = this; - pc._sctp = null; - - if (sctpInDescription(arguments[0])) { - // Check if the remote is FF. - var isFirefox = getRemoteFirefoxVersion(arguments[0]); - - // Get the maximum message size the local peer is capable of sending - var canSendMMS = getCanSendMaxMessageSize(isFirefox); - - // Get the maximum message size of the remote peer. - var remoteMMS = getMaxMessageSize(arguments[0], isFirefox); - - // Determine final maximum message size - var maxMessageSize; - if (canSendMMS === 0 && remoteMMS === 0) { - maxMessageSize = Number.POSITIVE_INFINITY; - } else if (canSendMMS === 0 || remoteMMS === 0) { - maxMessageSize = Math.max(canSendMMS, remoteMMS); - } else { - maxMessageSize = Math.min(canSendMMS, remoteMMS); - } - - // Create a dummy RTCSctpTransport object and the 'maxMessageSize' - // attribute. - var sctp = {}; - Object.defineProperty(sctp, 'maxMessageSize', { - get: function() { - return maxMessageSize; - } - }); - pc._sctp = sctp; - } - - return origSetRemoteDescription.apply(pc, arguments); - }; - }, - - shimSendThrowTypeError: function(window) { - // Note: Although Firefox >= 57 has a native implementation, the maximum - // message size can be reset for all data channels at a later stage. - // See: https://bugzilla.mozilla.org/show_bug.cgi?id=1426831 - - var origCreateDataChannel = - window.RTCPeerConnection.prototype.createDataChannel; - window.RTCPeerConnection.prototype.createDataChannel = function() { - var pc = this; - var dataChannel = origCreateDataChannel.apply(pc, arguments); - var origDataChannelSend = dataChannel.send; - - // Patch 'send' method - dataChannel.send = function() { - var dc = this; - var data = arguments[0]; - var length = data.length || data.size || data.byteLength; - if (length > pc.sctp.maxMessageSize) { - throw new DOMException('Message too large (can send a maximum of ' + - pc.sctp.maxMessageSize + ' bytes)', 'TypeError'); - } - return origDataChannelSend.apply(dc, arguments); - }; - - return dataChannel; - }; - } -}; - -},{"./utils":13,"sdp":2}],8:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var shimRTCPeerConnection = require('rtcpeerconnection-shim'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (window.RTCIceGatherer) { - // ORTC defines an RTCIceCandidate object but no constructor. - // Not implemented in Edge. - if (!window.RTCIceCandidate) { - window.RTCIceCandidate = function(args) { - return args; - }; - } - // ORTC does not have a session description object but - // other browsers (i.e. Chrome) that will support both PC and ORTC - // in the future might have this defined already. - if (!window.RTCSessionDescription) { - window.RTCSessionDescription = function(args) { - return args; - }; - } - // this adds an additional event listener to MediaStrackTrack that signals - // when a tracks enabled property was changed. Workaround for a bug in - // addStream, see below. No longer required in 15025+ - if (browserDetails.version < 15025) { - var origMSTEnabled = Object.getOwnPropertyDescriptor( - window.MediaStreamTrack.prototype, 'enabled'); - Object.defineProperty(window.MediaStreamTrack.prototype, 'enabled', { - set: function(value) { - origMSTEnabled.set.call(this, value); - var ev = new Event('enabled'); - ev.enabled = value; - this.dispatchEvent(ev); - } - }); - } - } - - // ORTC defines the DTMF sender a bit different. - // https://github.com/w3c/ortc/issues/714 - if (window.RTCRtpSender && !('dtmf' in window.RTCRtpSender.prototype)) { - Object.defineProperty(window.RTCRtpSender.prototype, 'dtmf', { - get: function() { - if (this._dtmf === undefined) { - if (this.track.kind === 'audio') { - this._dtmf = new window.RTCDtmfSender(this); - } else if (this.track.kind === 'video') { - this._dtmf = null; - } - } - return this._dtmf; - } - }); - } - - window.RTCPeerConnection = - shimRTCPeerConnection(window, browserDetails.version); - }, - shimReplaceTrack: function(window) { - // ORTC has replaceTrack -- https://github.com/w3c/ortc/issues/614 - if (window.RTCRtpSender && - !('replaceTrack' in window.RTCRtpSender.prototype)) { - window.RTCRtpSender.prototype.replaceTrack = - window.RTCRtpSender.prototype.setTrack; - } - } -}; - -},{"../utils":13,"./getusermedia":9,"rtcpeerconnection-shim":1}],9:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -// Expose public methods. -module.exports = function(window) { - var navigator = window && window.navigator; - - var shimError_ = function(e) { - return { - name: {PermissionDeniedError: 'NotAllowedError'}[e.name] || e.name, - message: e.message, - constraint: e.constraint, - toString: function() { - return this.name; - } - }; - }; - - // getUserMedia error shim. - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).catch(function(e) { - return Promise.reject(shimError_(e)); - }); - }; -}; - -},{}],10:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); - -module.exports = { - shimGetUserMedia: require('./getusermedia'), - shimOnTrack: function(window) { - if (typeof window === 'object' && window.RTCPeerConnection && !('ontrack' in - window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'ontrack', { - get: function() { - return this._ontrack; - }, - set: function(f) { - if (this._ontrack) { - this.removeEventListener('track', this._ontrack); - this.removeEventListener('addstream', this._ontrackpoly); - } - this.addEventListener('track', this._ontrack = f); - this.addEventListener('addstream', this._ontrackpoly = function(e) { - e.stream.getTracks().forEach(function(track) { - var event = new Event('track'); - event.track = track; - event.receiver = {track: track}; - event.transceiver = {receiver: event.receiver}; - event.streams = [e.stream]; - this.dispatchEvent(event); - }.bind(this)); - }.bind(this)); - } - }); - } - if (typeof window === 'object' && window.RTCTrackEvent && - ('receiver' in window.RTCTrackEvent.prototype) && - !('transceiver' in window.RTCTrackEvent.prototype)) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimSourceObject: function(window) { - // Firefox has supported mozSrcObject since FF22, unprefixed in 42. - if (typeof window === 'object') { - if (window.HTMLMediaElement && - !('srcObject' in window.HTMLMediaElement.prototype)) { - // Shim the srcObject property, once, when HTMLMediaElement is found. - Object.defineProperty(window.HTMLMediaElement.prototype, 'srcObject', { - get: function() { - return this.mozSrcObject; - }, - set: function(stream) { - this.mozSrcObject = stream; - } - }); - } - } - }, - - shimPeerConnection: function(window) { - var browserDetails = utils.detectBrowser(window); - - if (typeof window !== 'object' || !(window.RTCPeerConnection || - window.mozRTCPeerConnection)) { - return; // probably media.peerconnection.enabled=false in about:config - } - // The RTCPeerConnection object. - if (!window.RTCPeerConnection) { - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (browserDetails.version < 38) { - // .urls is not supported in FF < 38. - // create RTCIceServers with a single url. - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (server.hasOwnProperty('urls')) { - for (var j = 0; j < server.urls.length; j++) { - var newServer = { - url: server.urls[j] - }; - if (server.urls[j].indexOf('turn') === 0) { - newServer.username = server.username; - newServer.credential = server.credential; - } - newIceServers.push(newServer); - } - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - } - return new window.mozRTCPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = - window.mozRTCPeerConnection.prototype; - - // wrap static methods. Currently just generateCertificate. - if (window.mozRTCPeerConnection.generateCertificate) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return window.mozRTCPeerConnection.generateCertificate; - } - }); - } - - window.RTCSessionDescription = window.mozRTCSessionDescription; - window.RTCIceCandidate = window.mozRTCIceCandidate; - } - - // shim away need for obsolete RTCIceCandidate/RTCSessionDescription. - ['setLocalDescription', 'setRemoteDescription', 'addIceCandidate'] - .forEach(function(method) { - var nativeMethod = window.RTCPeerConnection.prototype[method]; - window.RTCPeerConnection.prototype[method] = function() { - arguments[0] = new ((method === 'addIceCandidate') ? - window.RTCIceCandidate : - window.RTCSessionDescription)(arguments[0]); - return nativeMethod.apply(this, arguments); - }; - }); - - // support for addIceCandidate(null or undefined) - var nativeAddIceCandidate = - window.RTCPeerConnection.prototype.addIceCandidate; - window.RTCPeerConnection.prototype.addIceCandidate = function() { - if (!arguments[0]) { - if (arguments[1]) { - arguments[1].apply(null); - } - return Promise.resolve(); - } - return nativeAddIceCandidate.apply(this, arguments); - }; - - // shim getStats with maplike support - var makeMapStats = function(stats) { - var map = new Map(); - Object.keys(stats).forEach(function(key) { - map.set(key, stats[key]); - map[key] = stats[key]; - }); - return map; - }; - - var modernStatsTypes = { - inboundrtp: 'inbound-rtp', - outboundrtp: 'outbound-rtp', - candidatepair: 'candidate-pair', - localcandidate: 'local-candidate', - remotecandidate: 'remote-candidate' - }; - - var nativeGetStats = window.RTCPeerConnection.prototype.getStats; - window.RTCPeerConnection.prototype.getStats = function( - selector, - onSucc, - onErr - ) { - return nativeGetStats.apply(this, [selector || null]) - .then(function(stats) { - if (browserDetails.version < 48) { - stats = makeMapStats(stats); - } - if (browserDetails.version < 53 && !onSucc) { - // Shim only promise getStats with spec-hyphens in type names - // Leave callback version alone; misc old uses of forEach before Map - try { - stats.forEach(function(stat) { - stat.type = modernStatsTypes[stat.type] || stat.type; - }); - } catch (e) { - if (e.name !== 'TypeError') { - throw e; - } - // Avoid TypeError: "type" is read-only, in old versions. 34-43ish - stats.forEach(function(stat, i) { - stats.set(i, Object.assign({}, stat, { - type: modernStatsTypes[stat.type] || stat.type - })); - }); - } - } - return stats; - }) - .then(onSucc, onErr); - }; - }, - - shimRemoveStream: function(window) { - if (!window.RTCPeerConnection || - 'removeStream' in window.RTCPeerConnection.prototype) { - return; - } - window.RTCPeerConnection.prototype.removeStream = function(stream) { - var pc = this; - utils.deprecated('removeStream', 'removeTrack'); - this.getSenders().forEach(function(sender) { - if (sender.track && stream.getTracks().indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } -}; - -},{"../utils":13,"./getusermedia":11}],11:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var utils = require('../utils'); -var logging = utils.log; - -// Expose public methods. -module.exports = function(window) { - var browserDetails = utils.detectBrowser(window); - var navigator = window && window.navigator; - var MediaStreamTrack = window && window.MediaStreamTrack; - - var shimError_ = function(e) { - return { - name: { - InternalError: 'NotReadableError', - NotSupportedError: 'TypeError', - PermissionDeniedError: 'NotAllowedError', - SecurityError: 'NotAllowedError' - }[e.name] || e.name, - message: { - 'The operation is insecure.': 'The request is not allowed by the ' + - 'user agent or the platform in the current context.' - }[e.message] || e.message, - constraint: e.constraint, - toString: function() { - return this.name + (this.message && ': ') + this.message; - } - }; - }; - - // getUserMedia constraints shim. - var getUserMedia_ = function(constraints, onSuccess, onError) { - var constraintsToFF37_ = function(c) { - if (typeof c !== 'object' || c.require) { - return c; - } - var require = []; - Object.keys(c).forEach(function(key) { - if (key === 'require' || key === 'advanced' || key === 'mediaSource') { - return; - } - var r = c[key] = (typeof c[key] === 'object') ? - c[key] : {ideal: c[key]}; - if (r.min !== undefined || - r.max !== undefined || r.exact !== undefined) { - require.push(key); - } - if (r.exact !== undefined) { - if (typeof r.exact === 'number') { - r. min = r.max = r.exact; - } else { - c[key] = r.exact; - } - delete r.exact; - } - if (r.ideal !== undefined) { - c.advanced = c.advanced || []; - var oc = {}; - if (typeof r.ideal === 'number') { - oc[key] = {min: r.ideal, max: r.ideal}; - } else { - oc[key] = r.ideal; - } - c.advanced.push(oc); - delete r.ideal; - if (!Object.keys(r).length) { - delete c[key]; - } - } - }); - if (require.length) { - c.require = require; - } - return c; - }; - constraints = JSON.parse(JSON.stringify(constraints)); - if (browserDetails.version < 38) { - logging('spec: ' + JSON.stringify(constraints)); - if (constraints.audio) { - constraints.audio = constraintsToFF37_(constraints.audio); - } - if (constraints.video) { - constraints.video = constraintsToFF37_(constraints.video); - } - logging('ff37: ' + JSON.stringify(constraints)); - } - return navigator.mozGetUserMedia(constraints, onSuccess, function(e) { - onError(shimError_(e)); - }); - }; - - // Returns the result of getUserMedia as a Promise. - var getUserMediaPromise_ = function(constraints) { - return new Promise(function(resolve, reject) { - getUserMedia_(constraints, resolve, reject); - }); - }; - - // Shim for mediaDevices on older versions. - if (!navigator.mediaDevices) { - navigator.mediaDevices = {getUserMedia: getUserMediaPromise_, - addEventListener: function() { }, - removeEventListener: function() { } - }; - } - navigator.mediaDevices.enumerateDevices = - navigator.mediaDevices.enumerateDevices || function() { - return new Promise(function(resolve) { - var infos = [ - {kind: 'audioinput', deviceId: 'default', label: '', groupId: ''}, - {kind: 'videoinput', deviceId: 'default', label: '', groupId: ''} - ]; - resolve(infos); - }); - }; - - if (browserDetails.version < 41) { - // Work around http://bugzil.la/1169665 - var orgEnumerateDevices = - navigator.mediaDevices.enumerateDevices.bind(navigator.mediaDevices); - navigator.mediaDevices.enumerateDevices = function() { - return orgEnumerateDevices().then(undefined, function(e) { - if (e.name === 'NotFoundError') { - return []; - } - throw e; - }); - }; - } - if (browserDetails.version < 49) { - var origGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - return origGetUserMedia(c).then(function(stream) { - // Work around https://bugzil.la/802326 - if (c.audio && !stream.getAudioTracks().length || - c.video && !stream.getVideoTracks().length) { - stream.getTracks().forEach(function(track) { - track.stop(); - }); - throw new DOMException('The object can not be found here.', - 'NotFoundError'); - } - return stream; - }, function(e) { - return Promise.reject(shimError_(e)); - }); - }; - } - if (!(browserDetails.version > 55 && - 'autoGainControl' in navigator.mediaDevices.getSupportedConstraints())) { - var remap = function(obj, a, b) { - if (a in obj && !(b in obj)) { - obj[b] = obj[a]; - delete obj[a]; - } - }; - - var nativeGetUserMedia = navigator.mediaDevices.getUserMedia. - bind(navigator.mediaDevices); - navigator.mediaDevices.getUserMedia = function(c) { - if (typeof c === 'object' && typeof c.audio === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c.audio, 'autoGainControl', 'mozAutoGainControl'); - remap(c.audio, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeGetUserMedia(c); - }; - - if (MediaStreamTrack && MediaStreamTrack.prototype.getSettings) { - var nativeGetSettings = MediaStreamTrack.prototype.getSettings; - MediaStreamTrack.prototype.getSettings = function() { - var obj = nativeGetSettings.apply(this, arguments); - remap(obj, 'mozAutoGainControl', 'autoGainControl'); - remap(obj, 'mozNoiseSuppression', 'noiseSuppression'); - return obj; - }; - } - - if (MediaStreamTrack && MediaStreamTrack.prototype.applyConstraints) { - var nativeApplyConstraints = MediaStreamTrack.prototype.applyConstraints; - MediaStreamTrack.prototype.applyConstraints = function(c) { - if (this.kind === 'audio' && typeof c === 'object') { - c = JSON.parse(JSON.stringify(c)); - remap(c, 'autoGainControl', 'mozAutoGainControl'); - remap(c, 'noiseSuppression', 'mozNoiseSuppression'); - } - return nativeApplyConstraints.apply(this, [c]); - }; - } - } - navigator.getUserMedia = function(constraints, onSuccess, onError) { - if (browserDetails.version < 44) { - return getUserMedia_(constraints, onSuccess, onError); - } - // Replace Firefox 44+'s deprecation warning with unprefixed version. - utils.deprecated('navigator.getUserMedia', - 'navigator.mediaDevices.getUserMedia'); - navigator.mediaDevices.getUserMedia(constraints).then(onSuccess, onError); - }; -}; - -},{"../utils":13}],12:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ -'use strict'; -var utils = require('../utils'); - -module.exports = { - shimLocalStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getLocalStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getLocalStreams = function() { - if (!this._localStreams) { - this._localStreams = []; - } - return this._localStreams; - }; - } - if (!('getStreamById' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getStreamById = function(id) { - var result = null; - if (this._localStreams) { - this._localStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - if (this._remoteStreams) { - this._remoteStreams.forEach(function(stream) { - if (stream.id === id) { - result = stream; - } - }); - } - return result; - }; - } - if (!('addStream' in window.RTCPeerConnection.prototype)) { - var _addTrack = window.RTCPeerConnection.prototype.addTrack; - window.RTCPeerConnection.prototype.addStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - var pc = this; - stream.getTracks().forEach(function(track) { - _addTrack.call(pc, track, stream); - }); - }; - - window.RTCPeerConnection.prototype.addTrack = function(track, stream) { - if (stream) { - if (!this._localStreams) { - this._localStreams = [stream]; - } else if (this._localStreams.indexOf(stream) === -1) { - this._localStreams.push(stream); - } - } - return _addTrack.call(this, track, stream); - }; - } - if (!('removeStream' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.removeStream = function(stream) { - if (!this._localStreams) { - this._localStreams = []; - } - var index = this._localStreams.indexOf(stream); - if (index === -1) { - return; - } - this._localStreams.splice(index, 1); - var pc = this; - var tracks = stream.getTracks(); - this.getSenders().forEach(function(sender) { - if (tracks.indexOf(sender.track) !== -1) { - pc.removeTrack(sender); - } - }); - }; - } - }, - shimRemoteStreamsAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - if (!('getRemoteStreams' in window.RTCPeerConnection.prototype)) { - window.RTCPeerConnection.prototype.getRemoteStreams = function() { - return this._remoteStreams ? this._remoteStreams : []; - }; - } - if (!('onaddstream' in window.RTCPeerConnection.prototype)) { - Object.defineProperty(window.RTCPeerConnection.prototype, 'onaddstream', { - get: function() { - return this._onaddstream; - }, - set: function(f) { - var pc = this; - if (this._onaddstream) { - this.removeEventListener('addstream', this._onaddstream); - this.removeEventListener('track', this._onaddstreampoly); - } - this.addEventListener('addstream', this._onaddstream = f); - this.addEventListener('track', this._onaddstreampoly = function(e) { - e.streams.forEach(function(stream) { - if (!pc._remoteStreams) { - pc._remoteStreams = []; - } - if (pc._remoteStreams.indexOf(stream) >= 0) { - return; - } - pc._remoteStreams.push(stream); - var event = new Event('addstream'); - event.stream = stream; - pc.dispatchEvent(event); - }); - }); - } - }); - } - }, - shimCallbacksAPI: function(window) { - if (typeof window !== 'object' || !window.RTCPeerConnection) { - return; - } - var prototype = window.RTCPeerConnection.prototype; - var createOffer = prototype.createOffer; - var createAnswer = prototype.createAnswer; - var setLocalDescription = prototype.setLocalDescription; - var setRemoteDescription = prototype.setRemoteDescription; - var addIceCandidate = prototype.addIceCandidate; - - prototype.createOffer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createOffer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - prototype.createAnswer = function(successCallback, failureCallback) { - var options = (arguments.length >= 2) ? arguments[2] : arguments[0]; - var promise = createAnswer.apply(this, [options]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - - var withCallback = function(description, successCallback, failureCallback) { - var promise = setLocalDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setLocalDescription = withCallback; - - withCallback = function(description, successCallback, failureCallback) { - var promise = setRemoteDescription.apply(this, [description]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.setRemoteDescription = withCallback; - - withCallback = function(candidate, successCallback, failureCallback) { - var promise = addIceCandidate.apply(this, [candidate]); - if (!failureCallback) { - return promise; - } - promise.then(successCallback, failureCallback); - return Promise.resolve(); - }; - prototype.addIceCandidate = withCallback; - }, - shimGetUserMedia: function(window) { - var navigator = window && window.navigator; - - if (!navigator.getUserMedia) { - if (navigator.webkitGetUserMedia) { - navigator.getUserMedia = navigator.webkitGetUserMedia.bind(navigator); - } else if (navigator.mediaDevices && - navigator.mediaDevices.getUserMedia) { - navigator.getUserMedia = function(constraints, cb, errcb) { - navigator.mediaDevices.getUserMedia(constraints) - .then(cb, errcb); - }.bind(navigator); - } - } - }, - shimRTCIceServerUrls: function(window) { - // migrate from non-spec RTCIceServer.url to RTCIceServer.urls - var OrigPeerConnection = window.RTCPeerConnection; - window.RTCPeerConnection = function(pcConfig, pcConstraints) { - if (pcConfig && pcConfig.iceServers) { - var newIceServers = []; - for (var i = 0; i < pcConfig.iceServers.length; i++) { - var server = pcConfig.iceServers[i]; - if (!server.hasOwnProperty('urls') && - server.hasOwnProperty('url')) { - utils.deprecated('RTCIceServer.url', 'RTCIceServer.urls'); - server = JSON.parse(JSON.stringify(server)); - server.urls = server.url; - delete server.url; - newIceServers.push(server); - } else { - newIceServers.push(pcConfig.iceServers[i]); - } - } - pcConfig.iceServers = newIceServers; - } - return new OrigPeerConnection(pcConfig, pcConstraints); - }; - window.RTCPeerConnection.prototype = OrigPeerConnection.prototype; - // wrap static methods. Currently just generateCertificate. - if ('generateCertificate' in window.RTCPeerConnection) { - Object.defineProperty(window.RTCPeerConnection, 'generateCertificate', { - get: function() { - return OrigPeerConnection.generateCertificate; - } - }); - } - }, - shimTrackEventTransceiver: function(window) { - // Add event.transceiver member over deprecated event.receiver - if (typeof window === 'object' && window.RTCPeerConnection && - ('receiver' in window.RTCTrackEvent.prototype) && - // can't check 'transceiver' in window.RTCTrackEvent.prototype, as it is - // defined for some reason even when window.RTCTransceiver is not. - !window.RTCTransceiver) { - Object.defineProperty(window.RTCTrackEvent.prototype, 'transceiver', { - get: function() { - return {receiver: this.receiver}; - } - }); - } - }, - - shimCreateOfferLegacy: function(window) { - var origCreateOffer = window.RTCPeerConnection.prototype.createOffer; - window.RTCPeerConnection.prototype.createOffer = function(offerOptions) { - var pc = this; - if (offerOptions) { - var audioTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'audio'; - }); - if (offerOptions.offerToReceiveAudio === false && audioTransceiver) { - if (audioTransceiver.direction === 'sendrecv') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('sendonly'); - } else { - audioTransceiver.direction = 'sendonly'; - } - } else if (audioTransceiver.direction === 'recvonly') { - if (audioTransceiver.setDirection) { - audioTransceiver.setDirection('inactive'); - } else { - audioTransceiver.direction = 'inactive'; - } - } - } else if (offerOptions.offerToReceiveAudio === true && - !audioTransceiver) { - pc.addTransceiver('audio'); - } - - var videoTransceiver = pc.getTransceivers().find(function(transceiver) { - return transceiver.sender.track && - transceiver.sender.track.kind === 'video'; - }); - if (offerOptions.offerToReceiveVideo === false && videoTransceiver) { - if (videoTransceiver.direction === 'sendrecv') { - videoTransceiver.setDirection('sendonly'); - } else if (videoTransceiver.direction === 'recvonly') { - videoTransceiver.setDirection('inactive'); - } - } else if (offerOptions.offerToReceiveVideo === true && - !videoTransceiver) { - pc.addTransceiver('video'); - } - } - return origCreateOffer.apply(pc, arguments); - }; - } -}; - -},{"../utils":13}],13:[function(require,module,exports){ -/* - * Copyright (c) 2016 The WebRTC project authors. All Rights Reserved. - * - * Use of this source code is governed by a BSD-style license - * that can be found in the LICENSE file in the root of the source - * tree. - */ - /* eslint-env node */ -'use strict'; - -var logDisabled_ = true; -var deprecationWarnings_ = true; - -/** - * Extract browser version out of the provided user agent string. - * - * @param {!string} uastring userAgent string. - * @param {!string} expr Regular expression used as match criteria. - * @param {!number} pos position in the version string to be returned. - * @return {!number} browser version. - */ -function extractVersion(uastring, expr, pos) { - var match = uastring.match(expr); - return match && match.length >= pos && parseInt(match[pos], 10); -} - -// Wraps the peerconnection event eventNameToWrap in a function -// which returns the modified event object. -function wrapPeerConnectionEvent(window, eventNameToWrap, wrapper) { - if (!window.RTCPeerConnection) { - return; - } - var proto = window.RTCPeerConnection.prototype; - var nativeAddEventListener = proto.addEventListener; - proto.addEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap) { - return nativeAddEventListener.apply(this, arguments); - } - var wrappedCallback = function(e) { - cb(wrapper(e)); - }; - this._eventMap = this._eventMap || {}; - this._eventMap[cb] = wrappedCallback; - return nativeAddEventListener.apply(this, [nativeEventName, - wrappedCallback]); - }; - - var nativeRemoveEventListener = proto.removeEventListener; - proto.removeEventListener = function(nativeEventName, cb) { - if (nativeEventName !== eventNameToWrap || !this._eventMap - || !this._eventMap[cb]) { - return nativeRemoveEventListener.apply(this, arguments); - } - var unwrappedCb = this._eventMap[cb]; - delete this._eventMap[cb]; - return nativeRemoveEventListener.apply(this, [nativeEventName, - unwrappedCb]); - }; - - Object.defineProperty(proto, 'on' + eventNameToWrap, { - get: function() { - return this['_on' + eventNameToWrap]; - }, - set: function(cb) { - if (this['_on' + eventNameToWrap]) { - this.removeEventListener(eventNameToWrap, - this['_on' + eventNameToWrap]); - delete this['_on' + eventNameToWrap]; - } - if (cb) { - this.addEventListener(eventNameToWrap, - this['_on' + eventNameToWrap] = cb); - } - } - }); -} - -// Utility methods. -module.exports = { - extractVersion: extractVersion, - wrapPeerConnectionEvent: wrapPeerConnectionEvent, - disableLog: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - logDisabled_ = bool; - return (bool) ? 'adapter.js logging disabled' : - 'adapter.js logging enabled'; - }, - - /** - * Disable or enable deprecation warnings - * @param {!boolean} bool set to true to disable warnings. - */ - disableWarnings: function(bool) { - if (typeof bool !== 'boolean') { - return new Error('Argument type: ' + typeof bool + - '. Please use a boolean.'); - } - deprecationWarnings_ = !bool; - return 'adapter.js deprecation warnings ' + (bool ? 'disabled' : 'enabled'); - }, - - log: function() { - if (typeof window === 'object') { - if (logDisabled_) { - return; - } - if (typeof console !== 'undefined' && typeof console.log === 'function') { - console.log.apply(console, arguments); - } - } - }, - - /** - * Shows a deprecation warning suggesting the modern and spec-compatible API. - */ - deprecated: function(oldMethod, newMethod) { - if (!deprecationWarnings_) { - return; - } - console.warn(oldMethod + ' is deprecated, please use ' + newMethod + - ' instead.'); - }, - - /** - * Browser detector. - * - * @return {object} result containing browser and version - * properties. - */ - detectBrowser: function(window) { - var navigator = window && window.navigator; - - // Returned result object. - var result = {}; - result.browser = null; - result.version = null; - - // Fail early if it's not a browser - if (typeof window === 'undefined' || !window.navigator) { - result.browser = 'Not a browser.'; - return result; - } - - if (navigator.mozGetUserMedia) { // Firefox. - result.browser = 'firefox'; - result.version = extractVersion(navigator.userAgent, - /Firefox\/(\d+)\./, 1); - } else if (navigator.webkitGetUserMedia) { - // Chrome, Chromium, Webview, Opera. - // Version matches Chrome/WebRTC version. - result.browser = 'chrome'; - result.version = extractVersion(navigator.userAgent, - /Chrom(e|ium)\/(\d+)\./, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)) { // Edge. - result.browser = 'edge'; - result.version = extractVersion(navigator.userAgent, - /Edge\/(\d+).(\d+)$/, 2); - } else if (navigator.mediaDevices && - navigator.userAgent.match(/AppleWebKit\/(\d+)\./)) { // Safari. - result.browser = 'safari'; - result.version = extractVersion(navigator.userAgent, - /AppleWebKit\/(\d+)\./, 1); - } else { // Default fallthrough: not supported. - result.browser = 'Not a supported browser.'; - return result; - } - - return result; - } -}; - -},{}]},{},[3])(3) -}); \ No newline at end of file +(function($){function findLine(sdpLines,prefix,substr){return findLineInRange(sdpLines,0,-1,prefix,substr);} +function findLineInRange(sdpLines,startLine,endLine,prefix,substr){var realEndLine=(endLine!=-1)?endLine:sdpLines.length;for(var i=startLine;i=0;if(iOS){self.options.useVideo.setAttribute("playsinline",true);}} +var element=self.options.useAudio;console.log("REMOTE STREAM",stream,element);FSRTCattachMediaStream(element,stream);self.remoteStream=stream;onRemoteStreamSuccess(self,stream);} +function onOfferSDP(self,sdp){self.mediaData.SDP=self.stereoHack(sdp.sdp);console.log("Offer SDP");doCallback(self,"onOfferSDP");} +$.FSRTC.prototype.answer=function(sdp,onSuccess,onError){this.peer.addAnswerSDP({type:"answer",sdp:sdp},onSuccess,onError);};$.FSRTC.prototype.stopPeer=function(){if(self.peer){console.log("stopping peer");self.peer.stop();}} +$.FSRTC.prototype.stop=function(){var self=this;if(self.options.useVideo){self.options.useVideo.style.display='none';self.options.useVideo['src']='';} +if(self.localStream&&!self.options.useStream){if(typeof self.localStream.stop=='function'){self.localStream.stop();}else{if(self.localStream.active){var tracks=self.localStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}} +self.localStream=null;} +if(self.options.localVideo){deactivateLocalVideo(self.options.localVideo);} +if(self.options.localVideoStream&&!self.options.useStream){if(typeof self.options.localVideoStream.stop=='function'){self.options.localVideoStream.stop();}else{if(self.options.localVideoStream.active){var tracks=self.options.localVideoStream.getTracks();console.log(tracks);tracks.forEach(function(track,index){console.log(track);track.stop();})}}} +if(self.peer){console.log("stopping peer");self.peer.stop();}};$.FSRTC.prototype.getMute=function(){var self=this;return self.audioEnabled;} +$.FSRTC.prototype.setMute=function(what){var self=this;if(!self.localStream){return false;} +var audioTracks=self.localStream.getAudioTracks();for(var i=0,len=audioTracks.length;i=w&&$.FSRTC.validRes[i][1]>=h){w=$.FSRTC.validRes[i][0];h=$.FSRTC.validRes[i][1];}} +return[w,h];} +var resList=[[160,120],[320,180],[320,240],[640,360],[640,480],[1280,720],[1920,1080]];var resI=0;var ttl=0;var checkRes=function(cam,func){if(resI>=resList.length){var res={'validRes':$.FSRTC.validRes,'bestResSupported':$.FSRTC.bestResSupported()};localStorage.setItem("res_"+cam,$.toJSON(res));if(func)return func(res);return;} +w=resList[resI][0];h=resList[resI][1];resI++;var video={width:{exact:w},height:{exact:h}};if(cam!=="any"){video=assignMediaIdToConstraint(cam,video);} +getUserMedia({constraints:{audio:ttl++==0,video:video},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info(w+"x"+h+" supported.");$.FSRTC.validRes.push([w,h]);checkRes(cam,func);},onerror:function(e){console.warn(w+"x"+h+" not supported.");checkRes(cam,func);}});} +$.FSRTC.getValidRes=function(cam,func){var used=[];var cached=localStorage.getItem("res_"+cam);if(cached){var cache=$.parseJSON(cached);if(cache){$.FSRTC.validRes=cache.validRes;console.log("CACHED RES FOR CAM "+cam,cache);}else{console.error("INVALID CACHE");} +return func?func(cache):null;} +$.FSRTC.validRes=[];resI=0;checkRes(cam,func);} +$.FSRTC.checkPerms=function(runtime,check_audio,check_video){getUserMedia({constraints:{audio:check_audio,video:check_video,},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info("media perm init complete");if(runtime){setTimeout(runtime,100,true);}},onerror:function(e){if(check_video&&check_audio){console.error("error, retesting with audio params only");return $.FSRTC.checkPerms(runtime,check_audio,false);} +console.error("media perm init error");if(runtime){runtime(false)}}});}})(jQuery);(function($){$.JsonRpcClient=function(options){var self=this;this.options=$.extend({ajaxUrl:null,socketUrl:null,onmessage:null,login:null,passwd:null,sessid:null,loginParams:null,userVariables:null,getSocket:function(onmessage_cb){return self._getSocket(onmessage_cb);}},options);self.ws_cnt=0;this.wsOnMessage=function(event){self._wsOnMessage(event);};};$.JsonRpcClient.prototype._ws_socket=null;$.JsonRpcClient.prototype._ws_callbacks={};$.JsonRpcClient.prototype._current_id=1;$.JsonRpcClient.prototype.speedTest=function(bytes,cb){var socket=this.options.getSocket(this.wsOnMessage);if(socket!==null){this.speedCB=cb;this.speedBytes=bytes;socket.send("#SPU "+bytes);var loops=bytes/1024;var rem=bytes%1024;var i;var data=new Array(1024).join(".");for(i=0;i1){return false;} +return true;};$.JsonRpcClient.prototype.closeSocket=function(){var self=this;if(self.socketReady()){self._ws_socket.onclose=function(w){console.log("Closing Socket");};self._ws_socket.close();}};$.JsonRpcClient.prototype.loginData=function(params){var self=this;self.options.login=params.login;self.options.passwd=params.passwd;self.options.loginParams=params.loginParams;self.options.userVariables=params.userVariables;};$.JsonRpcClient.prototype.connectSocket=function(onmessage_cb){var self=this;if(self.to){clearTimeout(self.to);} +if(!self.socketReady()){self.authing=false;if(self._ws_socket){delete self._ws_socket;} +self._ws_socket=new WebSocket(self.options.socketUrl);if(self._ws_socket){self._ws_socket.onmessage=onmessage_cb;self._ws_socket.onclose=function(w){if(!self.ws_sleep){self.ws_sleep=1000;} +if(self.options.onWSClose){self.options.onWSClose(self);} +if(self.ws_cnt>10&&self.options.wsFallbackURL){self.options.socketUrl=self.options.wsFallbackURL;} +console.error("Websocket Lost "+self.ws_cnt+" sleep: "+self.ws_sleep+"msec");self.to=setTimeout(function(){console.log("Attempting Reconnection....");self.connectSocket(onmessage_cb);},self.ws_sleep);self.ws_cnt++;if(self.ws_sleep<3000&&(self.ws_cnt%10)===0){self.ws_sleep+=1000;}};self._ws_socket.onopen=function(){if(self.to){clearTimeout(self.to);} +self.ws_sleep=1000;self.ws_cnt=0;if(self.options.onWSConnect){self.options.onWSConnect(self);} +var req;while((req=$.JsonRpcClient.q.pop())){self._ws_socket.send(req);}};}} +return self._ws_socket?true:false;};$.JsonRpcClient.prototype.stopRetrying=function(){if(self.to) +clearTimeout(self.to);} +$.JsonRpcClient.prototype._getSocket=function(onmessage_cb){if(this.options.socketUrl===null||!("WebSocket"in window))return null;this.connectSocket(onmessage_cb);return this._ws_socket;};$.JsonRpcClient.q=[];$.JsonRpcClient.prototype._wsCall=function(socket,request,success_cb,error_cb){var request_json=$.toJSON(request);if(socket.readyState<1){self=this;$.JsonRpcClient.q.push(request_json);}else{socket.send(request_json);} +if('id'in request&&typeof success_cb!=='undefined'){this._ws_callbacks[request.id]={request:request_json,request_obj:request,success_cb:success_cb,error_cb:error_cb};}};$.JsonRpcClient.prototype._wsOnMessage=function(event){var response;if(event.data[0]=="#"&&event.data[1]=="S"&&event.data[2]=="P"){if(event.data[3]=="U"){this.up_dur=parseInt(event.data.substring(4));}else if(this.speedCB&&event.data[3]=="D"){this.down_dur=parseInt(event.data.substring(4));var up_kps=(((this.speedBytes*8)/(this.up_dur/1000))/1024).toFixed(0);var down_kps=(((this.speedBytes*8)/(this.down_dur/1000))/1024).toFixed(0);console.info("Speed Test: Up: "+up_kps+" Down: "+down_kps);var cb=this.speedCB;this.speedCB=null;cb(event,{upDur:this.up_dur,downDur:this.down_dur,upKPS:up_kps,downKPS:down_kps});} +return;} +try{response=$.parseJSON(event.data);if(typeof response==='object'&&'jsonrpc'in response&&response.jsonrpc==='2.0'){if('result'in response&&this._ws_callbacks[response.id]){var success_cb=this._ws_callbacks[response.id].success_cb;delete this._ws_callbacks[response.id];success_cb(response.result,this);return;}else if('error'in response&&this._ws_callbacks[response.id]){var error_cb=this._ws_callbacks[response.id].error_cb;var orig_req=this._ws_callbacks[response.id].request;if(!self.authing&&response.error.code==-32000&&self.options.login&&self.options.passwd){self.authing=true;this.call("login",{login:self.options.login,passwd:self.options.passwd,loginParams:self.options.loginParams,userVariables:self.options.userVariables},this._ws_callbacks[response.id].request_obj.method=="login"?function(e){self.authing=false;console.log("logged in");delete self._ws_callbacks[response.id];if(self.options.onWSLogin){self.options.onWSLogin(true,self);}}:function(e){self.authing=false;console.log("logged in, resending request id: "+response.id);var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send(orig_req);} +if(self.options.onWSLogin){self.options.onWSLogin(true,self);}},function(e){console.log("error logging in, request id:",response.id);delete self._ws_callbacks[response.id];error_cb(response.error,this);if(self.options.onWSLogin){self.options.onWSLogin(false,self);}});return;} +delete this._ws_callbacks[response.id];error_cb(response.error,this);return;}}}catch(err){console.log("ERROR: "+err);return;} +if(typeof this.options.onmessage==='function'){event.eventData=response;if(!event.eventData){event.eventData={};} +var reply=this.options.onmessage(event);if(reply&&typeof reply==="object"&&event.eventData.id){var msg={jsonrpc:"2.0",id:event.eventData.id,result:reply};var socket=self.options.getSocket(self.wsOnMessage);if(socket!==null){socket.send($.toJSON(msg));}}}};$.JsonRpcClient._batchObject=function(jsonrpcclient,all_done_cb,error_cb){this._requests=[];this.jsonrpcclient=jsonrpcclient;this.all_done_cb=all_done_cb;this.error_cb=typeof error_cb==='function'?error_cb:function(){};};$.JsonRpcClient._batchObject.prototype.call=function(method,params,success_cb,error_cb){if(!params){params={};} +if(this.options.sessid){params.sessid=this.options.sessid;} +if(!success_cb){success_cb=function(e){console.log("Success: ",e);};} +if(!error_cb){error_cb=function(e){console.log("Error: ",e);};} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params,id:this.jsonrpcclient._current_id++},success_cb:success_cb,error_cb:error_cb});};$.JsonRpcClient._batchObject.prototype.notify=function(method,params){if(this.options.sessid){params.sessid=this.options.sessid;} +this._requests.push({request:{jsonrpc:'2.0',method:method,params:params}});};$.JsonRpcClient._batchObject.prototype._execute=function(){var self=this;if(this._requests.length===0)return;var batch_request=[];var handlers={};var i=0;var call;var success_cb;var error_cb;var socket=self.jsonrpcclient.options.getSocket(self.jsonrpcclient.wsOnMessage);if(socket!==null){for(i=0;i0){data.params.useVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);dialog.setState($.verto.enum.state.recovering);break;case'verto.invite':if(data.params.sdp&&data.params.sdp.indexOf("m=video")>0){data.params.wantVideo=true;} +if(data.params.sdp&&data.params.sdp.indexOf("stereo=1")>0){data.params.useStereo=true;} +dialog=new $.verto.dialog($.verto.enum.direction.inbound,verto,data.params);break;default:console.debug("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED");break;}} +return{method:data.method};}else{switch(data.method){case'verto.punt':verto.purge();verto.logout();break;case'verto.event':var list=null;var key=null;if(data.params){key=data.params.eventChannel;} +if(key){list=verto.eventSUBS[key];if(!list){list=verto.eventSUBS[key.split(".")[0]];}} +if(!list&&key&&key===verto.sessid){if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.pvtEvent,data.params);}}else if(!list&&key&&verto.dialogs[key]){verto.dialogs[key].sendMessage($.verto.enum.message.pvtEvent,data.params);}else if(!list){if(!key){key="UNDEFINED";} +console.error("UNSUBBED or invalid EVENT "+key+" IGNORED");}else{for(var i in list){var sub=list[i];if(!sub||!sub.ready){console.error("invalid EVENT for "+key+" IGNORED");}else if(sub.handler){sub.handler(verto,data.params,sub.userData);}else if(verto.callbacks.onEvent){verto.callbacks.onEvent(verto,data.params,sub.userData);}else{console.log("EVENT:",data.params);}}} +break;case"verto.info":if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.info,data.params.msg);} +console.debug("MESSAGE from: "+data.params.msg.from,data.params.msg.body);break;case'verto.clientReady':if(verto.callbacks.onMessage){verto.callbacks.onMessage(verto,null,$.verto.enum.message.clientReady,data.params);} +console.debug("CLIENT READY",data.params);break;default:console.error("INVALID METHOD OR NON-EXISTANT CALL REFERENCE IGNORED",data.method);break;}}};var del_array=function(array,name){var r=[];var len=array.length;for(var i=0;i=array.length){array.push(name);}else{var x=0;var n=[];var len=array.length;for(var i=0;i":"\n");});return str;};};$.verto.liveArray=function(verto,context,name,config){var la=this;var lastSerno=0;var binding=null;var user_obj=config.userObj;var local=false;hashArray.call(la);la._add=la.add;la._del=la.del;la._reorder=la.reorder;la._clear=la.clear;la.context=context;la.name=name;la.user_obj=user_obj;la.verto=verto;la.broadcast=function(channel,obj){verto.broadcast(channel,obj);};la.errs=0;la.clear=function(){la._clear();lastSerno=0;if(la.onChange){la.onChange(la,{action:"clear"});}};la.checkSerno=function(serno){if(serno<0){return true;} +if(lastSerno>0&&serno!=(lastSerno+1)){if(la.onErr){la.onErr(la,{lastSerno:lastSerno,serno:serno});} +la.errs++;console.debug(la.errs);if(la.errs<3){la.bootstrap(la.user_obj);} +return false;}else{lastSerno=serno;return true;}};la.reorder=function(serno,a){if(la.checkSerno(serno)){la._reorder(a);if(la.onChange){la.onChange(la,{serno:serno,action:"reorder"});}}};la.init=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(la.onChange){la.onChange(la,{serno:serno,action:"init",index:index,key:key,data:val});}}};la.bootObj=function(serno,val){if(la.checkSerno(serno)){for(var i in val){la._add(val[i][0],val[i][1]);} +if(la.onChange){la.onChange(la,{serno:serno,action:"bootObj",data:val,redraw:true});}}};la.add=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){var redraw=la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"add",index:index,key:key,data:val,redraw:redraw});}}};la.modify=function(serno,val,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){la._add(key,val,index);if(la.onChange){la.onChange(la,{serno:serno,action:"modify",key:key,data:val,index:index});}}};la.del=function(serno,key,index){if(key===null||key===undefined){key=serno;} +if(la.checkSerno(serno)){if(index===null||index<0||index===undefined){index=la.indexOf(key);} +var ok=la._del(key);if(ok&&la.onChange){la.onChange(la,{serno:serno,action:"del",key:key,index:index});}}};var eventHandler=function(v,e,la){var packet=e.data;if(packet.name!=la.name){return;} +switch(packet.action){case"init":la.init(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"bootObj":la.bootObj(packet.wireSerno,packet.data);break;case"add":la.add(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);break;case"modify":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.modify(packet.wireSerno,packet.data,packet.hashKey,packet.arrIndex);} +break;case"del":if(!(packet.arrIndex||packet.hashKey)){console.error("Invalid Packet",packet);}else{la.del(packet.wireSerno,packet.hashKey,packet.arrIndex);} +break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,packet.order);break;default:if(la.checkSerno(packet.wireSerno)){if(la.onChange){la.onChange(la,{serno:packet.wireSerno,action:packet.action,data:packet.data});}} +break;}};if(la.context){binding=la.verto.subscribe(la.context,{handler:eventHandler,userData:la,subParams:config.subParams});} +la.destroy=function(){la._clear();la.verto.unsubscribe(binding);};la.sendCommand=function(cmd,obj){var self=la;self.broadcast(self.context,{liveArray:{command:cmd,context:self.context,name:self.name,obj:obj}});};la.bootstrap=function(obj){var self=la;la.sendCommand("bootstrap",obj);};la.changepage=function(obj){var self=la;self.clear();self.broadcast(self.context,{liveArray:{command:"changepage",context:la.context,name:la.name,obj:obj}});};la.heartbeat=function(obj){var self=la;var callback=function(){self.heartbeat.call(self,obj);};self.broadcast(self.context,{liveArray:{command:"heartbeat",context:self.context,name:self.name,obj:obj}});self.hb_pid=setTimeout(callback,30000);};la.bootstrap(la.user_obj);};$.verto.liveTable=function(verto,context,name,jq,config){var dt;var la=new $.verto.liveArray(verto,context,name,{subParams:config.subParams});var lt=this;lt.liveArray=la;lt.dataTable=dt;lt.verto=verto;lt.destroy=function(){if(dt){dt.fnDestroy();} +if(la){la.destroy();} +dt=null;la=null;};la.onErr=function(obj,args){console.error("Error: ",obj,args);};function genRow(data){if(typeof(data[4])==="string"&&data[4].indexOf("{")>-1){var tmp=$.parseJSON(data[4]);data[4]=tmp.oldStatus;data[5]=null;} +return data;} +function genArray(obj){var data=obj.asArray();for(var i in data){data[i]=genRow(data[i]);} +return data;} +la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;} +config.aoColumns=[];for(var i in args.data){config.aoColumns.push({"sTitle":args.data[i]});}} +dt=jq.dataTable(config);} +if(dt&&(args.action=="del"||args.action=="modify")){index=args.index;if(index===undefined&&args.key){index=la.indexOf(args.key);} +if(index===undefined){console.error("INVALID PACKET Missing INDEX\n",args);return;}} +if(config.onChange){config.onChange(obj,args);} +try{switch(args.action){case"bootObj":if(!args.data){console.error("missing data");return;} +dt.fnClearTable();dt.fnAddData(genArray(obj));dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;} +if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(genArray(obj));}else{dt.fnAddData(genRow(args.data));} +dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;} +dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;} +if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.infoChannel,{handler:function(v,e){if(typeof(conf.params.infoCallback)==="function"){conf.params.infoCallback(v,e);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);} +if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);} +if(conf.params.laData.infoChannel){conf.verto.unsubscribe(conf.params.laData.infoChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';} +if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-res-id",parseInt(memberID),"presenter");};$.verto.conf.prototype.videoFloor=function(memberID){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-floor",parseInt(memberID),"force");};$.verto.conf.prototype.banner=function(memberID,text){if(!this.params.hasVid){throw'Conference has no video';} +this.modCommand("vid-banner",parseInt(memberID),escape(text));};$.verto.conf.prototype.volumeDown=function(memberID){this.modCommand("volume_out",parseInt(memberID),"down");};$.verto.conf.prototype.volumeUp=function(memberID){this.modCommand("volume_out",parseInt(memberID),"up");};$.verto.conf.prototype.gainDown=function(memberID){this.modCommand("volume_in",parseInt(memberID),"down");};$.verto.conf.prototype.gainUp=function(memberID){this.modCommand("volume_in",parseInt(memberID),"up");};$.verto.conf.prototype.transfer=function(memberID,exten){this.modCommand("transfer",parseInt(memberID),exten);};$.verto.conf.prototype.sendChat=function(message,type){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};} +$.verto.modfuncs={};$.verto.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;confMan.canvasCount=confMan.params.laData.canvasCount;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="

"+""+""+""+""+ +(confMan.params.hasVid?"":"")+"

";jq.html(html);$.verto.modfuncs.change_video_layout=function(id,canvas_id){var val=$("#"+id+" option:selected").text();if(val!=="none"){confMan.modCommand("vid-layout",null,[val,canvas_id]);}};if(confMan.params.hasVid){for(var j=0;j
"+"Video Layout Canvas "+(j+1)+" "+"

";jq.append(vlhtml);} +$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});} +$("#"+play_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("play",null,file);}});$("#"+stop_id).click(function(){confMan.modCommand("stop",null,"all");});$("#"+recording_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("recording",null,["start",file]);}});$("#"+rec_stop_id).click(function(){confMan.modCommand("recording",null,["stop","all"]);});} +function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var canvas_in_next_id="canvas_in_next_"+x;var canvas_in_prev_id="canvas_in_prev_"+x;var canvas_out_next_id="canvas_out_next_"+x;var canvas_out_prev_id="canvas_out_prev_"+x;var canvas_in_set_id="canvas_in_set_"+x;var canvas_out_set_id="canvas_out_set_"+x;var layer_set_id="layer_set_"+x;var layer_next_id="layer_next_"+x;var layer_prev_id="layer_prev_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var gainup_id="gain_in_up"+x;var gaindn_id="gain_in_dn"+x;var volup_id="vol_in_up"+x;var voldn_id="vol_in_dn"+x;var transfer_id="transfer"+x;var html="
";html+="General Controls
";html+=""+""+""+""+""+""+"";if(confMan.params.hasVid){html+="

Video Controls
";html+=""+""+""+"";if(confMan.canvasCount>1){html+="

Canvas Controls
"+""+""+""+"
"+""+""+"";} +html+="
"+""+""+""+"
";} +jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();} +jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});} +$("#"+gainup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+gaindn_id).click(function(){confMan.modCommand("volume_in",x,"down");});$("#"+volup_id).click(function(){confMan.modCommand("volume_out",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_out",x,"down");});return html;} +var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.infoChannel,{handler:function(v,e){if(typeof(confMan.params.infoCallback)==="function"){confMan.params.infoCallback(v,e);}}});verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready

");}else{$(confMan.params.mainModID).html("");} +verto.subscribe(confMan.params.laData.modChannel,{handler:function(v,e){if(confMan.params.onBroadcast){confMan.params.onBroadcast(verto,confMan,e.data);} +if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;jb)?1:-1));});for(var i in options){$(vlselect_id).append(new Option(options[i],options[i]));x++;}} +if(x){$(vlselect_id).selectmenu('refresh',true);}else{$(vlayout_id).hide();}}}else{if(!confMan.destroyed&&confMan.params.displayID){$(confMan.params.displayID).html(e.data.response+"

");if(confMan.lastTimeout){clearTimeout(confMan.lastTimeout);confMan.lastTimeout=0;} +confMan.lastTimeout=setTimeout(function(){$(confMan.params.displayID).html(confMan.destroyed?"":"Moderator Controls Ready

");},4000);}}}});if(confMan.params.hasVid){confMan.modCommand("list-videoLayouts",null,null);}} +var row_callback=null;if(confMan.params.laData.role==="moderator"){row_callback=function(nRow,aData,iDisplayIndex,iDisplayIndexFull){if(!aData[5]){var $row=$('td:eq(5)',nRow);genControls($row,aData);if(confMan.params.onLaRow){confMan.params.onLaRow(verto,confMan,$row,aData);}}};} +confMan.lt=new $.verto.liveTable(verto,confMan.params.laData.laChannel,confMan.params.laData.laName,$(confMan.params.tableID),{subParams:{callID:confMan.params.dialog?confMan.params.dialog.callID:null},"onChange":function(obj,args){$(confMan.params.statusID).text("Conference Members: "+" ("+obj.arrayLen()+" Total)");if(confMan.params.onLaChange){confMan.params.onLaChange(verto,confMan,$.verto.enum.confEvent.laChange,obj,args);}},"aaData":[],"aoColumns":[{"sTitle":"ID","sWidth":"50"},{"sTitle":"Number","sWidth":"250"},{"sTitle":"Name","sWidth":"250"},{"sTitle":"Codec","sWidth":"100"},{"sTitle":"Status","sWidth":confMan.params.hasVid?"200px":"150px"},{"sTitle":atitle,"sWidth":awidth,}],"bAutoWidth":true,"bDestroy":true,"bSort":false,"bInfo":false,"bFilter":false,"bLengthChange":false,"bPaginate":false,"iDisplayLength":1400,"oLanguage":{"sEmptyTable":"The Conference is Empty....."},"fnRowCallback":row_callback});};$.verto.confMan.prototype.modCommand=function(cmd,id,value){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.confMan.prototype.sendChat=function(message,type){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.chatChannel,"data":{"action":"send","message":message,"type":type}});};$.verto.confMan.prototype.destroy=function(){var confMan=this;confMan.destroyed=true;if(confMan.lt){confMan.lt.destroy();} +if(confMan.params.laData.chatChannel){confMan.verto.unsubscribe(confMan.params.laData.chatChannel);} +if(confMan.params.laData.modChannel){confMan.verto.unsubscribe(confMan.params.laData.modChannel);} +if(confMan.params.mainModID){$(confMan.params.mainModID).html("");}};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,screenShare:false,useCamera:false,useMic:verto.options.deviceParams.useMic,useMicLabel:verto.options.deviceParams.useMicLabel,useSpeak:verto.options.deviceParams.useSpeak,tag:verto.options.tag,localTag:verto.options.localTag,login:verto.options.login,videoParams:verto.options.videoParams,useStream:verto.options.useStream,},params);if(!dialog.params.screenShare){dialog.params.useCamera=verto.options.deviceParams.useCamera;dialog.params.useCameraLabel=verto.options.deviceParams.useCameraLabel;} +dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;dialog.screenShare=params.screenShare||false;dialog.useCamera=dialog.params.useCamera;dialog.useCameraLabel=dialog.params.useCameraLabel;dialog.useMic=dialog.params.useMic;dialog.useMicLabel=dialog.params.useMicLabel;dialog.useSpeak=dialog.params.useSpeak;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();} +if(typeof(dialog.params.tag)==="function"){dialog.params.tag=dialog.params.tag();} +if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}} +if(dialog.params.localTag){dialog.localVideo=document.getElementById(dialog.params.localTag);} +dialog.verto.dialogs[dialog.callID]=dialog;var RTCcallbacks={};if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.params.display_direction==="outbound"){dialog.params.remote_caller_id_name=dialog.params.caller_id_name;dialog.params.remote_caller_id_number=dialog.params.caller_id_number;}else{dialog.params.remote_caller_id_name=dialog.params.callee_id_name;dialog.params.remote_caller_id_number=dialog.params.callee_id_number;} +if(!dialog.params.remote_caller_id_name){dialog.params.remote_caller_id_name="Nobody";} +if(!dialog.params.remote_caller_id_number){dialog.params.remote_caller_id_number="UNKNOWN";} +RTCcallbacks.onMessage=function(rtc,msg){console.debug(msg);};RTCcallbacks.onAnswerSDP=function(rtc,sdp){console.error("answer sdp",sdp);};}else{dialog.params.remote_caller_id_name="Outbound Call";dialog.params.remote_caller_id_number=dialog.params.destination_number;} +RTCcallbacks.onICESDP=function(rtc){console.log("RECV "+rtc.type+" SDP",rtc.mediaData.SDP);if(dialog.state==$.verto.enum.state.requesting||dialog.state==$.verto.enum.state.answering||dialog.state==$.verto.enum.state.active){location.reload();return;} +if(rtc.type=="offer"){if(dialog.state==$.verto.enum.state.active){dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.attach",{sdp:rtc.mediaData.SDP});}else{dialog.setState($.verto.enum.state.requesting);dialog.sendMethod("verto.invite",{sdp:rtc.mediaData.SDP});}}else{dialog.setState($.verto.enum.state.answering);dialog.sendMethod(dialog.attach?"verto.attach":"verto.answer",{sdp:dialog.rtc.mediaData.SDP});}};RTCcallbacks.onICE=function(rtc){if(rtc.type=="offer"){console.log("offer",rtc.mediaData.candidate);return;}};RTCcallbacks.onStream=function(rtc,stream){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onGranted==='function'){dialog.callbacks.permissionCallback.onGranted(stream);} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onGranted==='function'){dialog.verto.options.permissionCallback.onGranted(stream);} +console.log("stream started");};RTCcallbacks.onRemoteStream=function(rtc,stream){if(typeof dialog.callbacks.onRemoteStream==='function'){dialog.callbacks.onRemoteStream(stream,dialog);} +console.log("remote stream started");};RTCcallbacks.onError=function(e){if(dialog.callbacks.permissionCallback&&typeof dialog.callbacks.permissionCallback.onDenied==='function'){dialog.callbacks.permissionCallback.onDenied();} +else if(dialog.verto.options.permissionCallback&&typeof dialog.verto.options.permissionCallback.onDenied==='function'){dialog.verto.options.permissionCallback.onDenied();} +console.error("ERROR:",e);dialog.hangup({cause:"Device or Permission Error"});};dialog.rtc=new $.FSRTC({callbacks:RTCcallbacks,localVideo:dialog.screenShare?null:dialog.localVideo,useVideo:dialog.params.useVideo?dialog.videoStream:null,useAudio:dialog.audioStream,useStereo:dialog.params.useStereo,videoParams:dialog.params.videoParams,audioParams:verto.options.audioParams,iceServers:verto.options.iceServers,screenShare:dialog.screenShare,useCamera:dialog.useCamera,useCameraLabel:dialog.useCameraLabel,useMic:dialog.useMic,useMicLabel:dialog.useMicLabel,useSpeak:dialog.useSpeak,turnServer:verto.options.turnServer,useStream:dialog.params.useStream});dialog.rtc.verto=dialog.verto;if(dialog.direction==$.verto.enum.direction.inbound){if(dialog.attach){dialog.answer();}else{dialog.ring();}}};$.verto.dialog.prototype.invite=function(){var dialog=this;dialog.rtc.call();};$.verto.dialog.prototype.sendMethod=function(method,obj){var dialog=this;obj.dialogParams={};for(var i in dialog.params){if(i=="sdp"&&method!="verto.invite"&&method!="verto.attach"){continue;} +if((obj.noDialogParams&&i!="callID")){continue;} +obj.dialogParams[i]=dialog.params[i];} +delete obj.noDialogParams;dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,true,e);},function(e){dialog.processReply(method,false,e);});};function checkStateChange(oldS,newS){if(newS==$.verto.enum.state.purge||$.verto.enum.states[oldS.name][newS.name]){return true;} +return false;} +function find_name(id){for(var i in $.verto.audioOutDevices){var source=$.verto.audioOutDevices[i];if(source.id===id){return(source.label);}} +return id;} +$.verto.dialog.prototype.setAudioPlaybackDevice=function(sinkId,callback,arg){var dialog=this;var element=dialog.audioStream;if(typeof element.sinkId!=='undefined'){var devname=find_name(sinkId);console.info("Dialog: "+dialog.callID+" Setting speaker:",element,devname);element.setSinkId(sinkId).then(function(){console.log("Dialog: "+dialog.callID+' Success, audio output device attached: '+sinkId);if(callback){callback(true,devname,arg);}}).catch(function(error){var errorMessage=error;if(error.name==='SecurityError'){errorMessage="Dialog: "+dialog.callID+' You need to use HTTPS for selecting audio output '+'device: '+error;} +if(callback){callback(false,null,arg);} +console.error(errorMessage);});}else{console.warn("Dialog: "+dialog.callID+' Browser does not support output device selection.');if(callback){callback(false,null,arg);}}} +$.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();} +if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;} +console.log("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(dialog.callbacks.onDialogState){dialog.callbacks.onDialogState(this);} +switch(dialog.state){case $.verto.enum.state.early:case $.verto.enum.state.active:var speaker=dialog.useSpeak;console.info("Using Speaker: ",speaker);if(speaker&&speaker!=="any"&&speaker!=="none"){setTimeout(function(){dialog.setAudioPlaybackDevice(speaker);},500);} +break;case $.verto.enum.state.trying:setTimeout(function(){if(dialog.state==$.verto.enum.state.trying){dialog.setState($.verto.enum.state.hangup);}},30000);break;case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});} +dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:if(typeof(dialog.verto.options.tag)==="function"){$('#'+dialog.params.tag).remove();} +delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();} +break;} +return true;};$.verto.dialog.prototype.processReply=function(method,success,e){var dialog=this;switch(method){case"verto.answer":case"verto.attach":if(success){dialog.setState($.verto.enum.state.active);}else{dialog.hangup();} +break;case"verto.invite":if(success){dialog.setState($.verto.enum.state.trying);}else{dialog.setState($.verto.enum.state.destroy);} +break;case"verto.bye":dialog.hangup();break;case"verto.modify":if(e.holdState){if(e.holdState=="held"){if(dialog.state!=$.verto.enum.state.held){dialog.setState($.verto.enum.state.held);}}else if(e.holdState=="active"){if(dialog.state!=$.verto.enum.state.active){dialog.setState($.verto.enum.state.active);}}} +if(success){} +break;default:break;}};$.verto.dialog.prototype.hangup=function(params){var dialog=this;if(params){if(params.causeCode){dialog.causeCode=params.causeCode;} +if(params.cause){dialog.cause=params.cause;}} +if(!dialog.cause&&!dialog.causeCode){dialog.cause="NORMAL_CLEARING";} +if(dialog.state.val>=$.verto.enum.state.new.val&&dialog.state.val<$.verto.enum.state.hangup.val){dialog.setState($.verto.enum.state.hangup);}else if(dialog.state.val<$.verto.enum.state.destroy){dialog.setState($.verto.enum.state.destroy);}};$.verto.dialog.prototype.stopRinging=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.stop();}};$.verto.dialog.prototype.indicateRing=function(){var dialog=this;if(dialog.verto.ringer){dialog.verto.ringer.attr("src",dialog.verto.options.ringFile)[0].play();setTimeout(function(){dialog.stopRinging();if(dialog.state==$.verto.enum.state.ringing){dialog.indicateRing();}},dialog.verto.options.ringSleep);}};$.verto.dialog.prototype.ring=function(){var dialog=this;dialog.setState($.verto.enum.state.ringing);dialog.indicateRing();};$.verto.dialog.prototype.useVideo=function(on){var dialog=this;dialog.params.useVideo=on;if(on){dialog.videoStream=dialog.audioStream;}else{dialog.videoStream=null;} +dialog.rtc.useVideo(dialog.videoStream,dialog.localVideo);};$.verto.dialog.prototype.setMute=function(what){var dialog=this;return dialog.rtc.setMute(what);};$.verto.dialog.prototype.getMute=function(){var dialog=this;return dialog.rtc.getMute();};$.verto.dialog.prototype.setVideoMute=function(what){var dialog=this;return dialog.rtc.setVideoMute(what);};$.verto.dialog.prototype.getVideoMute=function(){var dialog=this;return dialog.rtc.getVideoMute();};$.verto.dialog.prototype.useStereo=function(on){var dialog=this;dialog.params.useStereo=on;dialog.rtc.useStereo(on);};$.verto.dialog.prototype.dtmf=function(digits){var dialog=this;if(digits){dialog.sendMethod("verto.info",{dtmf:digits});}};$.verto.dialog.prototype.rtt=function(obj){var dialog=this;var pobj={};if(!obj){return false;} +pobj.code=obj.code;pobj.chars=obj.chars;if(pobj.chars||pobj.code){dialog.sendMethod("verto.info",{txt:obj,noDialogParams:true});}};$.verto.dialog.prototype.transfer=function(dest,params){var dialog=this;if(dest){dialog.sendMethod("verto.modify",{action:"transfer",destination:dest,params:params});}};$.verto.dialog.prototype.replace=function(replaceCallID,params){var dialog=this;if(replaceCallID){dialog.sendMethod("verto.modify",{action:"replace",replaceCallID:replaceCallID,params:params});}};$.verto.dialog.prototype.hold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"hold",params:params});};$.verto.dialog.prototype.unhold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"unhold",params:params});};$.verto.dialog.prototype.toggleHold=function(params){var dialog=this;dialog.sendMethod("verto.modify",{action:"toggleHold",params:params});};$.verto.dialog.prototype.message=function(msg){var dialog=this;var err=0;msg.from=dialog.params.login;if(!msg.to){console.error("Missing To");err++;} +if(!msg.body){console.error("Missing Body");err++;} +if(err){return false;} +dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(!params){params={};} +params.sdp=dialog.params.sdp;if(params){if(params.useVideo){dialog.useVideo(true);} +dialog.params.callee_id_name=params.callee_id_name;dialog.params.callee_id_number=params.callee_id_number;if(params.useCamera){dialog.useCamera=params.useCamera;dialog.useCameraLabel=params.useCameraLabel;} +if(params.useMic){dialog.useMic=params.useMic;dialog.useMic=params.useMicLabel;} +if(params.useSpeak){dialog.useSpeak=params.useSpeak;}} +dialog.rtc.createAnswer(params);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(params){var dialog=this;dialog.gotAnswer=true;if(dialog.state.val>=$.verto.enum.state.active.val){return;} +if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{if(dialog.gotEarly){console.log("Dialog "+dialog.callID+" Got answer while still establishing early media, delaying...");}else{console.log("Dialog "+dialog.callID+" Answering Channel");dialog.rtc.answer(params.sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"ANSWER SDP",params.sdp);}}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" <":" <")+dialog.params.remote_caller_id_number+(enc?">":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;} +if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;} +dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(params){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;} +dialog.gotEarly=true;dialog.rtc.answer(params.sdp,function(){console.log("Dialog "+dialog.callID+"Establishing early media");dialog.setState($.verto.enum.state.early);if(dialog.gotAnswer){console.log("Dialog "+dialog.callID+"Answering Channel");dialog.setState($.verto.enum.state.active);}},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"EARLY SDP",params.sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,recovering:1,ringing:1,destroy:1,answering:1,hangup:1},requesting:{trying:1,hangup:1,active:1},recovering:{answering:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{answering:1,requesting:1,hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent clientReady");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$.verto.unloadJobs=[];var unloadEventName='beforeunload';var iOS=['iPad','iPhone','iPod'].indexOf(navigator.platform)>=0;if(iOS){unloadEventName='pagehide';} +$(window).bind(unloadEventName,function(){for(var f in $.verto.unloadJobs){$.verto.unloadJobs[f]();} +if($.verto.haltClosure) +return $.verto.haltClosure();for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.purge();verto.logout();}} +return $.verto.warnOnUnload;});$.verto.videoDevices=[];$.verto.audioInDevices=[];$.verto.audioOutDevices=[];var checkDevices=function(runtime){console.info("enumerating devices");var aud_in=[],aud_out=[],vid=[];var has_video=0,has_audio=0;var Xstream;function gotDevices(deviceInfos){for(var i=0;i!==deviceInfos.length;++i){var deviceInfo=deviceInfos[i];var text="";console.log(deviceInfo);console.log(deviceInfo.kind+": "+deviceInfo.label+" id = "+deviceInfo.deviceId);if(deviceInfo.kind==='audioinput'){text=deviceInfo.label||'microphone '+(aud_in.length+1);aud_in.push({id:deviceInfo.deviceId,kind:"audio_in",label:text});}else if(deviceInfo.kind==='audiooutput'){text=deviceInfo.label||'speaker '+(aud_out.length+1);aud_out.push({id:deviceInfo.deviceId,kind:"audio_out",label:text});}else if(deviceInfo.kind==='videoinput'){text=deviceInfo.label||'camera '+(vid.length+1);vid.push({id:deviceInfo.deviceId,kind:"video",label:text});}else{console.log('Some other kind of source/device: ',deviceInfo);}} +$.verto.videoDevices=vid;$.verto.audioInDevices=aud_in;$.verto.audioOutDevices=aud_out;console.info("Audio IN Devices",$.verto.audioInDevices);console.info("Audio Out Devices",$.verto.audioOutDevices);console.info("Video Devices",$.verto.videoDevices);if(Xstream){Xstream.getTracks().forEach(function(track){track.stop();});} +if(runtime){runtime(true);}} +function handleError(error){console.log('device enumeration error: ',error);if(runtime)runtime(false);} +function checkTypes(devs){for(var i=0;i!==devs.length;++i){if(devs[i].kind==='audioinput'){has_audio++;}else if(devs[i].kind==='videoinput'){has_video++;}} +navigator.getUserMedia({audio:(has_audio>0?true:false),video:(has_video>0?true:false)},function(stream){Xstream=stream;navigator.mediaDevices.enumerateDevices().then(gotDevices).catch(handleError);},function(err){console.log("The following error occurred: "+err.name);});} +navigator.mediaDevices.enumerateDevices().then(checkTypes).catch(handleError);};$.verto.refreshDevices=function(runtime){checkDevices(runtime);} +$.verto.init=function(obj,runtime){if(!obj){obj={};} +if(!obj.skipPermCheck&&!obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){checkDevices(runtime);},true,true);}else if(obj.skipPermCheck&&!obj.skipDeviceCheck){checkDevices(runtime);}else if(!obj.skipPermCheck&&obj.skipDeviceCheck){$.FSRTC.checkPerms(function(status){runtime(status);},true,true);}else{runtime(null);}} +$.verto.genUUID=function(){return generateGUID();}})(jQuery);(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g.adapter=f()}})(function(){var define,module,exports;return(function(){function r(e,n,t){function o(i,f){if(!n[i]){if(!e[i]){var c="function"==typeof require&&require;if(!f&&c)return c(i,!0);if(u)return u(i,!0);var a=new Error("Cannot find module '"+i+"'");throw a.code="MODULE_NOT_FOUND",a}var p=n[i]={exports:{}};e[i][0].call(p.exports,function(r){var n=e[i][1][r];return o(n||r)},p,p.exports,r,e,n,t)}return n[i].exports}for(var u="function"==typeof require&&require,i=0;i0&&arguments[0]!==undefined?arguments[0]:{},window=_ref.window;var options=arguments.length>1&&arguments[1]!==undefined?arguments[1]:{shimChrome:true,shimFirefox:true,shimEdge:true,shimSafari:true};var logging=utils.log;var browserDetails=utils.detectBrowser(window);var adapter={browserDetails:browserDetails,commonShim:commonShim,extractVersion:utils.extractVersion,disableLog:utils.disableLog,disableWarnings:utils.disableWarnings};switch(browserDetails.browser){case'chrome':if(!chromeShim||!chromeShim.shimPeerConnection||!options.shimChrome){logging('Chrome shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming chrome.');adapter.browserShim=chromeShim;chromeShim.shimGetUserMedia(window);chromeShim.shimMediaStream(window);chromeShim.shimPeerConnection(window);chromeShim.shimOnTrack(window);chromeShim.shimAddTrackRemoveTrack(window);chromeShim.shimGetSendersWithDtmf(window);chromeShim.shimSenderReceiverGetStats(window);chromeShim.fixNegotiationNeeded(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;case'firefox':if(!firefoxShim||!firefoxShim.shimPeerConnection||!options.shimFirefox){logging('Firefox shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming firefox.');adapter.browserShim=firefoxShim;firefoxShim.shimGetUserMedia(window);firefoxShim.shimPeerConnection(window);firefoxShim.shimOnTrack(window);firefoxShim.shimRemoveStream(window);firefoxShim.shimSenderGetStats(window);firefoxShim.shimReceiverGetStats(window);firefoxShim.shimRTCDataChannel(window);commonShim.shimRTCIceCandidate(window);commonShim.shimConnectionState(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'edge':if(!edgeShim||!edgeShim.shimPeerConnection||!options.shimEdge){logging('MS edge shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming edge.');adapter.browserShim=edgeShim;edgeShim.shimGetUserMedia(window);edgeShim.shimGetDisplayMedia(window);edgeShim.shimPeerConnection(window);edgeShim.shimReplaceTrack(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);break;case'safari':if(!safariShim||!options.shimSafari){logging('Safari shim is not included in this adapter release.');return adapter;} +logging('adapter.js shimming safari.');adapter.browserShim=safariShim;safariShim.shimRTCIceServerUrls(window);safariShim.shimCreateOfferLegacy(window);safariShim.shimCallbacksAPI(window);safariShim.shimLocalStreamsAPI(window);safariShim.shimRemoteStreamsAPI(window);safariShim.shimTrackEventTransceiver(window);safariShim.shimGetUserMedia(window);commonShim.shimRTCIceCandidate(window);commonShim.shimMaxMessageSize(window);commonShim.shimSendThrowTypeError(window);commonShim.removeAllowExtmapMixed(window);break;default:logging('Unsupported browser!');break;} +return adapter;}},{"./chrome/chrome_shim":3,"./common_shim":6,"./edge/edge_shim":7,"./firefox/firefox_shim":11,"./safari/safari_shim":14,"./utils":15}],3:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimMediaStream=shimMediaStream;exports.shimOnTrack=shimOnTrack;exports.shimGetSendersWithDtmf=shimGetSendersWithDtmf;exports.shimSenderReceiverGetStats=shimSenderReceiverGetStats;exports.shimAddTrackRemoveTrackWithNative=shimAddTrackRemoveTrackWithNative;exports.shimAddTrackRemoveTrack=shimAddTrackRemoveTrack;exports.shimPeerConnection=shimPeerConnection;exports.fixNegotiationNeeded=fixNegotiationNeeded;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function walkStats(stats,base,resultSet){if(!base||resultSet.has(base.id)){return;} +resultSet.set(base.id,base);Object.keys(base).forEach(function(name){if(name.endsWith('Id')){walkStats(stats,stats.get(base[name]),resultSet);}else if(name.endsWith('Ids')){base[name].forEach(function(id){walkStats(stats,stats.get(id),resultSet);});}});} +function filterStats(result,track,outbound){var streamStatsType=outbound?'outbound-rtp':'inbound-rtp';var filteredResult=new Map();if(track===null){return filteredResult;} +var trackStats=[];result.forEach(function(value){if(value.type==='track'&&value.trackIdentifier===track.id){trackStats.push(value);}});trackStats.forEach(function(trackStat){result.forEach(function(stats){if(stats.type===streamStatsType&&stats.trackId===trackStat.id){walkStats(result,stats,filteredResult);}});});return filteredResult;} +function shimMediaStream(window){window.MediaStream=window.MediaStream||window.webkitMediaStream;} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('ontrack'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'ontrack',{get:function get(){return this._ontrack;},set:function set(f){if(this._ontrack){this.removeEventListener('track',this._ontrack);} +this.addEventListener('track',this._ontrack=f);},enumerable:true,configurable:true});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var _this=this;if(!this._ontrackpoly){this._ontrackpoly=function(e){e.stream.addEventListener('addtrack',function(te){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===te.track.id;});}else{receiver={track:te.track};} +var event=new Event('track');event.track=te.track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});e.stream.getTracks().forEach(function(track){var receiver=void 0;if(window.RTCPeerConnection.prototype.getReceivers){receiver=_this.getReceivers().find(function(r){return r.track&&r.track.id===track.id;});}else{receiver={track:track};} +var event=new Event('track');event.track=track;event.receiver=receiver;event.transceiver={receiver:receiver};event.streams=[e.stream];_this.dispatchEvent(event);});};this.addEventListener('addstream',this._ontrackpoly);} +return origSetRemoteDescription.apply(this,arguments);};}else{utils.wrapPeerConnectionEvent(window,'track',function(e){if(!e.transceiver){Object.defineProperty(e,'transceiver',{value:{receiver:e.receiver}});} +return e;});}} +function shimGetSendersWithDtmf(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&!('getSenders'in window.RTCPeerConnection.prototype)&&'createDTMFSender'in window.RTCPeerConnection.prototype){var shimSenderWithDtmf=function shimSenderWithDtmf(pc,track){return{track:track,get dtmf(){if(this._dtmf===undefined){if(track.kind==='audio'){this._dtmf=pc.createDTMFSender(track);}else{this._dtmf=null;}} +return this._dtmf;},_pc:pc};};if(!window.RTCPeerConnection.prototype.getSenders){window.RTCPeerConnection.prototype.getSenders=function(){this._senders=this._senders||[];return this._senders.slice();};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){var sender=origAddTrack.apply(this,arguments);if(!sender){sender=shimSenderWithDtmf(this,track);this._senders.push(sender);} +return sender;};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){origRemoveTrack.apply(this,arguments);var idx=this._senders.indexOf(sender);if(idx!==-1){this._senders.splice(idx,1);}};} +var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this2=this;this._senders=this._senders||[];origAddStream.apply(this,[stream]);stream.getTracks().forEach(function(track){_this2._senders.push(shimSenderWithDtmf(_this2,track));});};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;this._senders=this._senders||[];origRemoveStream.apply(this,[stream]);stream.getTracks().forEach(function(track){var sender=_this3._senders.find(function(s){return s.track===track;});if(sender){_this3._senders.splice(_this3._senders.indexOf(sender),1);}});};}else if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&'getSenders'in window.RTCPeerConnection.prototype&&'createDTMFSender'in window.RTCPeerConnection.prototype&&window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;window.RTCPeerConnection.prototype.getSenders=function(){var _this4=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this4;});return senders;};Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=this._pc.createDTMFSender(this.track);}else{this._dtmf=null;}} +return this._dtmf;}});}} +function shimSenderReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender&&window.RTCRtpReceiver)){return;} +if(!('getStats'in window.RTCRtpSender.prototype)){var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this5=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this5;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){var sender=this;return this._pc.getStats().then(function(result){return(filterStats(result,sender.track,true));});};} +if(!('getStats'in window.RTCRtpReceiver.prototype)){var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this6=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this6;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){var receiver=this;return this._pc.getStats().then(function(result){return filterStats(result,receiver.track,false);});};} +if(!('getStats'in window.RTCRtpSender.prototype&&'getStats'in window.RTCRtpReceiver.prototype)){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(){if(arguments.length>0&&arguments[0]instanceof window.MediaStreamTrack){var track=arguments[0];var sender=void 0;var receiver=void 0;var err=void 0;this.getSenders().forEach(function(s){if(s.track===track){if(sender){err=true;}else{sender=s;}}});this.getReceivers().forEach(function(r){if(r.track===track){if(receiver){err=true;}else{receiver=r;}} +return r.track===track;});if(err||sender&&receiver){return Promise.reject(new DOMException('There are more than one sender or receiver for the track.','InvalidAccessError'));}else if(sender){return sender.getStats();}else if(receiver){return receiver.getStats();} +return Promise.reject(new DOMException('There is no sender or receiver for the track.','InvalidAccessError'));} +return origGetStats.apply(this,arguments);};} +function shimAddTrackRemoveTrackWithNative(window){window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this7=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};return Object.keys(this._shimmedLocalStreams).map(function(streamId){return _this7._shimmedLocalStreams[streamId][0];});};var origAddTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(!stream){return origAddTrack.apply(this,arguments);} +this._shimmedLocalStreams=this._shimmedLocalStreams||{};var sender=origAddTrack.apply(this,arguments);if(!this._shimmedLocalStreams[stream.id]){this._shimmedLocalStreams[stream.id]=[stream,sender];}else if(this._shimmedLocalStreams[stream.id].indexOf(sender)===-1){this._shimmedLocalStreams[stream.id].push(sender);} +return sender;};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this8=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this8.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});var existingSenders=this.getSenders();origAddStream.apply(this,arguments);var newSenders=this.getSenders().filter(function(newSender){return existingSenders.indexOf(newSender)===-1;});this._shimmedLocalStreams[stream.id]=[stream].concat(newSenders);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._shimmedLocalStreams=this._shimmedLocalStreams||{};delete this._shimmedLocalStreams[stream.id];return origRemoveStream.apply(this,arguments);};var origRemoveTrack=window.RTCPeerConnection.prototype.removeTrack;window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this9=this;this._shimmedLocalStreams=this._shimmedLocalStreams||{};if(sender){Object.keys(this._shimmedLocalStreams).forEach(function(streamId){var idx=_this9._shimmedLocalStreams[streamId].indexOf(sender);if(idx!==-1){_this9._shimmedLocalStreams[streamId].splice(idx,1);} +if(_this9._shimmedLocalStreams[streamId].length===1){delete _this9._shimmedLocalStreams[streamId];}});} +return origRemoveTrack.apply(this,arguments);};} +function shimAddTrackRemoveTrack(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(window.RTCPeerConnection.prototype.addTrack&&browserDetails.version>=65){return shimAddTrackRemoveTrackWithNative(window);} +var origGetLocalStreams=window.RTCPeerConnection.prototype.getLocalStreams;window.RTCPeerConnection.prototype.getLocalStreams=function(){var _this10=this;var nativeStreams=origGetLocalStreams.apply(this);this._reverseStreams=this._reverseStreams||{};return nativeStreams.map(function(stream){return _this10._reverseStreams[stream.id];});};var origAddStream=window.RTCPeerConnection.prototype.addStream;window.RTCPeerConnection.prototype.addStream=function(stream){var _this11=this;this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};stream.getTracks().forEach(function(track){var alreadyExists=_this11.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');}});if(!this._reverseStreams[stream.id]){var newStream=new window.MediaStream(stream.getTracks());this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;stream=newStream;} +origAddStream.apply(this,[stream]);};var origRemoveStream=window.RTCPeerConnection.prototype.removeStream;window.RTCPeerConnection.prototype.removeStream=function(stream){this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};origRemoveStream.apply(this,[this._streams[stream.id]||stream]);delete this._reverseStreams[this._streams[stream.id]?this._streams[stream.id].id:stream.id];delete this._streams[stream.id];};window.RTCPeerConnection.prototype.addTrack=function(track,stream){var _this12=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +var streams=[].slice.call(arguments,1);if(streams.length!==1||!streams[0].getTracks().find(function(t){return t===track;})){throw new DOMException('The adapter.js addTrack polyfill only supports a single '+' stream which is associated with the specified track.','NotSupportedError');} +var alreadyExists=this.getSenders().find(function(s){return s.track===track;});if(alreadyExists){throw new DOMException('Track already exists.','InvalidAccessError');} +this._streams=this._streams||{};this._reverseStreams=this._reverseStreams||{};var oldStream=this._streams[stream.id];if(oldStream){oldStream.addTrack(track);Promise.resolve().then(function(){_this12.dispatchEvent(new Event('negotiationneeded'));});}else{var newStream=new window.MediaStream([track]);this._streams[stream.id]=newStream;this._reverseStreams[newStream.id]=stream;this.addStream(newStream);} +return this.getSenders().find(function(s){return s.track===track;});};function replaceInternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(internalStream.id,'g'),externalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +function replaceExternalStreamId(pc,description){var sdp=description.sdp;Object.keys(pc._reverseStreams||[]).forEach(function(internalId){var externalStream=pc._reverseStreams[internalId];var internalStream=pc._streams[externalStream.id];sdp=sdp.replace(new RegExp(externalStream.id,'g'),internalStream.id);});return new RTCSessionDescription({type:description.type,sdp:sdp});} +['createOffer','createAnswer'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){var _this13=this;var args=arguments;var isLegacyCall=arguments.length&&typeof arguments[0]==='function';if(isLegacyCall){return nativeMethod.apply(this,[function(description){var desc=replaceInternalStreamId(_this13,description);args[0].apply(null,[desc]);},function(err){if(args[1]){args[1].apply(null,err);}},arguments[2]]);} +return nativeMethod.apply(this,arguments).then(function(description){return replaceInternalStreamId(_this13,description);});};});var origSetLocalDescription=window.RTCPeerConnection.prototype.setLocalDescription;window.RTCPeerConnection.prototype.setLocalDescription=function(){if(!arguments.length||!arguments[0].type){return origSetLocalDescription.apply(this,arguments);} +arguments[0]=replaceExternalStreamId(this,arguments[0]);return origSetLocalDescription.apply(this,arguments);};var origLocalDescription=Object.getOwnPropertyDescriptor(window.RTCPeerConnection.prototype,'localDescription');Object.defineProperty(window.RTCPeerConnection.prototype,'localDescription',{get:function get(){var description=origLocalDescription.get.apply(this);if(description.type===''){return description;} +return replaceInternalStreamId(this,description);}});window.RTCPeerConnection.prototype.removeTrack=function(sender){var _this14=this;if(this.signalingState==='closed'){throw new DOMException('The RTCPeerConnection\'s signalingState is \'closed\'.','InvalidStateError');} +if(!sender._pc){throw new DOMException('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.','TypeError');} +var isLocal=sender._pc===this;if(!isLocal){throw new DOMException('Sender was not created by this connection.','InvalidAccessError');} +this._streams=this._streams||{};var stream=void 0;Object.keys(this._streams).forEach(function(streamid){var hasTrack=_this14._streams[streamid].getTracks().find(function(track){return sender.track===track;});if(hasTrack){stream=_this14._streams[streamid];}});if(stream){if(stream.getTracks().length===1){this.removeStream(this._reverseStreams[stream.id]);}else{stream.removeTrack(sender.track);} +this.dispatchEvent(new Event('negotiationneeded'));}};} +function shimPeerConnection(window){if(!window.RTCPeerConnection&&window.webkitRTCPeerConnection){window.RTCPeerConnection=window.webkitRTCPeerConnection;} +if(!window.RTCPeerConnection){return;} +var origGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,successCallback,errorCallback){var _this15=this;var args=arguments;if(arguments.length>0&&typeof selector==='function'){return origGetStats.apply(this,arguments);} +if(origGetStats.length===0&&(arguments.length===0||typeof arguments[0]!=='function')){return origGetStats.apply(this,[]);} +var fixChromeStats_=function fixChromeStats_(response){var standardReport={};var reports=response.result();reports.forEach(function(report){var standardStats={id:report.id,timestamp:report.timestamp,type:{localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[report.type]||report.type};report.names().forEach(function(name){standardStats[name]=report.stat(name);});standardReport[standardStats.id]=standardStats;});return standardReport;};var makeMapStats=function makeMapStats(stats){return new Map(Object.keys(stats).map(function(key){return[key,stats[key]];}));};if(arguments.length>=2){var successCallbackWrapper_=function successCallbackWrapper_(response){args[1](makeMapStats(fixChromeStats_(response)));};return origGetStats.apply(this,[successCallbackWrapper_,arguments[0]]);} +return new Promise(function(resolve,reject){origGetStats.apply(_this15,[function(response){resolve(makeMapStats(fixChromeStats_(response)));},reject]);}).then(successCallback,errorCallback);};['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};} +function fixNegotiationNeeded(window){utils.wrapPeerConnectionEvent(window,'negotiationneeded',function(e){var pc=e.target;if(pc.signalingState!=='stable'){return;} +return e;});}},{"../utils.js":15,"./getdisplaymedia":4,"./getusermedia":5}],4:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,getSourceId){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +if(typeof getSourceId!=='function'){console.error('shimGetDisplayMedia: getSourceId argument is not '+'a function');return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){return getSourceId(constraints).then(function(sourceId){var widthSpecified=constraints.video&&constraints.video.width;var heightSpecified=constraints.video&&constraints.video.height;var frameRateSpecified=constraints.video&&constraints.video.frameRate;constraints.video={mandatory:{chromeMediaSource:'desktop',chromeMediaSourceId:sourceId,maxFrameRate:frameRateSpecified||3}};if(widthSpecified){constraints.video.mandatory.maxWidth=widthSpecified;} +if(heightSpecified){constraints.video.mandatory.maxHeight=heightSpecified;} +return window.navigator.mediaDevices.getUserMedia(constraints);});};}},{}],5:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils.js');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +var logging=utils.log;function shimGetUserMedia(window){var navigator=window&&window.navigator;if(!navigator.mediaDevices){return;} +var browserDetails=utils.detectBrowser(window);var constraintsToChrome_=function constraintsToChrome_(c){if((typeof c==='undefined'?'undefined':_typeof(c))!=='object'||c.mandatory||c.optional){return c;} +var cc={};Object.keys(c).forEach(function(key){if(key==='require'||key==='advanced'||key==='mediaSource'){return;} +var r=_typeof(c[key])==='object'?c[key]:{ideal:c[key]};if(r.exact!==undefined&&typeof r.exact==='number'){r.min=r.max=r.exact;} +var oldname_=function oldname_(prefix,name){if(prefix){return prefix+name.charAt(0).toUpperCase()+name.slice(1);} +return name==='deviceId'?'sourceId':name;};if(r.ideal!==undefined){cc.optional=cc.optional||[];var oc={};if(typeof r.ideal==='number'){oc[oldname_('min',key)]=r.ideal;cc.optional.push(oc);oc={};oc[oldname_('max',key)]=r.ideal;cc.optional.push(oc);}else{oc[oldname_('',key)]=r.ideal;cc.optional.push(oc);}} +if(r.exact!==undefined&&typeof r.exact!=='number'){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_('',key)]=r.exact;}else{['min','max'].forEach(function(mix){if(r[mix]!==undefined){cc.mandatory=cc.mandatory||{};cc.mandatory[oldname_(mix,key)]=r[mix];}});}});if(c.advanced){cc.optional=(cc.optional||[]).concat(c.advanced);} +return cc;};var shimConstraints_=function shimConstraints_(constraints,func){if(browserDetails.version>=61){return func(constraints);} +constraints=JSON.parse(JSON.stringify(constraints));if(constraints&&_typeof(constraints.audio)==='object'){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};constraints=JSON.parse(JSON.stringify(constraints));remap(constraints.audio,'autoGainControl','googAutoGainControl');remap(constraints.audio,'noiseSuppression','googNoiseSuppression');constraints.audio=constraintsToChrome_(constraints.audio);} +if(constraints&&_typeof(constraints.video)==='object'){var face=constraints.video.facingMode;face=face&&((typeof face==='undefined'?'undefined':_typeof(face))==='object'?face:{ideal:face});var getSupportedFacingModeLies=browserDetails.version<66;if(face&&(face.exact==='user'||face.exact==='environment'||face.ideal==='user'||face.ideal==='environment')&&!(navigator.mediaDevices.getSupportedConstraints&&navigator.mediaDevices.getSupportedConstraints().facingMode&&!getSupportedFacingModeLies)){delete constraints.video.facingMode;var matches=void 0;if(face.exact==='environment'||face.ideal==='environment'){matches=['back','rear'];}else if(face.exact==='user'||face.ideal==='user'){matches=['front'];} +if(matches){return navigator.mediaDevices.enumerateDevices().then(function(devices){devices=devices.filter(function(d){return d.kind==='videoinput';});var dev=devices.find(function(d){return matches.some(function(match){return d.label.toLowerCase().includes(match);});});if(!dev&&devices.length&&matches.includes('back')){dev=devices[devices.length-1];} +if(dev){constraints.video.deviceId=face.exact?{exact:dev.deviceId}:{ideal:dev.deviceId};} +constraints.video=constraintsToChrome_(constraints.video);logging('chrome: '+JSON.stringify(constraints));return func(constraints);});}} +constraints.video=constraintsToChrome_(constraints.video);} +logging('chrome: '+JSON.stringify(constraints));return func(constraints);};var shimError_=function shimError_(e){if(browserDetails.version>=64){return e;} +return{name:{PermissionDeniedError:'NotAllowedError',PermissionDismissedError:'NotAllowedError',InvalidStateError:'NotAllowedError',DevicesNotFoundError:'NotFoundError',ConstraintNotSatisfiedError:'OverconstrainedError',TrackStartError:'NotReadableError',MediaDeviceFailedDueToShutdown:'NotAllowedError',MediaDeviceKillSwitchOn:'NotAllowedError',TabCaptureError:'AbortError',ScreenCaptureError:'AbortError',DeviceCaptureError:'AbortError'}[e.name]||e.name,message:e.message,constraint:e.constraint||e.constraintName,toString:function toString(){return this.name+(this.message&&': ')+this.message;}};};var getUserMedia_=function getUserMedia_(constraints,onSuccess,onError){shimConstraints_(constraints,function(c){navigator.webkitGetUserMedia(c,onSuccess,function(e){if(onError){onError(shimError_(e));}});});};navigator.getUserMedia=getUserMedia_.bind(navigator);var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(cs){return shimConstraints_(cs,function(c){return origGetUserMedia(c).then(function(stream){if(c.audio&&!stream.getAudioTracks().length||c.video&&!stream.getVideoTracks().length){stream.getTracks().forEach(function(track){track.stop();});throw new DOMException('','NotFoundError');} +return stream;},function(e){return Promise.reject(shimError_(e));});});};}},{"../utils.js":15}],6:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimRTCIceCandidate=shimRTCIceCandidate;exports.shimMaxMessageSize=shimMaxMessageSize;exports.shimSendThrowTypeError=shimSendThrowTypeError;exports.shimConnectionState=shimConnectionState;exports.removeAllowExtmapMixed=removeAllowExtmapMixed;var _sdp=require('sdp');var _sdp2=_interopRequireDefault(_sdp);var _utils=require('./utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function shimRTCIceCandidate(window){if(!window.RTCIceCandidate||window.RTCIceCandidate&&'foundation'in window.RTCIceCandidate.prototype){return;} +var NativeRTCIceCandidate=window.RTCIceCandidate;window.RTCIceCandidate=function(args){if((typeof args==='undefined'?'undefined':_typeof(args))==='object'&&args.candidate&&args.candidate.indexOf('a=')===0){args=JSON.parse(JSON.stringify(args));args.candidate=args.candidate.substr(2);} +if(args.candidate&&args.candidate.length){var nativeCandidate=new NativeRTCIceCandidate(args);var parsedCandidate=_sdp2.default.parseCandidate(args.candidate);var augmentedCandidate=Object.assign(nativeCandidate,parsedCandidate);augmentedCandidate.toJSON=function(){return{candidate:augmentedCandidate.candidate,sdpMid:augmentedCandidate.sdpMid,sdpMLineIndex:augmentedCandidate.sdpMLineIndex,usernameFragment:augmentedCandidate.usernameFragment};};return augmentedCandidate;} +return new NativeRTCIceCandidate(args);};window.RTCIceCandidate.prototype=NativeRTCIceCandidate.prototype;utils.wrapPeerConnectionEvent(window,'icecandidate',function(e){if(e.candidate){Object.defineProperty(e,'candidate',{value:new window.RTCIceCandidate(e.candidate),writable:'false'});} +return e;});} +function shimMaxMessageSize(window){if(window.RTCSctpTransport||!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(!('sctp'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'sctp',{get:function get(){return typeof this._sctp==='undefined'?null:this._sctp;}});} +var sctpInDescription=function sctpInDescription(description){var sections=_sdp2.default.splitSections(description.sdp);sections.shift();return sections.some(function(mediaSection){var mLine=_sdp2.default.parseMLine(mediaSection);return mLine&&mLine.kind==='application'&&mLine.protocol.indexOf('SCTP')!==-1;});};var getRemoteFirefoxVersion=function getRemoteFirefoxVersion(description){var match=description.sdp.match(/mozilla...THIS_IS_SDPARTA-(\d+)/);if(match===null||match.length<2){return-1;} +var version=parseInt(match[1],10);return version!==version?-1:version;};var getCanSendMaxMessageSize=function getCanSendMaxMessageSize(remoteIsFirefox){var canSendMaxMessageSize=65536;if(browserDetails.browser==='firefox'){if(browserDetails.version<57){if(remoteIsFirefox===-1){canSendMaxMessageSize=16384;}else{canSendMaxMessageSize=2147483637;}}else if(browserDetails.version<60){canSendMaxMessageSize=browserDetails.version===57?65535:65536;}else{canSendMaxMessageSize=2147483637;}} +return canSendMaxMessageSize;};var getMaxMessageSize=function getMaxMessageSize(description,remoteIsFirefox){var maxMessageSize=65536;if(browserDetails.browser==='firefox'&&browserDetails.version===57){maxMessageSize=65535;} +var match=_sdp2.default.matchPrefix(description.sdp,'a=max-message-size:');if(match.length>0){maxMessageSize=parseInt(match[0].substr(19),10);}else if(browserDetails.browser==='firefox'&&remoteIsFirefox!==-1){maxMessageSize=2147483637;} +return maxMessageSize;};var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){this._sctp=null;if(sctpInDescription(arguments[0])){var isFirefox=getRemoteFirefoxVersion(arguments[0]);var canSendMMS=getCanSendMaxMessageSize(isFirefox);var remoteMMS=getMaxMessageSize(arguments[0],isFirefox);var maxMessageSize=void 0;if(canSendMMS===0&&remoteMMS===0){maxMessageSize=Number.POSITIVE_INFINITY;}else if(canSendMMS===0||remoteMMS===0){maxMessageSize=Math.max(canSendMMS,remoteMMS);}else{maxMessageSize=Math.min(canSendMMS,remoteMMS);} +var sctp={};Object.defineProperty(sctp,'maxMessageSize',{get:function get(){return maxMessageSize;}});this._sctp=sctp;} +return origSetRemoteDescription.apply(this,arguments);};} +function shimSendThrowTypeError(window){if(!(window.RTCPeerConnection&&'createDataChannel'in window.RTCPeerConnection.prototype)){return;} +function wrapDcSend(dc,pc){var origDataChannelSend=dc.send;dc.send=function(){var data=arguments[0];var length=data.length||data.size||data.byteLength;if(dc.readyState==='open'&&pc.sctp&&length>pc.sctp.maxMessageSize){throw new TypeError('Message too large (can send a maximum of '+pc.sctp.maxMessageSize+' bytes)');} +return origDataChannelSend.apply(dc,arguments);};} +var origCreateDataChannel=window.RTCPeerConnection.prototype.createDataChannel;window.RTCPeerConnection.prototype.createDataChannel=function(){var dataChannel=origCreateDataChannel.apply(this,arguments);wrapDcSend(dataChannel,this);return dataChannel;};utils.wrapPeerConnectionEvent(window,'datachannel',function(e){wrapDcSend(e.channel,e.target);return e;});} +function shimConnectionState(window){if(!window.RTCPeerConnection||'connectionState'in window.RTCPeerConnection.prototype){return;} +var proto=window.RTCPeerConnection.prototype;Object.defineProperty(proto,'connectionState',{get:function get(){return{completed:'connected',checking:'connecting'}[this.iceConnectionState]||this.iceConnectionState;},enumerable:true,configurable:true});Object.defineProperty(proto,'onconnectionstatechange',{get:function get(){return this._onconnectionstatechange||null;},set:function set(cb){if(this._onconnectionstatechange){this.removeEventListener('connectionstatechange',this._onconnectionstatechange);delete this._onconnectionstatechange;} +if(cb){this.addEventListener('connectionstatechange',this._onconnectionstatechange=cb);}},enumerable:true,configurable:true});['setLocalDescription','setRemoteDescription'].forEach(function(method){var origMethod=proto[method];proto[method]=function(){if(!this._connectionstatechangepoly){this._connectionstatechangepoly=function(e){var pc=e.target;if(pc._lastConnectionState!==pc.connectionState){pc._lastConnectionState=pc.connectionState;var newEvent=new Event('connectionstatechange',e);pc.dispatchEvent(newEvent);} +return e;};this.addEventListener('iceconnectionstatechange',this._connectionstatechangepoly);} +return origMethod.apply(this,arguments);};});} +function removeAllowExtmapMixed(window){if(!window.RTCPeerConnection){return;} +var browserDetails=utils.detectBrowser(window);if(browserDetails.browser==='chrome'&&browserDetails.version>=71){return;} +var nativeSRD=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(desc){if(desc&&desc.sdp&&desc.sdp.indexOf('\na=extmap-allow-mixed')!==-1){desc.sdp=desc.sdp.split('\n').filter(function(line){return line.trim()!=='a=extmap-allow-mixed';}).join('\n');} +return nativeSRD.apply(this,arguments);};}},{"./utils":15,"sdp":17}],7:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimPeerConnection=shimPeerConnection;exports.shimReplaceTrack=shimReplaceTrack;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);var _filtericeservers=require('./filtericeservers');var _rtcpeerconnectionShim=require('rtcpeerconnection-shim');var _rtcpeerconnectionShim2=_interopRequireDefault(_rtcpeerconnectionShim);function _interopRequireDefault(obj){return obj&&obj.__esModule?obj:{default:obj};} +function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if(window.RTCIceGatherer){if(!window.RTCIceCandidate){window.RTCIceCandidate=function(args){return args;};} +if(!window.RTCSessionDescription){window.RTCSessionDescription=function(args){return args;};} +if(browserDetails.version<15025){var origMSTEnabled=Object.getOwnPropertyDescriptor(window.MediaStreamTrack.prototype,'enabled');Object.defineProperty(window.MediaStreamTrack.prototype,'enabled',{set:function set(value){origMSTEnabled.set.call(this,value);var ev=new Event('enabled');ev.enabled=value;this.dispatchEvent(ev);}});}} +if(window.RTCRtpSender&&!('dtmf'in window.RTCRtpSender.prototype)){Object.defineProperty(window.RTCRtpSender.prototype,'dtmf',{get:function get(){if(this._dtmf===undefined){if(this.track.kind==='audio'){this._dtmf=new window.RTCDtmfSender(this);}else if(this.track.kind==='video'){this._dtmf=null;}} +return this._dtmf;}});} +if(window.RTCDtmfSender&&!window.RTCDTMFSender){window.RTCDTMFSender=window.RTCDtmfSender;} +var RTCPeerConnectionShim=(0,_rtcpeerconnectionShim2.default)(window,browserDetails.version);window.RTCPeerConnection=function(config){if(config&&config.iceServers){config.iceServers=(0,_filtericeservers.filterIceServers)(config.iceServers,browserDetails.version);utils.log('ICE servers after filtering:',config.iceServers);} +return new RTCPeerConnectionShim(config);};window.RTCPeerConnection.prototype=RTCPeerConnectionShim.prototype;} +function shimReplaceTrack(window){if(window.RTCRtpSender&&!('replaceTrack'in window.RTCRtpSender.prototype)){window.RTCRtpSender.prototype.replaceTrack=window.RTCRtpSender.prototype.setTrack;}}},{"../utils":15,"./filtericeservers":8,"./getdisplaymedia":9,"./getusermedia":10,"rtcpeerconnection-shim":16}],8:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.filterIceServers=filterIceServers;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){utils.deprecated('RTCIceServer.url','RTCIceServer.urls');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){if(url.indexOf('stun:')===0){return false;} +var validTurn=url.startsWith('turn')&&!url.startsWith('turn:[')&&url.includes('transport=udp');if(validTurn&&!hasTurn){hasTurn=true;return true;} +return validTurn&&!hasTurn;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});}},{"../utils":15}],9:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window){if(!('getDisplayMedia'in window.navigator)){return;} +if(!window.navigator.mediaDevices){return;} +if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=window.navigator.getDisplayMedia.bind(window.navigator.mediaDevices);}},{}],10:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetUserMedia=shimGetUserMedia;function shimGetUserMedia(window){var navigator=window&&window.navigator;var shimError_=function shimError_(e){return{name:{PermissionDeniedError:'NotAllowedError'}[e.name]||e.name,message:e.message,constraint:e.constraint,toString:function toString(){return this.name;}};};var origGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){return origGetUserMedia(c).catch(function(e){return Promise.reject(shimError_(e));});};}},{}],11:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=exports.shimGetUserMedia=undefined;var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};var _getusermedia=require('./getusermedia');Object.defineProperty(exports,'shimGetUserMedia',{enumerable:true,get:function get(){return _getusermedia.shimGetUserMedia;}});var _getdisplaymedia=require('./getdisplaymedia');Object.defineProperty(exports,'shimGetDisplayMedia',{enumerable:true,get:function get(){return _getdisplaymedia.shimGetDisplayMedia;}});exports.shimOnTrack=shimOnTrack;exports.shimPeerConnection=shimPeerConnection;exports.shimSenderGetStats=shimSenderGetStats;exports.shimReceiverGetStats=shimReceiverGetStats;exports.shimRemoveStream=shimRemoveStream;exports.shimRTCDataChannel=shimRTCDataChannel;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimOnTrack(window){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCTrackEvent&&'receiver'in window.RTCTrackEvent.prototype&&!('transceiver'in window.RTCTrackEvent.prototype)){Object.defineProperty(window.RTCTrackEvent.prototype,'transceiver',{get:function get(){return{receiver:this.receiver};}});}} +function shimPeerConnection(window){var browserDetails=utils.detectBrowser(window);if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!(window.RTCPeerConnection||window.mozRTCPeerConnection)){return;} +if(!window.RTCPeerConnection&&window.mozRTCPeerConnection){window.RTCPeerConnection=window.mozRTCPeerConnection;} +['setLocalDescription','setRemoteDescription','addIceCandidate'].forEach(function(method){var nativeMethod=window.RTCPeerConnection.prototype[method];window.RTCPeerConnection.prototype[method]=function(){arguments[0]=new(method==='addIceCandidate'?window.RTCIceCandidate:window.RTCSessionDescription)(arguments[0]);return nativeMethod.apply(this,arguments);};});var nativeAddIceCandidate=window.RTCPeerConnection.prototype.addIceCandidate;window.RTCPeerConnection.prototype.addIceCandidate=function(){if(!arguments[0]){if(arguments[1]){arguments[1].apply(null);} +return Promise.resolve();} +return nativeAddIceCandidate.apply(this,arguments);};var modernStatsTypes={inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'};var nativeGetStats=window.RTCPeerConnection.prototype.getStats;window.RTCPeerConnection.prototype.getStats=function(selector,onSucc,onErr){return nativeGetStats.apply(this,[selector||null]).then(function(stats){if(browserDetails.version<53&&!onSucc){try{stats.forEach(function(stat){stat.type=modernStatsTypes[stat.type]||stat.type;});}catch(e){if(e.name!=='TypeError'){throw e;} +stats.forEach(function(stat,i){stats.set(i,Object.assign({},stat,{type:modernStatsTypes[stat.type]||stat.type}));});}} +return stats;}).then(onSucc,onErr);};} +function shimSenderGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpSender.prototype){return;} +var origGetSenders=window.RTCPeerConnection.prototype.getSenders;if(origGetSenders){window.RTCPeerConnection.prototype.getSenders=function(){var _this=this;var senders=origGetSenders.apply(this,[]);senders.forEach(function(sender){return sender._pc=_this;});return senders;};} +var origAddTrack=window.RTCPeerConnection.prototype.addTrack;if(origAddTrack){window.RTCPeerConnection.prototype.addTrack=function(){var sender=origAddTrack.apply(this,arguments);sender._pc=this;return sender;};} +window.RTCRtpSender.prototype.getStats=function(){return this.track?this._pc.getStats(this.track):Promise.resolve(new Map());};} +function shimReceiverGetStats(window){if(!((typeof window==='undefined'?'undefined':_typeof(window))==='object'&&window.RTCPeerConnection&&window.RTCRtpSender)){return;} +if(window.RTCRtpSender&&'getStats'in window.RTCRtpReceiver.prototype){return;} +var origGetReceivers=window.RTCPeerConnection.prototype.getReceivers;if(origGetReceivers){window.RTCPeerConnection.prototype.getReceivers=function(){var _this2=this;var receivers=origGetReceivers.apply(this,[]);receivers.forEach(function(receiver){return receiver._pc=_this2;});return receivers;};} +utils.wrapPeerConnectionEvent(window,'track',function(e){e.receiver._pc=e.srcElement;return e;});window.RTCRtpReceiver.prototype.getStats=function(){return this._pc.getStats(this.track);};} +function shimRemoveStream(window){if(!window.RTCPeerConnection||'removeStream'in window.RTCPeerConnection.prototype){return;} +window.RTCPeerConnection.prototype.removeStream=function(stream){var _this3=this;utils.deprecated('removeStream','removeTrack');this.getSenders().forEach(function(sender){if(sender.track&&stream.getTracks().includes(sender.track)){_this3.removeTrack(sender);}});};} +function shimRTCDataChannel(window){if(window.DataChannel&&!window.RTCDataChannel){window.RTCDataChannel=window.DataChannel;}}},{"../utils":15,"./getdisplaymedia":12,"./getusermedia":13}],12:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});exports.shimGetDisplayMedia=shimGetDisplayMedia;function shimGetDisplayMedia(window,preferredMediaSource){if(window.navigator.mediaDevices&&'getDisplayMedia'in window.navigator.mediaDevices){return;} +if(!window.navigator.mediaDevices){return;} +window.navigator.mediaDevices.getDisplayMedia=function(constraints){if(!(constraints&&constraints.video)){var err=new DOMException('getDisplayMedia without video '+'constraints is undefined');err.name='NotFoundError';err.code=8;return Promise.reject(err);} +if(constraints.video===true){constraints.video={mediaSource:preferredMediaSource};}else{constraints.video.mediaSource=preferredMediaSource;} +return window.navigator.mediaDevices.getUserMedia(constraints);};}},{}],13:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimGetUserMedia=shimGetUserMedia;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimGetUserMedia(window){var browserDetails=utils.detectBrowser(window);var navigator=window&&window.navigator;var MediaStreamTrack=window&&window.MediaStreamTrack;navigator.getUserMedia=function(constraints,onSuccess,onError){utils.deprecated('navigator.getUserMedia','navigator.mediaDevices.getUserMedia');navigator.mediaDevices.getUserMedia(constraints).then(onSuccess,onError);};if(!(browserDetails.version>55&&'autoGainControl'in navigator.mediaDevices.getSupportedConstraints())){var remap=function remap(obj,a,b){if(a in obj&&!(b in obj)){obj[b]=obj[a];delete obj[a];}};var nativeGetUserMedia=navigator.mediaDevices.getUserMedia.bind(navigator.mediaDevices);navigator.mediaDevices.getUserMedia=function(c){if((typeof c==='undefined'?'undefined':_typeof(c))==='object'&&_typeof(c.audio)==='object'){c=JSON.parse(JSON.stringify(c));remap(c.audio,'autoGainControl','mozAutoGainControl');remap(c.audio,'noiseSuppression','mozNoiseSuppression');} +return nativeGetUserMedia(c);};if(MediaStreamTrack&&MediaStreamTrack.prototype.getSettings){var nativeGetSettings=MediaStreamTrack.prototype.getSettings;MediaStreamTrack.prototype.getSettings=function(){var obj=nativeGetSettings.apply(this,arguments);remap(obj,'mozAutoGainControl','autoGainControl');remap(obj,'mozNoiseSuppression','noiseSuppression');return obj;};} +if(MediaStreamTrack&&MediaStreamTrack.prototype.applyConstraints){var nativeApplyConstraints=MediaStreamTrack.prototype.applyConstraints;MediaStreamTrack.prototype.applyConstraints=function(c){if(this.kind==='audio'&&(typeof c==='undefined'?'undefined':_typeof(c))==='object'){c=JSON.parse(JSON.stringify(c));remap(c,'autoGainControl','mozAutoGainControl');remap(c,'noiseSuppression','mozNoiseSuppression');} +return nativeApplyConstraints.apply(this,[c]);};}}}},{"../utils":15}],14:[function(require,module,exports){'use strict';Object.defineProperty(exports,"__esModule",{value:true});var _typeof=typeof Symbol==="function"&&typeof Symbol.iterator==="symbol"?function(obj){return typeof obj;}:function(obj){return obj&&typeof Symbol==="function"&&obj.constructor===Symbol&&obj!==Symbol.prototype?"symbol":typeof obj;};exports.shimLocalStreamsAPI=shimLocalStreamsAPI;exports.shimRemoteStreamsAPI=shimRemoteStreamsAPI;exports.shimCallbacksAPI=shimCallbacksAPI;exports.shimGetUserMedia=shimGetUserMedia;exports.shimConstraints=shimConstraints;exports.shimRTCIceServerUrls=shimRTCIceServerUrls;exports.shimTrackEventTransceiver=shimTrackEventTransceiver;exports.shimCreateOfferLegacy=shimCreateOfferLegacy;var _utils=require('../utils');var utils=_interopRequireWildcard(_utils);function _interopRequireWildcard(obj){if(obj&&obj.__esModule){return obj;}else{var newObj={};if(obj!=null){for(var key in obj){if(Object.prototype.hasOwnProperty.call(obj,key))newObj[key]=obj[key];}}newObj.default=obj;return newObj;}} +function shimLocalStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getLocalStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getLocalStreams=function(){if(!this._localStreams){this._localStreams=[];} +return this._localStreams;};} +if(!('addStream'in window.RTCPeerConnection.prototype)){var _addTrack=window.RTCPeerConnection.prototype.addTrack;window.RTCPeerConnection.prototype.addStream=function(stream){var _this=this;if(!this._localStreams){this._localStreams=[];} +if(!this._localStreams.includes(stream)){this._localStreams.push(stream);} +stream.getTracks().forEach(function(track){return _addTrack.call(_this,track,stream);});};window.RTCPeerConnection.prototype.addTrack=function(track,stream){if(stream){if(!this._localStreams){this._localStreams=[stream];}else if(!this._localStreams.includes(stream)){this._localStreams.push(stream);}} +return _addTrack.call(this,track,stream);};} +if(!('removeStream'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.removeStream=function(stream){var _this2=this;if(!this._localStreams){this._localStreams=[];} +var index=this._localStreams.indexOf(stream);if(index===-1){return;} +this._localStreams.splice(index,1);var tracks=stream.getTracks();this.getSenders().forEach(function(sender){if(tracks.includes(sender.track)){_this2.removeTrack(sender);}});};}} +function shimRemoteStreamsAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +if(!('getRemoteStreams'in window.RTCPeerConnection.prototype)){window.RTCPeerConnection.prototype.getRemoteStreams=function(){return this._remoteStreams?this._remoteStreams:[];};} +if(!('onaddstream'in window.RTCPeerConnection.prototype)){Object.defineProperty(window.RTCPeerConnection.prototype,'onaddstream',{get:function get(){return this._onaddstream;},set:function set(f){var _this3=this;if(this._onaddstream){this.removeEventListener('addstream',this._onaddstream);this.removeEventListener('track',this._onaddstreampoly);} +this.addEventListener('addstream',this._onaddstream=f);this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!_this3._remoteStreams){_this3._remoteStreams=[];} +if(_this3._remoteStreams.includes(stream)){return;} +_this3._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;_this3.dispatchEvent(event);});});}});var origSetRemoteDescription=window.RTCPeerConnection.prototype.setRemoteDescription;window.RTCPeerConnection.prototype.setRemoteDescription=function(){var pc=this;if(!this._onaddstreampoly){this.addEventListener('track',this._onaddstreampoly=function(e){e.streams.forEach(function(stream){if(!pc._remoteStreams){pc._remoteStreams=[];} +if(pc._remoteStreams.indexOf(stream)>=0){return;} +pc._remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;pc.dispatchEvent(event);});});} +return origSetRemoteDescription.apply(pc,arguments);};}} +function shimCallbacksAPI(window){if((typeof window==='undefined'?'undefined':_typeof(window))!=='object'||!window.RTCPeerConnection){return;} +var prototype=window.RTCPeerConnection.prototype;var createOffer=prototype.createOffer;var createAnswer=prototype.createAnswer;var setLocalDescription=prototype.setLocalDescription;var setRemoteDescription=prototype.setRemoteDescription;var addIceCandidate=prototype.addIceCandidate;prototype.createOffer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createOffer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.createAnswer=function(successCallback,failureCallback){var options=arguments.length>=2?arguments[2]:arguments[0];var promise=createAnswer.apply(this,[options]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};var withCallback=function withCallback(description,successCallback,failureCallback){var promise=setLocalDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setLocalDescription=withCallback;withCallback=function withCallback(description,successCallback,failureCallback){var promise=setRemoteDescription.apply(this,[description]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.setRemoteDescription=withCallback;withCallback=function withCallback(candidate,successCallback,failureCallback){var promise=addIceCandidate.apply(this,[candidate]);if(!failureCallback){return promise;} +promise.then(successCallback,failureCallback);return Promise.resolve();};prototype.addIceCandidate=withCallback;} +function shimGetUserMedia(window){var navigator=window&&window.navigator;if(navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){var mediaDevices=navigator.mediaDevices;var _getUserMedia=mediaDevices.getUserMedia.bind(mediaDevices);navigator.mediaDevices.getUserMedia=function(constraints){return _getUserMedia(shimConstraints(constraints));};} +if(!navigator.getUserMedia&&navigator.mediaDevices&&navigator.mediaDevices.getUserMedia){navigator.getUserMedia=function(constraints,cb,errcb){navigator.mediaDevices.getUserMedia(constraints).then(cb,errcb);}.bind(navigator);}} +function shimConstraints(constraints){if(constraints&&constraints.video!==undefined){return Object.assign({},constraints,{video:utils.compactObject(constraints.video)});} +return constraints;} +function shimRTCIceServerUrls(window){var OrigPeerConnection=window.RTCPeerConnection;window.RTCPeerConnection=function(pcConfig,pcConstraints){if(pcConfig&&pcConfig.iceServers){var newIceServers=[];for(var i=0;i=pos&&parseInt(match[pos],10);} +function wrapPeerConnectionEvent(window,eventNameToWrap,wrapper){if(!window.RTCPeerConnection){return;} +var proto=window.RTCPeerConnection.prototype;var nativeAddEventListener=proto.addEventListener;proto.addEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap){return nativeAddEventListener.apply(this,arguments);} +var wrappedCallback=function wrappedCallback(e){var modifiedEvent=wrapper(e);if(modifiedEvent){cb(modifiedEvent);}};this._eventMap=this._eventMap||{};this._eventMap[cb]=wrappedCallback;return nativeAddEventListener.apply(this,[nativeEventName,wrappedCallback]);};var nativeRemoveEventListener=proto.removeEventListener;proto.removeEventListener=function(nativeEventName,cb){if(nativeEventName!==eventNameToWrap||!this._eventMap||!this._eventMap[cb]){return nativeRemoveEventListener.apply(this,arguments);} +var unwrappedCb=this._eventMap[cb];delete this._eventMap[cb];return nativeRemoveEventListener.apply(this,[nativeEventName,unwrappedCb]);};Object.defineProperty(proto,'on'+eventNameToWrap,{get:function get(){return this['_on'+eventNameToWrap];},set:function set(cb){if(this['_on'+eventNameToWrap]){this.removeEventListener(eventNameToWrap,this['_on'+eventNameToWrap]);delete this['_on'+eventNameToWrap];} +if(cb){this.addEventListener(eventNameToWrap,this['_on'+eventNameToWrap]=cb);}},enumerable:true,configurable:true});} +function disableLog(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +logDisabled_=bool;return bool?'adapter.js logging disabled':'adapter.js logging enabled';} +function disableWarnings(bool){if(typeof bool!=='boolean'){return new Error('Argument type: '+(typeof bool==='undefined'?'undefined':_typeof(bool))+'. Please use a boolean.');} +deprecationWarnings_=!bool;return'adapter.js deprecation warnings '+(bool?'disabled':'enabled');} +function log(){if((typeof window==='undefined'?'undefined':_typeof(window))==='object'){if(logDisabled_){return;} +if(typeof console!=='undefined'&&typeof console.log==='function'){console.log.apply(console,arguments);}}} +function deprecated(oldMethod,newMethod){if(!deprecationWarnings_){return;} +console.warn(oldMethod+' is deprecated, please use '+newMethod+' instead.');} +function detectBrowser(window){var navigator=window.navigator;var result={browser:null,version:null};if(typeof window==='undefined'||!window.navigator){result.browser='Not a browser.';return result;} +if(navigator.mozGetUserMedia){result.browser='firefox';result.version=extractVersion(navigator.userAgent,/Firefox\/(\d+)\./,1);}else if(navigator.webkitGetUserMedia){result.browser='chrome';result.version=extractVersion(navigator.userAgent,/Chrom(e|ium)\/(\d+)\./,2);}else if(navigator.mediaDevices&&navigator.userAgent.match(/Edge\/(\d+).(\d+)$/)){result.browser='edge';result.version=extractVersion(navigator.userAgent,/Edge\/(\d+).(\d+)$/,2);}else if(window.RTCPeerConnection&&navigator.userAgent.match(/AppleWebKit\/(\d+)\./)){result.browser='safari';result.version=extractVersion(navigator.userAgent,/AppleWebKit\/(\d+)\./,1);}else{result.browser='Not a supported browser.';return result;} +return result;} +function compactObject(data){if((typeof data==='undefined'?'undefined':_typeof(data))!=='object'){return data;} +return Object.keys(data).reduce(function(accumulator,key){var isObject=_typeof(data[key])==='object';var value=isObject?compactObject(data[key]):data[key];var isEmptyObject=isObject&&!Object.keys(value).length;if(value===undefined||isEmptyObject){return accumulator;} +return Object.assign(accumulator,_defineProperty({},key,value));},{});}},{}],16:[function(require,module,exports){'use strict';var SDPUtils=require('sdp');function fixStatsType(stat){return{inboundrtp:'inbound-rtp',outboundrtp:'outbound-rtp',candidatepair:'candidate-pair',localcandidate:'local-candidate',remotecandidate:'remote-candidate'}[stat.type]||stat.type;} +function writeMediaSection(transceiver,caps,type,stream,dtlsRole){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':dtlsRole||'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var trackId=transceiver.rtpSender._initialTrackId||transceiver.rtpSender.track.id;transceiver.rtpSender._initialTrackId=trackId;var msid='msid:'+(stream?stream.id:'-')+' '+ +trackId+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;} +function filterIceServers(iceServers,edgeVersion){var hasTurn=false;iceServers=JSON.parse(JSON.stringify(iceServers));return iceServers.filter(function(server){if(server&&(server.urls||server.url)){var urls=server.urls||server.url;if(server.url&&!server.urls){console.warn('RTCIceServer.url is deprecated! Use urls instead.');} +var isString=typeof urls==='string';if(isString){urls=[urls];} +urls=urls.filter(function(url){var validTurn=url.indexOf('turn:')===0&&url.indexOf('transport=udp')!==-1&&url.indexOf('turn:[')===-1&&!hasTurn;if(validTurn){hasTurn=true;return true;} +return url.indexOf('stun:')===0&&edgeVersion>=14393&&url.indexOf('?transport=udp')===-1;});delete server.url;server.urls=isString?urls[0]:urls;return!!urls.length;}});} +function getCommonCapabilities(localCapabilities,remoteCapabilities){var commonCapabilities={codecs:[],headerExtensions:[],fecMechanisms:[]};var findCodecByPayloadType=function(pt,codecs){pt=parseInt(pt,10);for(var i=0;i0;i--){this._iceGatherers.push(new window.RTCIceGatherer({iceServers:config.iceServers,gatherPolicy:config.iceTransportPolicy}));}}else{config.iceCandidatePoolSize=0;} +this._config=config;this.transceivers=[];this._sdpSessionId=SDPUtils.generateSessionId();this._sdpSessionVersion=0;this._dtlsRole=undefined;this._isClosed=false;};Object.defineProperty(RTCPeerConnection.prototype,'localDescription',{configurable:true,get:function(){return this._localDescription;}});Object.defineProperty(RTCPeerConnection.prototype,'remoteDescription',{configurable:true,get:function(){return this._remoteDescription;}});RTCPeerConnection.prototype.onicecandidate=null;RTCPeerConnection.prototype.onaddstream=null;RTCPeerConnection.prototype.ontrack=null;RTCPeerConnection.prototype.onremovestream=null;RTCPeerConnection.prototype.onsignalingstatechange=null;RTCPeerConnection.prototype.oniceconnectionstatechange=null;RTCPeerConnection.prototype.onconnectionstatechange=null;RTCPeerConnection.prototype.onicegatheringstatechange=null;RTCPeerConnection.prototype.onnegotiationneeded=null;RTCPeerConnection.prototype.ondatachannel=null;RTCPeerConnection.prototype._dispatchEvent=function(name,event){if(this._isClosed){return;} +this.dispatchEvent(event);if(typeof this['on'+name]==='function'){this['on'+name](event);}};RTCPeerConnection.prototype._emitGatheringStateChange=function(){var event=new Event('icegatheringstatechange');this._dispatchEvent('icegatheringstatechange',event);};RTCPeerConnection.prototype.getConfiguration=function(){return this._config;};RTCPeerConnection.prototype.getLocalStreams=function(){return this.localStreams;};RTCPeerConnection.prototype.getRemoteStreams=function(){return this.remoteStreams;};RTCPeerConnection.prototype._createTransceiver=function(kind,doNotAdd){var hasBundleTransport=this.transceivers.length>0;var transceiver={track:null,iceGatherer:null,iceTransport:null,dtlsTransport:null,localCapabilities:null,remoteCapabilities:null,rtpSender:null,rtpReceiver:null,kind:kind,mid:null,sendEncodingParameters:null,recvEncodingParameters:null,stream:null,associatedRemoteMediaStreams:[],wantReceive:true};if(this.usingBundle&&hasBundleTransport){transceiver.iceTransport=this.transceivers[0].iceTransport;transceiver.dtlsTransport=this.transceivers[0].dtlsTransport;}else{var transports=this._createIceAndDtlsTransports();transceiver.iceTransport=transports.iceTransport;transceiver.dtlsTransport=transports.dtlsTransport;} +if(!doNotAdd){this.transceivers.push(transceiver);} +return transceiver;};RTCPeerConnection.prototype.addTrack=function(track,stream){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call addTrack on a closed peerconnection.');} +var alreadyExists=this.transceivers.find(function(s){return s.track===track;});if(alreadyExists){throw makeError('InvalidAccessError','Track already exists.');} +var transceiver;for(var i=0;i=15025){stream.getTracks().forEach(function(track){pc.addTrack(track,stream);});}else{var clonedStream=stream.clone();stream.getTracks().forEach(function(track,idx){var clonedTrack=clonedStream.getTracks()[idx];track.addEventListener('enabled',function(event){clonedTrack.enabled=event.enabled;});});clonedStream.getTracks().forEach(function(track){pc.addTrack(track,clonedStream);});}};RTCPeerConnection.prototype.removeTrack=function(sender){if(this._isClosed){throw makeError('InvalidStateError','Attempted to call removeTrack on a closed peerconnection.');} +if(!(sender instanceof window.RTCRtpSender)){throw new TypeError('Argument 1 of RTCPeerConnection.removeTrack '+'does not implement interface RTCRtpSender.');} +var transceiver=this.transceivers.find(function(t){return t.rtpSender===sender;});if(!transceiver){throw makeError('InvalidAccessError','Sender was not created by this connection.');} +var stream=transceiver.stream;transceiver.rtpSender.stop();transceiver.rtpSender=null;transceiver.track=null;transceiver.stream=null;var localStreams=this.transceivers.map(function(t){return t.stream;});if(localStreams.indexOf(stream)===-1&&this.localStreams.indexOf(stream)>-1){this.localStreams.splice(this.localStreams.indexOf(stream),1);} +this._maybeFireNegotiationNeeded();};RTCPeerConnection.prototype.removeStream=function(stream){var pc=this;stream.getTracks().forEach(function(track){var sender=pc.getSenders().find(function(s){return s.track===track;});if(sender){pc.removeTrack(sender);}});};RTCPeerConnection.prototype.getSenders=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpSender;}).map(function(transceiver){return transceiver.rtpSender;});};RTCPeerConnection.prototype.getReceivers=function(){return this.transceivers.filter(function(transceiver){return!!transceiver.rtpReceiver;}).map(function(transceiver){return transceiver.rtpReceiver;});};RTCPeerConnection.prototype._createIceGatherer=function(sdpMLineIndex,usingBundle){var pc=this;if(usingBundle&&sdpMLineIndex>0){return this.transceivers[0].iceGatherer;}else if(this._iceGatherers.length){return this._iceGatherers.shift();} +var iceGatherer=new window.RTCIceGatherer({iceServers:this._config.iceServers,gatherPolicy:this._config.iceTransportPolicy});Object.defineProperty(iceGatherer,'state',{value:'new',writable:true});this.transceivers[sdpMLineIndex].bufferedCandidateEvents=[];this.transceivers[sdpMLineIndex].bufferCandidates=function(event){var end=!event.candidate||Object.keys(event.candidate).length===0;iceGatherer.state=end?'completed':'gathering';if(pc.transceivers[sdpMLineIndex].bufferedCandidateEvents!==null){pc.transceivers[sdpMLineIndex].bufferedCandidateEvents.push(event);}};iceGatherer.addEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);return iceGatherer;};RTCPeerConnection.prototype._gather=function(mid,sdpMLineIndex){var pc=this;var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer.onlocalcandidate){return;} +var bufferedCandidateEvents=this.transceivers[sdpMLineIndex].bufferedCandidateEvents;this.transceivers[sdpMLineIndex].bufferedCandidateEvents=null;iceGatherer.removeEventListener('localcandidate',this.transceivers[sdpMLineIndex].bufferCandidates);iceGatherer.onlocalcandidate=function(evt){if(pc.usingBundle&&sdpMLineIndex>0){return;} +var event=new Event('icecandidate');event.candidate={sdpMid:mid,sdpMLineIndex:sdpMLineIndex};var cand=evt.candidate;var end=!cand||Object.keys(cand).length===0;if(end){if(iceGatherer.state==='new'||iceGatherer.state==='gathering'){iceGatherer.state='completed';}}else{if(iceGatherer.state==='new'){iceGatherer.state='gathering';} +cand.component=1;cand.ufrag=iceGatherer.getLocalParameters().usernameFragment;var serializedCandidate=SDPUtils.writeCandidate(cand);event.candidate=Object.assign(event.candidate,SDPUtils.parseCandidate(serializedCandidate));event.candidate.candidate=serializedCandidate;event.candidate.toJSON=function(){return{candidate:event.candidate.candidate,sdpMid:event.candidate.sdpMid,sdpMLineIndex:event.candidate.sdpMLineIndex,usernameFragment:event.candidate.usernameFragment};};} +var sections=SDPUtils.getMediaSections(pc._localDescription.sdp);if(!end){sections[event.candidate.sdpMLineIndex]+='a='+event.candidate.candidate+'\r\n';}else{sections[event.candidate.sdpMLineIndex]+='a=end-of-candidates\r\n';} +pc._localDescription.sdp=SDPUtils.getDescription(pc._localDescription.sdp)+ +sections.join('');var complete=pc.transceivers.every(function(transceiver){return transceiver.iceGatherer&&transceiver.iceGatherer.state==='completed';});if(pc.iceGatheringState!=='gathering'){pc.iceGatheringState='gathering';pc._emitGatheringStateChange();} +if(!end){pc._dispatchEvent('icecandidate',event);} +if(complete){pc._dispatchEvent('icecandidate',new Event('icecandidate'));pc.iceGatheringState='complete';pc._emitGatheringStateChange();}};window.setTimeout(function(){bufferedCandidateEvents.forEach(function(e){iceGatherer.onlocalcandidate(e);});},0);};RTCPeerConnection.prototype._createIceAndDtlsTransports=function(){var pc=this;var iceTransport=new window.RTCIceTransport(null);iceTransport.onicestatechange=function(){pc._updateIceConnectionState();pc._updateConnectionState();};var dtlsTransport=new window.RTCDtlsTransport(iceTransport);dtlsTransport.ondtlsstatechange=function(){pc._updateConnectionState();};dtlsTransport.onerror=function(){Object.defineProperty(dtlsTransport,'state',{value:'failed',writable:true});pc._updateConnectionState();};return{iceTransport:iceTransport,dtlsTransport:dtlsTransport};};RTCPeerConnection.prototype._disposeIceAndDtlsTransports=function(sdpMLineIndex){var iceGatherer=this.transceivers[sdpMLineIndex].iceGatherer;if(iceGatherer){delete iceGatherer.onlocalcandidate;delete this.transceivers[sdpMLineIndex].iceGatherer;} +var iceTransport=this.transceivers[sdpMLineIndex].iceTransport;if(iceTransport){delete iceTransport.onicestatechange;delete this.transceivers[sdpMLineIndex].iceTransport;} +var dtlsTransport=this.transceivers[sdpMLineIndex].dtlsTransport;if(dtlsTransport){delete dtlsTransport.ondtlsstatechange;delete dtlsTransport.onerror;delete this.transceivers[sdpMLineIndex].dtlsTransport;}};RTCPeerConnection.prototype._transceive=function(transceiver,send,recv){var params=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);if(send&&transceiver.rtpSender){params.encodings=transceiver.sendEncodingParameters;params.rtcp={cname:SDPUtils.localCName,compound:transceiver.rtcpParameters.compound};if(transceiver.recvEncodingParameters.length){params.rtcp.ssrc=transceiver.recvEncodingParameters[0].ssrc;} +transceiver.rtpSender.send(params);} +if(recv&&transceiver.rtpReceiver&¶ms.codecs.length>0){if(transceiver.kind==='video'&&transceiver.recvEncodingParameters&&edgeVersion<15019){transceiver.recvEncodingParameters.forEach(function(p){delete p.rtx;});} +if(transceiver.recvEncodingParameters.length){params.encodings=transceiver.recvEncodingParameters;}else{params.encodings=[{}];} +params.rtcp={compound:transceiver.rtcpParameters.compound};if(transceiver.rtcpParameters.cname){params.rtcp.cname=transceiver.rtcpParameters.cname;} +if(transceiver.sendEncodingParameters.length){params.rtcp.ssrc=transceiver.sendEncodingParameters[0].ssrc;} +transceiver.rtpReceiver.receive(params);}};RTCPeerConnection.prototype.setLocalDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setLocalDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set local '+description.type+' in state '+pc.signalingState));} +var sections;var sessionpart;if(description.type==='offer'){sections=SDPUtils.splitSections(description.sdp);sessionpart=sections.shift();sections.forEach(function(mediaSection,sdpMLineIndex){var caps=SDPUtils.parseRtpParameters(mediaSection);pc.transceivers[sdpMLineIndex].localCapabilities=caps;});pc.transceivers.forEach(function(transceiver,sdpMLineIndex){pc._gather(transceiver.mid,sdpMLineIndex);});}else if(description.type==='answer'){sections=SDPUtils.splitSections(pc._remoteDescription.sdp);sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;sections.forEach(function(mediaSection,sdpMLineIndex){var transceiver=pc.transceivers[sdpMLineIndex];var iceGatherer=transceiver.iceGatherer;var iceTransport=transceiver.iceTransport;var dtlsTransport=transceiver.dtlsTransport;var localCapabilities=transceiver.localCapabilities;var remoteCapabilities=transceiver.remoteCapabilities;var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;if(!rejected&&!transceiver.rejected){var remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);var remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);if(isIceLite){remoteDtlsParameters.role='server';} +if(!pc.usingBundle||sdpMLineIndex===0){pc._gather(transceiver.mid,sdpMLineIndex);if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,isIceLite?'controlling':'controlled');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var params=getCommonCapabilities(localCapabilities,remoteCapabilities);pc._transceive(transceiver,params.codecs.length>0,false);}});} +pc._localDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-local-offer');}else{pc._updateSignalingState('stable');} +return Promise.resolve();};RTCPeerConnection.prototype.setRemoteDescription=function(description){var pc=this;if(['offer','answer'].indexOf(description.type)===-1){return Promise.reject(makeError('TypeError','Unsupported type "'+description.type+'"'));} +if(!isActionAllowedInSignalingState('setRemoteDescription',description.type,pc.signalingState)||pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not set remote '+description.type+' in state '+pc.signalingState));} +var streams={};pc.remoteStreams.forEach(function(stream){streams[stream.id]=stream;});var receiverList=[];var sections=SDPUtils.splitSections(description.sdp);var sessionpart=sections.shift();var isIceLite=SDPUtils.matchPrefix(sessionpart,'a=ice-lite').length>0;var usingBundle=SDPUtils.matchPrefix(sessionpart,'a=group:BUNDLE ').length>0;pc.usingBundle=usingBundle;var iceOptions=SDPUtils.matchPrefix(sessionpart,'a=ice-options:')[0];if(iceOptions){pc.canTrickleIceCandidates=iceOptions.substr(14).split(' ').indexOf('trickle')>=0;}else{pc.canTrickleIceCandidates=false;} +sections.forEach(function(mediaSection,sdpMLineIndex){var lines=SDPUtils.splitLines(mediaSection);var kind=SDPUtils.getKind(mediaSection);var rejected=SDPUtils.isRejected(mediaSection)&&SDPUtils.matchPrefix(mediaSection,'a=bundle-only').length===0;var protocol=lines[0].substr(2).split(' ')[2];var direction=SDPUtils.getDirection(mediaSection,sessionpart);var remoteMsid=SDPUtils.parseMsid(mediaSection);var mid=SDPUtils.getMid(mediaSection)||SDPUtils.generateIdentifier();if(rejected||(kind==='application'&&(protocol==='DTLS/SCTP'||protocol==='UDP/DTLS/SCTP'))){pc.transceivers[sdpMLineIndex]={mid:mid,kind:kind,protocol:protocol,rejected:true};return;} +if(!rejected&&pc.transceivers[sdpMLineIndex]&&pc.transceivers[sdpMLineIndex].rejected){pc.transceivers[sdpMLineIndex]=pc._createTransceiver(kind,true);} +var transceiver;var iceGatherer;var iceTransport;var dtlsTransport;var rtpReceiver;var sendEncodingParameters;var recvEncodingParameters;var localCapabilities;var track;var remoteCapabilities=SDPUtils.parseRtpParameters(mediaSection);var remoteIceParameters;var remoteDtlsParameters;if(!rejected){remoteIceParameters=SDPUtils.getIceParameters(mediaSection,sessionpart);remoteDtlsParameters=SDPUtils.getDtlsParameters(mediaSection,sessionpart);remoteDtlsParameters.role='client';} +recvEncodingParameters=SDPUtils.parseRtpEncodingParameters(mediaSection);var rtcpParameters=SDPUtils.parseRtcpParameters(mediaSection);var isComplete=SDPUtils.matchPrefix(mediaSection,'a=end-of-candidates',sessionpart).length>0;var cands=SDPUtils.matchPrefix(mediaSection,'a=candidate:').map(function(cand){return SDPUtils.parseCandidate(cand);}).filter(function(cand){return cand.component===1;});if((description.type==='offer'||description.type==='answer')&&!rejected&&usingBundle&&sdpMLineIndex>0&&pc.transceivers[sdpMLineIndex]){pc._disposeIceAndDtlsTransports(sdpMLineIndex);pc.transceivers[sdpMLineIndex].iceGatherer=pc.transceivers[0].iceGatherer;pc.transceivers[sdpMLineIndex].iceTransport=pc.transceivers[0].iceTransport;pc.transceivers[sdpMLineIndex].dtlsTransport=pc.transceivers[0].dtlsTransport;if(pc.transceivers[sdpMLineIndex].rtpSender){pc.transceivers[sdpMLineIndex].rtpSender.setTransport(pc.transceivers[0].dtlsTransport);} +if(pc.transceivers[sdpMLineIndex].rtpReceiver){pc.transceivers[sdpMLineIndex].rtpReceiver.setTransport(pc.transceivers[0].dtlsTransport);}} +if(description.type==='offer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex]||pc._createTransceiver(kind);transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,usingBundle);} +if(cands.length&&transceiver.iceTransport.state==='new'){if(isComplete&&(!usingBundle||sdpMLineIndex===0)){transceiver.iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +localCapabilities=window.RTCRtpReceiver.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+2)*1001}];var isNewTrack=false;if(direction==='sendrecv'||direction==='sendonly'){isNewTrack=!transceiver.rtpReceiver;rtpReceiver=transceiver.rtpReceiver||new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);if(isNewTrack){var stream;track=rtpReceiver.track;if(remoteMsid&&remoteMsid.stream==='-'){}else if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();Object.defineProperty(streams[remoteMsid.stream],'id',{get:function(){return remoteMsid.stream;}});} +Object.defineProperty(track,'id',{get:function(){return remoteMsid.track;}});stream=streams[remoteMsid.stream];}else{if(!streams.default){streams.default=new window.MediaStream();} +stream=streams.default;} +if(stream){addTrackToStreamAndFireEvent(track,stream);transceiver.associatedRemoteMediaStreams.push(stream);} +receiverList.push([track,rtpReceiver,stream]);}}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track){transceiver.associatedRemoteMediaStreams.forEach(function(s){var nativeTrack=s.getTracks().find(function(t){return t.id===transceiver.rtpReceiver.track.id;});if(nativeTrack){removeTrackFromStreamAndFireEvent(nativeTrack,s);}});transceiver.associatedRemoteMediaStreams=[];} +transceiver.localCapabilities=localCapabilities;transceiver.remoteCapabilities=remoteCapabilities;transceiver.rtpReceiver=rtpReceiver;transceiver.rtcpParameters=rtcpParameters;transceiver.sendEncodingParameters=sendEncodingParameters;transceiver.recvEncodingParameters=recvEncodingParameters;pc._transceive(pc.transceivers[sdpMLineIndex],false,isNewTrack);}else if(description.type==='answer'&&!rejected){transceiver=pc.transceivers[sdpMLineIndex];iceGatherer=transceiver.iceGatherer;iceTransport=transceiver.iceTransport;dtlsTransport=transceiver.dtlsTransport;rtpReceiver=transceiver.rtpReceiver;sendEncodingParameters=transceiver.sendEncodingParameters;localCapabilities=transceiver.localCapabilities;pc.transceivers[sdpMLineIndex].recvEncodingParameters=recvEncodingParameters;pc.transceivers[sdpMLineIndex].remoteCapabilities=remoteCapabilities;pc.transceivers[sdpMLineIndex].rtcpParameters=rtcpParameters;if(cands.length&&iceTransport.state==='new'){if((isIceLite||isComplete)&&(!usingBundle||sdpMLineIndex===0)){iceTransport.setRemoteCandidates(cands);}else{cands.forEach(function(candidate){maybeAddCandidate(transceiver.iceTransport,candidate);});}} +if(!usingBundle||sdpMLineIndex===0){if(iceTransport.state==='new'){iceTransport.start(iceGatherer,remoteIceParameters,'controlling');} +if(dtlsTransport.state==='new'){dtlsTransport.start(remoteDtlsParameters);}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +pc._transceive(transceiver,direction==='sendrecv'||direction==='recvonly',direction==='sendrecv'||direction==='sendonly');if(rtpReceiver&&(direction==='sendrecv'||direction==='sendonly')){track=rtpReceiver.track;if(remoteMsid){if(!streams[remoteMsid.stream]){streams[remoteMsid.stream]=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams[remoteMsid.stream]);receiverList.push([track,rtpReceiver,streams[remoteMsid.stream]]);}else{if(!streams.default){streams.default=new window.MediaStream();} +addTrackToStreamAndFireEvent(track,streams.default);receiverList.push([track,rtpReceiver,streams.default]);}}else{delete transceiver.rtpReceiver;}}});if(pc._dtlsRole===undefined){pc._dtlsRole=description.type==='offer'?'active':'passive';} +pc._remoteDescription={type:description.type,sdp:description.sdp};if(description.type==='offer'){pc._updateSignalingState('have-remote-offer');}else{pc._updateSignalingState('stable');} +Object.keys(streams).forEach(function(sid){var stream=streams[sid];if(stream.getTracks().length){if(pc.remoteStreams.indexOf(stream)===-1){pc.remoteStreams.push(stream);var event=new Event('addstream');event.stream=stream;window.setTimeout(function(){pc._dispatchEvent('addstream',event);});} +receiverList.forEach(function(item){var track=item[0];var receiver=item[1];if(stream.id!==item[2].id){return;} +fireAddTrack(pc,track,receiver,[stream]);});}});receiverList.forEach(function(item){if(item[2]){return;} +fireAddTrack(pc,item[0],item[1],[]);});window.setTimeout(function(){if(!(pc&&pc.transceivers)){return;} +pc.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.iceTransport.state==='new'&&transceiver.iceTransport.getRemoteCandidates().length>0){console.warn('Timeout for addRemoteCandidate. Consider sending '+'an end-of-candidates notification');transceiver.iceTransport.addRemoteCandidate({});}});},4000);return Promise.resolve();};RTCPeerConnection.prototype.close=function(){this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport){transceiver.iceTransport.stop();} +if(transceiver.dtlsTransport){transceiver.dtlsTransport.stop();} +if(transceiver.rtpSender){transceiver.rtpSender.stop();} +if(transceiver.rtpReceiver){transceiver.rtpReceiver.stop();}});this._isClosed=true;this._updateSignalingState('closed');};RTCPeerConnection.prototype._updateSignalingState=function(newState){this.signalingState=newState;var event=new Event('signalingstatechange');this._dispatchEvent('signalingstatechange',event);};RTCPeerConnection.prototype._maybeFireNegotiationNeeded=function(){var pc=this;if(this.signalingState!=='stable'||this.needNegotiation===true){return;} +this.needNegotiation=true;window.setTimeout(function(){if(pc.needNegotiation){pc.needNegotiation=false;var event=new Event('negotiationneeded');pc._dispatchEvent('negotiationneeded',event);}},0);};RTCPeerConnection.prototype._updateIceConnectionState=function(){var newState;var states={'new':0,closed:0,checking:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;}});newState='new';if(states.failed>0){newState='failed';}else if(states.checking>0){newState='checking';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';}else if(states.completed>0){newState='completed';} +if(newState!==this.iceConnectionState){this.iceConnectionState=newState;var event=new Event('iceconnectionstatechange');this._dispatchEvent('iceconnectionstatechange',event);}};RTCPeerConnection.prototype._updateConnectionState=function(){var newState;var states={'new':0,closed:0,connecting:0,connected:0,completed:0,disconnected:0,failed:0};this.transceivers.forEach(function(transceiver){if(transceiver.iceTransport&&transceiver.dtlsTransport&&!transceiver.rejected){states[transceiver.iceTransport.state]++;states[transceiver.dtlsTransport.state]++;}});states.connected+=states.completed;newState='new';if(states.failed>0){newState='failed';}else if(states.connecting>0){newState='connecting';}else if(states.disconnected>0){newState='disconnected';}else if(states.new>0){newState='new';}else if(states.connected>0){newState='connected';} +if(newState!==this.connectionState){this.connectionState=newState;var event=new Event('connectionstatechange');this._dispatchEvent('connectionstatechange',event);}};RTCPeerConnection.prototype.createOffer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createOffer after close'));} +var numAudioTracks=pc.transceivers.filter(function(t){return t.kind==='audio';}).length;var numVideoTracks=pc.transceivers.filter(function(t){return t.kind==='video';}).length;var offerOptions=arguments[0];if(offerOptions){if(offerOptions.mandatory||offerOptions.optional){throw new TypeError('Legacy mandatory/optional constraints not supported.');} +if(offerOptions.offerToReceiveAudio!==undefined){if(offerOptions.offerToReceiveAudio===true){numAudioTracks=1;}else if(offerOptions.offerToReceiveAudio===false){numAudioTracks=0;}else{numAudioTracks=offerOptions.offerToReceiveAudio;}} +if(offerOptions.offerToReceiveVideo!==undefined){if(offerOptions.offerToReceiveVideo===true){numVideoTracks=1;}else if(offerOptions.offerToReceiveVideo===false){numVideoTracks=0;}else{numVideoTracks=offerOptions.offerToReceiveVideo;}}} +pc.transceivers.forEach(function(transceiver){if(transceiver.kind==='audio'){numAudioTracks--;if(numAudioTracks<0){transceiver.wantReceive=false;}}else if(transceiver.kind==='video'){numVideoTracks--;if(numVideoTracks<0){transceiver.wantReceive=false;}}});while(numAudioTracks>0||numVideoTracks>0){if(numAudioTracks>0){pc._createTransceiver('audio');numAudioTracks--;} +if(numVideoTracks>0){pc._createTransceiver('video');numVideoTracks--;}} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);pc.transceivers.forEach(function(transceiver,sdpMLineIndex){var track=transceiver.track;var kind=transceiver.kind;var mid=transceiver.mid||SDPUtils.generateIdentifier();transceiver.mid=mid;if(!transceiver.iceGatherer){transceiver.iceGatherer=pc._createIceGatherer(sdpMLineIndex,pc.usingBundle);} +var localCapabilities=window.RTCRtpSender.getCapabilities(kind);if(edgeVersion<15019){localCapabilities.codecs=localCapabilities.codecs.filter(function(codec){return codec.name!=='rtx';});} +localCapabilities.codecs.forEach(function(codec){if(codec.name==='H264'&&codec.parameters['level-asymmetry-allowed']===undefined){codec.parameters['level-asymmetry-allowed']='1';} +if(transceiver.remoteCapabilities&&transceiver.remoteCapabilities.codecs){transceiver.remoteCapabilities.codecs.forEach(function(remoteCodec){if(codec.name.toLowerCase()===remoteCodec.name.toLowerCase()&&codec.clockRate===remoteCodec.clockRate){codec.preferredPayloadType=remoteCodec.payloadType;}});}});localCapabilities.headerExtensions.forEach(function(hdrExt){var remoteExtensions=transceiver.remoteCapabilities&&transceiver.remoteCapabilities.headerExtensions||[];remoteExtensions.forEach(function(rHdrExt){if(hdrExt.uri===rHdrExt.uri){hdrExt.id=rHdrExt.id;}});});var sendEncodingParameters=transceiver.sendEncodingParameters||[{ssrc:(2*sdpMLineIndex+1)*1001}];if(track){if(edgeVersion>=15019&&kind==='video'&&!sendEncodingParameters[0].rtx){sendEncodingParameters[0].rtx={ssrc:sendEncodingParameters[0].ssrc+1};}} +if(transceiver.wantReceive){transceiver.rtpReceiver=new window.RTCRtpReceiver(transceiver.dtlsTransport,kind);} +transceiver.localCapabilities=localCapabilities;transceiver.sendEncodingParameters=sendEncodingParameters;});if(pc._config.bundlePolicy!=='max-compat'){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';pc.transceivers.forEach(function(transceiver,sdpMLineIndex){sdp+=writeMediaSection(transceiver,transceiver.localCapabilities,'offer',transceiver.stream,pc._dtlsRole);sdp+='a=rtcp-rsize\r\n';if(transceiver.iceGatherer&&pc.iceGatheringState!=='new'&&(sdpMLineIndex===0||!pc.usingBundle)){transceiver.iceGatherer.getLocalCandidates().forEach(function(cand){cand.component=1;sdp+='a='+SDPUtils.writeCandidate(cand)+'\r\n';});if(transceiver.iceGatherer.state==='completed'){sdp+='a=end-of-candidates\r\n';}}});var desc=new window.RTCSessionDescription({type:'offer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.createAnswer=function(){var pc=this;if(pc._isClosed){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer after close'));} +if(!(pc.signalingState==='have-remote-offer'||pc.signalingState==='have-local-pranswer')){return Promise.reject(makeError('InvalidStateError','Can not call createAnswer in signalingState '+pc.signalingState));} +var sdp=SDPUtils.writeSessionBoilerplate(pc._sdpSessionId,pc._sdpSessionVersion++);if(pc.usingBundle){sdp+='a=group:BUNDLE '+pc.transceivers.map(function(t){return t.mid;}).join(' ')+'\r\n';} +sdp+='a=ice-options:trickle\r\n';var mediaSectionsInOffer=SDPUtils.getMediaSections(pc._remoteDescription.sdp).length;pc.transceivers.forEach(function(transceiver,sdpMLineIndex){if(sdpMLineIndex+1>mediaSectionsInOffer){return;} +if(transceiver.rejected){if(transceiver.kind==='application'){if(transceiver.protocol==='DTLS/SCTP'){sdp+='m=application 0 DTLS/SCTP 5000\r\n';}else{sdp+='m=application 0 '+transceiver.protocol+' webrtc-datachannel\r\n';}}else if(transceiver.kind==='audio'){sdp+='m=audio 0 UDP/TLS/RTP/SAVPF 0\r\n'+'a=rtpmap:0 PCMU/8000\r\n';}else if(transceiver.kind==='video'){sdp+='m=video 0 UDP/TLS/RTP/SAVPF 120\r\n'+'a=rtpmap:120 VP8/90000\r\n';} +sdp+='c=IN IP4 0.0.0.0\r\n'+'a=inactive\r\n'+'a=mid:'+transceiver.mid+'\r\n';return;} +if(transceiver.stream){var localTrack;if(transceiver.kind==='audio'){localTrack=transceiver.stream.getAudioTracks()[0];}else if(transceiver.kind==='video'){localTrack=transceiver.stream.getVideoTracks()[0];} +if(localTrack){if(edgeVersion>=15019&&transceiver.kind==='video'&&!transceiver.sendEncodingParameters[0].rtx){transceiver.sendEncodingParameters[0].rtx={ssrc:transceiver.sendEncodingParameters[0].ssrc+1};}}} +var commonCapabilities=getCommonCapabilities(transceiver.localCapabilities,transceiver.remoteCapabilities);var hasRtx=commonCapabilities.codecs.filter(function(c){return c.name.toLowerCase()==='rtx';}).length;if(!hasRtx&&transceiver.sendEncodingParameters[0].rtx){delete transceiver.sendEncodingParameters[0].rtx;} +sdp+=writeMediaSection(transceiver,commonCapabilities,'answer',transceiver.stream,pc._dtlsRole);if(transceiver.rtcpParameters&&transceiver.rtcpParameters.reducedSize){sdp+='a=rtcp-rsize\r\n';}});var desc=new window.RTCSessionDescription({type:'answer',sdp:sdp});return Promise.resolve(desc);};RTCPeerConnection.prototype.addIceCandidate=function(candidate){var pc=this;var sections;if(candidate&&!(candidate.sdpMLineIndex!==undefined||candidate.sdpMid)){return Promise.reject(new TypeError('sdpMLineIndex or sdpMid required'));} +return new Promise(function(resolve,reject){if(!pc._remoteDescription){return reject(makeError('InvalidStateError','Can not add ICE candidate without a remote description'));}else if(!candidate||candidate.candidate===''){for(var j=0;j0?SDPUtils.parseCandidate(candidate.candidate):{};if(cand.protocol==='tcp'&&(cand.port===0||cand.port===9)){return resolve();} +if(cand.component&&cand.component!==1){return resolve();} +if(sdpMLineIndex===0||(sdpMLineIndex>0&&transceiver.iceTransport!==pc.transceivers[0].iceTransport)){if(!maybeAddCandidate(transceiver.iceTransport,cand)){return reject(makeError('OperationError','Can not add ICE candidate'));}} +var candidateString=candidate.candidate.trim();if(candidateString.indexOf('a=')===0){candidateString=candidateString.substr(2);} +sections=SDPUtils.getMediaSections(pc._remoteDescription.sdp);sections[sdpMLineIndex]+='a='+ +(cand.type?candidateString:'end-of-candidates') ++'\r\n';pc._remoteDescription.sdp=SDPUtils.getDescription(pc._remoteDescription.sdp)+ +sections.join('');}else{return reject(makeError('OperationError','Can not add ICE candidate'));}} +resolve();});};RTCPeerConnection.prototype.getStats=function(selector){if(selector&&selector instanceof window.MediaStreamTrack){var senderOrReceiver=null;this.transceivers.forEach(function(transceiver){if(transceiver.rtpSender&&transceiver.rtpSender.track===selector){senderOrReceiver=transceiver.rtpSender;}else if(transceiver.rtpReceiver&&transceiver.rtpReceiver.track===selector){senderOrReceiver=transceiver.rtpReceiver;}});if(!senderOrReceiver){throw makeError('InvalidAccessError','Invalid selector.');} +return senderOrReceiver.getStats();} +var promises=[];this.transceivers.forEach(function(transceiver){['rtpSender','rtpReceiver','iceGatherer','iceTransport','dtlsTransport'].forEach(function(method){if(transceiver[method]){promises.push(transceiver[method].getStats());}});});return Promise.all(promises).then(function(allStats){var results=new Map();allStats.forEach(function(stats){stats.forEach(function(stat){results.set(stat.id,stat);});});return results;});};var ortcObjects=['RTCRtpSender','RTCRtpReceiver','RTCIceGatherer','RTCIceTransport','RTCDtlsTransport'];ortcObjects.forEach(function(ortcObjectName){var obj=window[ortcObjectName];if(obj&&obj.prototype&&obj.prototype.getStats){var nativeGetstats=obj.prototype.getStats;obj.prototype.getStats=function(){return nativeGetstats.apply(this).then(function(nativeStats){var mapStats=new Map();Object.keys(nativeStats).forEach(function(id){nativeStats[id].type=fixStatsType(nativeStats[id]);mapStats.set(id,nativeStats[id]);});return mapStats;});};}});var methods=['createOffer','createAnswer'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[0]==='function'||typeof args[1]==='function'){return nativeMethod.apply(this,[arguments[2]]).then(function(description){if(typeof args[0]==='function'){args[0].apply(null,[description]);}},function(error){if(typeof args[1]==='function'){args[1].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});methods=['setLocalDescription','setRemoteDescription','addIceCandidate'];methods.forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'||typeof args[2]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}},function(error){if(typeof args[2]==='function'){args[2].apply(null,[error]);}});} +return nativeMethod.apply(this,arguments);};});['getStats'].forEach(function(method){var nativeMethod=RTCPeerConnection.prototype[method];RTCPeerConnection.prototype[method]=function(){var args=arguments;if(typeof args[1]==='function'){return nativeMethod.apply(this,arguments).then(function(){if(typeof args[1]==='function'){args[1].apply(null);}});} +return nativeMethod.apply(this,arguments);};});return RTCPeerConnection;};},{"sdp":17}],17:[function(require,module,exports){'use strict';var SDPUtils={};SDPUtils.generateIdentifier=function(){return Math.random().toString(36).substr(2,10);};SDPUtils.localCName=SDPUtils.generateIdentifier();SDPUtils.splitLines=function(blob){return blob.trim().split('\n').map(function(line){return line.trim();});};SDPUtils.splitSections=function(blob){var parts=blob.split('\nm=');return parts.map(function(part,index){return(index>0?'m='+part:part).trim()+'\r\n';});};SDPUtils.getDescription=function(blob){var sections=SDPUtils.splitSections(blob);return sections&§ions[0];};SDPUtils.getMediaSections=function(blob){var sections=SDPUtils.splitSections(blob);sections.shift();return sections;};SDPUtils.matchPrefix=function(blob,prefix){return SDPUtils.splitLines(blob).filter(function(line){return line.indexOf(prefix)===0;});};SDPUtils.parseCandidate=function(line){var parts;if(line.indexOf('a=candidate:')===0){parts=line.substring(12).split(' ');}else{parts=line.substring(10).split(' ');} +var candidate={foundation:parts[0],component:parseInt(parts[1],10),protocol:parts[2].toLowerCase(),priority:parseInt(parts[3],10),ip:parts[4],address:parts[4],port:parseInt(parts[5],10),type:parts[7]};for(var i=8;i0?parts[0].split('/')[1]:'sendrecv',uri:parts[1]};};SDPUtils.writeExtmap=function(headerExtension){return'a=extmap:'+(headerExtension.id||headerExtension.preferredId)+ +(headerExtension.direction&&headerExtension.direction!=='sendrecv'?'/'+headerExtension.direction:'')+' '+headerExtension.uri+'\r\n';};SDPUtils.parseFmtp=function(line){var parsed={};var kv;var parts=line.substr(line.indexOf(' ')+1).split(';');for(var j=0;j-1){parts.attribute=line.substr(sp+1,colon-sp-1);parts.value=line.substr(colon+1);}else{parts.attribute=line.substr(sp+1);} +return parts;};SDPUtils.parseSsrcGroup=function(line){var parts=line.substr(13).split(' ');return{semantics:parts.shift(),ssrcs:parts.map(function(ssrc){return parseInt(ssrc,10);})};};SDPUtils.getMid=function(mediaSection){var mid=SDPUtils.matchPrefix(mediaSection,'a=mid:')[0];if(mid){return mid.substr(6);}};SDPUtils.parseFingerprint=function(line){var parts=line.substr(14).split(' ');return{algorithm:parts[0].toLowerCase(),value:parts[1]};};SDPUtils.getDtlsParameters=function(mediaSection,sessionpart){var lines=SDPUtils.matchPrefix(mediaSection+sessionpart,'a=fingerprint:');return{role:'auto',fingerprints:lines.map(SDPUtils.parseFingerprint)};};SDPUtils.writeDtlsParameters=function(params,setupType){var sdp='a=setup:'+setupType+'\r\n';params.fingerprints.forEach(function(fp){sdp+='a=fingerprint:'+fp.algorithm+' '+fp.value+'\r\n';});return sdp;};SDPUtils.getIceParameters=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);lines=lines.concat(SDPUtils.splitLines(sessionpart));var iceParameters={usernameFragment:lines.filter(function(line){return line.indexOf('a=ice-ufrag:')===0;})[0].substr(12),password:lines.filter(function(line){return line.indexOf('a=ice-pwd:')===0;})[0].substr(10)};return iceParameters;};SDPUtils.writeIceParameters=function(params){return'a=ice-ufrag:'+params.usernameFragment+'\r\n'+'a=ice-pwd:'+params.password+'\r\n';};SDPUtils.parseRtpParameters=function(mediaSection){var description={codecs:[],headerExtensions:[],fecMechanisms:[],rtcp:[]};var lines=SDPUtils.splitLines(mediaSection);var mline=lines[0].split(' ');for(var i=3;i0?'9':'0';sdp+=' UDP/TLS/RTP/SAVPF ';sdp+=caps.codecs.map(function(codec){if(codec.preferredPayloadType!==undefined){return codec.preferredPayloadType;} +return codec.payloadType;}).join(' ')+'\r\n';sdp+='c=IN IP4 0.0.0.0\r\n';sdp+='a=rtcp:9 IN IP4 0.0.0.0\r\n';caps.codecs.forEach(function(codec){sdp+=SDPUtils.writeRtpMap(codec);sdp+=SDPUtils.writeFmtp(codec);sdp+=SDPUtils.writeRtcpFb(codec);});var maxptime=0;caps.codecs.forEach(function(codec){if(codec.maxptime>maxptime){maxptime=codec.maxptime;}});if(maxptime>0){sdp+='a=maxptime:'+maxptime+'\r\n';} +sdp+='a=rtcp-mux\r\n';if(caps.headerExtensions){caps.headerExtensions.forEach(function(extension){sdp+=SDPUtils.writeExtmap(extension);});} +return sdp;};SDPUtils.parseRtpEncodingParameters=function(mediaSection){var encodingParameters=[];var description=SDPUtils.parseRtpParameters(mediaSection);var hasRed=description.fecMechanisms.indexOf('RED')!==-1;var hasUlpfec=description.fecMechanisms.indexOf('ULPFEC')!==-1;var ssrcs=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(parts){return parts.attribute==='cname';});var primarySsrc=ssrcs.length>0&&ssrcs[0].ssrc;var secondarySsrc;var flows=SDPUtils.matchPrefix(mediaSection,'a=ssrc-group:FID').map(function(line){var parts=line.substr(17).split(' ');return parts.map(function(part){return parseInt(part,10);});});if(flows.length>0&&flows[0].length>1&&flows[0][0]===primarySsrc){secondarySsrc=flows[0][1];} +description.codecs.forEach(function(codec){if(codec.name.toUpperCase()==='RTX'&&codec.parameters.apt){var encParam={ssrc:primarySsrc,codecPayloadType:parseInt(codec.parameters.apt,10)};if(primarySsrc&&secondarySsrc){encParam.rtx={ssrc:secondarySsrc};} +encodingParameters.push(encParam);if(hasRed){encParam=JSON.parse(JSON.stringify(encParam));encParam.fec={ssrc:primarySsrc,mechanism:hasUlpfec?'red+ulpfec':'red'};encodingParameters.push(encParam);}}});if(encodingParameters.length===0&&primarySsrc){encodingParameters.push({ssrc:primarySsrc});} +var bandwidth=SDPUtils.matchPrefix(mediaSection,'b=');if(bandwidth.length){if(bandwidth[0].indexOf('b=TIAS:')===0){bandwidth=parseInt(bandwidth[0].substr(7),10);}else if(bandwidth[0].indexOf('b=AS:')===0){bandwidth=parseInt(bandwidth[0].substr(5),10)*1000*0.95 +-(50*40*8);}else{bandwidth=undefined;} +encodingParameters.forEach(function(params){params.maxBitrate=bandwidth;});} +return encodingParameters;};SDPUtils.parseRtcpParameters=function(mediaSection){var rtcpParameters={};var remoteSsrc=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(obj){return obj.attribute==='cname';})[0];if(remoteSsrc){rtcpParameters.cname=remoteSsrc.value;rtcpParameters.ssrc=remoteSsrc.ssrc;} +var rsize=SDPUtils.matchPrefix(mediaSection,'a=rtcp-rsize');rtcpParameters.reducedSize=rsize.length>0;rtcpParameters.compound=rsize.length===0;var mux=SDPUtils.matchPrefix(mediaSection,'a=rtcp-mux');rtcpParameters.mux=mux.length>0;return rtcpParameters;};SDPUtils.parseMsid=function(mediaSection){var parts;var spec=SDPUtils.matchPrefix(mediaSection,'a=msid:');if(spec.length===1){parts=spec[0].substr(7).split(' ');return{stream:parts[0],track:parts[1]};} +var planB=SDPUtils.matchPrefix(mediaSection,'a=ssrc:').map(function(line){return SDPUtils.parseSsrcMedia(line);}).filter(function(msidParts){return msidParts.attribute==='msid';});if(planB.length>0){parts=planB[0].value.split(' ');return{stream:parts[0],track:parts[1]};}};SDPUtils.generateSessionId=function(){return Math.random().toString().substr(2,21);};SDPUtils.writeSessionBoilerplate=function(sessId,sessVer,sessUser){var sessionId;var version=sessVer!==undefined?sessVer:2;if(sessId){sessionId=sessId;}else{sessionId=SDPUtils.generateSessionId();} +var user=sessUser||'thisisadapterortc';return'v=0\r\n'+'o='+user+' '+sessionId+' '+version+' IN IP4 127.0.0.1\r\n'+'s=-\r\n'+'t=0 0\r\n';};SDPUtils.writeMediaSection=function(transceiver,caps,type,stream){var sdp=SDPUtils.writeRtpDescription(transceiver.kind,caps);sdp+=SDPUtils.writeIceParameters(transceiver.iceGatherer.getLocalParameters());sdp+=SDPUtils.writeDtlsParameters(transceiver.dtlsTransport.getLocalParameters(),type==='offer'?'actpass':'active');sdp+='a=mid:'+transceiver.mid+'\r\n';if(transceiver.direction){sdp+='a='+transceiver.direction+'\r\n';}else if(transceiver.rtpSender&&transceiver.rtpReceiver){sdp+='a=sendrecv\r\n';}else if(transceiver.rtpSender){sdp+='a=sendonly\r\n';}else if(transceiver.rtpReceiver){sdp+='a=recvonly\r\n';}else{sdp+='a=inactive\r\n';} +if(transceiver.rtpSender){var msid='msid:'+stream.id+' '+ +transceiver.rtpSender.track.id+'\r\n';sdp+='a='+msid;sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' '+msid;if(transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' '+msid;sdp+='a=ssrc-group:FID '+ +transceiver.sendEncodingParameters[0].ssrc+' '+ +transceiver.sendEncodingParameters[0].rtx.ssrc+'\r\n';}} +sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].ssrc+' cname:'+SDPUtils.localCName+'\r\n';if(transceiver.rtpSender&&transceiver.sendEncodingParameters[0].rtx){sdp+='a=ssrc:'+transceiver.sendEncodingParameters[0].rtx.ssrc+' cname:'+SDPUtils.localCName+'\r\n';} +return sdp;};SDPUtils.getDirection=function(mediaSection,sessionpart){var lines=SDPUtils.splitLines(mediaSection);for(var i=0;iai_addr->sa_family != AF_INET) { + freeaddrinfo(ai); exit(1); } + freeaddrinfo(ai); exit(0); } ],[ @@ -92,12 +95,15 @@ AC_DEFUN([APR_CHECK_GETADDRINFO_ADDRCONFIG], [ int main(int argc, char **argv) { struct addrinfo hints, *ai; + int ret; memset(&hints, 0, sizeof(hints)); hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; hints.ai_flags = AI_ADDRCONFIG; - return getaddrinfo("localhost", NULL, &hints, &ai) != 0; + ret = getaddrinfo("localhost", NULL, &hints, &ai) != 0; + freeaddrinfo(ai); + return ret; }], [apr_cv_gai_addrconfig=yes], [apr_cv_gai_addrconfig=no], [apr_cv_gai_addrconfig=no])]) diff --git a/libs/libdingaling/configure.ac b/libs/libdingaling/configure.ac index 57aa712c84..0d7e832fa1 100755 --- a/libs/libdingaling/configure.ac +++ b/libs/libdingaling/configure.ac @@ -136,7 +136,6 @@ AC_STRUCT_TM # Checks for library functions. AC_PROG_GCC_TRADITIONAL -AC_FUNC_MALLOC AC_TYPE_SIGNAL AC_FUNC_STRFTIME #AC_CHECK_FUNCS([gethostname gettimeofday localtime_r memmove memset socket strcasecmp strchr strdup strncasecmp strstr]) diff --git a/libs/libteletone/src/libteletone_detect.c b/libs/libteletone/src/libteletone_detect.c index f25fea73ff..7debc553dd 100644 --- a/libs/libteletone/src/libteletone_detect.c +++ b/libs/libteletone/src/libteletone_detect.c @@ -317,11 +317,10 @@ TELETONE_API(teletone_hit_type_t) teletone_dtmf_detect (teletone_dtmf_detect_sta int sample; int best_row; int best_col; - char hit; + char hit = 0; int limit; teletone_hit_type_t r = 0; - hit = 0; for (sample = 0; sample < samples; sample = limit) { /* BLOCK_LEN is optimised to meet the DTMF specs. */ if ((samples - sample) >= (BLOCK_LEN - dtmf_detect_state->current_sample)) { diff --git a/libs/libteletone/src/libteletone_generate.c b/libs/libteletone/src/libteletone_generate.c index f052c1fe9e..94ae14d228 100644 --- a/libs/libteletone/src/libteletone_generate.c +++ b/libs/libteletone/src/libteletone_generate.c @@ -256,7 +256,9 @@ TELETONE_API(int) teletone_mux_tones(teletone_generation_session_t *ts, teletone int32_t s = teletone_dds_state_modulate_sample(&tones[i], 0); sample += s; } - sample /= freqlen; + if (freqlen) { + sample /= freqlen; + } ts->buffer[ts->samples] = (teletone_audio_t)sample; for (c = 1; c < ts->channels; c++) { diff --git a/libs/libzrtp/configure.ac b/libs/libzrtp/configure.ac index 251c51acc1..5ac158109c 100644 --- a/libs/libzrtp/configure.ac +++ b/libs/libzrtp/configure.ac @@ -66,7 +66,6 @@ AC_CHECK_TYPES([int8_t,uint8_t,int16_t,uint16_t,int32_t,uint32_t,uint64_t,int64_ AC_C_CONST # Checks for library functions. -AC_FUNC_MALLOC AC_CHECK_FUNCS([memset memcpy malloc free]) AC_CHECK_FUNCS([usleep nanosleep]) AC_CHECK_FUNCS([fopen fread]) diff --git a/libs/sofia-sip/.update b/libs/sofia-sip/.update index e94c5432f4..ec04f46051 100644 --- a/libs/sofia-sip/.update +++ b/libs/sofia-sip/.update @@ -1 +1 @@ -Wed Feb 21 15:29:04 CST 2018 +Mon Feb 18 16:55:02 EST 2019 diff --git a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c index d9261324d5..21c3d65af1 100644 --- a/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c +++ b/libs/sofia-sip/libsofia-sip-ua/nua/nua_session.c @@ -940,12 +940,12 @@ static int nua_session_client_response(nua_client_request_t *cr, char const *received = NULL; #define LOG3(m) \ - SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s\n", \ + SU_DEBUG_3(("nua(%p): %s: %s %s in %u %s (%u)\n", \ (void *)nh, cr->cr_method_name, (m), \ - received ? received : "SDP", status, phrase)) + received ? received : "SDP", status, phrase, cr->cr_answer_recv)) #define LOG5(m) \ - SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s\n", \ - (void *)nh, cr->cr_method_name, (m), received, status, phrase)) + SU_DEBUG_5(("nua(%p): %s: %s %s in %u %s (%u)\n", \ + (void *)nh, cr->cr_method_name, (m), received, status, phrase, cr->cr_answer_recv)) retry: @@ -954,12 +954,16 @@ static int nua_session_client_response(nua_client_request_t *cr, else if (!session_get_description(sip, &sdp, &len)) /* No SDP */; else if (cr->cr_answer_recv) { - /* Ignore spurious answers after completing O/A */ - //LOG3("ignoring duplicate"); - //sdp = NULL; - // we need to make sure its *actually* a dup, so we can't assume for now. - cr->cr_answer_recv = 0; - goto retry; + if (cr->cr_answer_recv > status) { + LOG3("status is older than previous answer, ignoring"); + sdp = NULL; + return 0; + } else { + // we need to make sure its *actually* a dup, so we can't assume for now. + LOG3("multiple answers received, processing"); + cr->cr_answer_recv = 0; + goto retry; + } } else if (cr->cr_offer_sent) { /* case 1: answer to our offer */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c index 3b1190ee5f..bb9221f109 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c +++ b/libs/sofia-sip/libsofia-sip-ua/sdp/sdp_parse.c @@ -1546,7 +1546,7 @@ static void parse_payload(sdp_parser_t *p, char *r, sdp_rtpmap_t **result) else if (p->pr_config && r[0] == '*' && (r[1] == ' ' || r[1] == '\0')) { PARSE_ALLOC(p, sdp_rtpmap_t, rm); - *result = rm; result = &rm->rm_next; + *result = rm; rm->rm_predef = 1; rm->rm_any = 1; diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c index f75da713eb..2ea82963e6 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_status.c @@ -104,6 +104,7 @@ char const sip_603_Decline[] = "Decline", sip_604_Does_not_exist_anywhere[] = "Does Not Exist Anywhere", sip_606_Not_acceptable[] = "Not Acceptable", + sip_607_Unwanted[] = "Unwanted", sip_687_Dialog_terminated[] = "Dialog Terminated" ; @@ -191,6 +192,7 @@ char const *sip_status_phrase(int status) case 603: return sip_603_Decline; case 604: return sip_604_Does_not_exist_anywhere; case 606: return sip_606_Not_acceptable; + case 607: return sip_607_Unwanted; case 687: return sip_687_Dialog_terminated; } diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c index 051ba5ae39..e5ef095eb0 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sip_util.c @@ -1422,6 +1422,15 @@ int sip_response_terminates_dialog(int response_code, */ *return_graceful_terminate_usage = 0; return 0; + + case 607: /** @par 607 Unwanted + + This response is similar to 603, except it informs the caller + that the call is unwanted and may be blacklisted. Added by + RFC-8197 + */ + *return_graceful_terminate_usage = 0; + return 0; } /* Do not change graceful_terminate */ diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h index c5a738927f..b10d165e3a 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h +++ b/libs/sofia-sip/libsofia-sip-ua/sip/sofia-sip/sip_status.h @@ -169,6 +169,8 @@ SOFIAPUBFUN char const *sip_status_phrase(int status); #define SIP_604_DOES_NOT_EXIST_ANYWHERE 604, sip_604_Does_not_exist_anywhere /** 606 Not Acceptable @HIDE */ #define SIP_606_NOT_ACCEPTABLE 606, sip_606_Not_acceptable +/** 607 Unwanted @HIDE */ +#define SIP_607_UNWANTED 607, sip_607_Unwanted /** 687 Dialog terminated @HIDE */ #define SIP_687_DIALOG_TERMINATED 687, sip_687_Dialog_terminated @@ -238,6 +240,7 @@ SOFIAPUBVAR char const sip_600_Busy_everywhere[]; SOFIAPUBVAR char const sip_603_Decline[]; SOFIAPUBVAR char const sip_604_Does_not_exist_anywhere[]; SOFIAPUBVAR char const sip_606_Not_acceptable[]; +SOFIAPUBVAR char const sip_607_Unwanted[]; SOFIAPUBVAR char const sip_687_Dialog_terminated[]; SOFIA_END_DECLS diff --git a/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c b/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c index 2927380728..00514fbd2c 100644 --- a/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c +++ b/libs/sofia-sip/libsofia-sip-ua/sip/torture_sip.c @@ -1511,6 +1511,7 @@ static int response_phrase_test(void) { SIP_603_DECLINE }, { SIP_604_DOES_NOT_EXIST_ANYWHERE }, { SIP_606_NOT_ACCEPTABLE }, + { SIP_607_UNWANTED }, { 0, NULL } }; int i; diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c index 1c889da5f6..53dea29060 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_logging.c @@ -386,7 +386,7 @@ void tport_dump_iovec(tport_t const *self, msg_t *msg, size_t len = iov[i].mv_len; if (len > n) len = n; - if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != len) + if (fwrite(iov[i].mv_base, len, 1, mr->mr_dump_file) != 1) break; n -= len; } @@ -732,7 +732,7 @@ int tport_capt_msg_hepv3 (tport_t const *self, msg_t *msg, size_t n, /* Capture ID */ hg->capt_id.chunk.vendor_id = htons(0x0000); hg->capt_id.chunk.type_id = htons(0x000c); - hg->capt_id.data = htons(mr->mr_agent_id); + hg->capt_id.data = htonl(mr->mr_agent_id); hg->capt_id.chunk.length = htons(sizeof(hg->capt_id)); diff --git a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c index 6165c73fec..a9dd26cf0c 100644 --- a/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c +++ b/libs/sofia-sip/libsofia-sip-ua/tport/tport_type_tls.c @@ -468,6 +468,9 @@ int tport_tls_recv(tport_t *self) if (self->tp_master->mr_dump_file) tport_dump_iovec(self, msg, n, iovec, veclen, "recv", "from"); + if (self->tp_master->mr_capt_sock) + tport_capt_msg(self, msg, n, iovec, veclen, "recv"); + /* Mark buffer as used */ msg_recv_commit(msg, N, 0); diff --git a/libs/spandsp/configure.ac b/libs/spandsp/configure.ac index baef75ef69..92354bd246 100644 --- a/libs/spandsp/configure.ac +++ b/libs/spandsp/configure.ac @@ -154,11 +154,6 @@ AC_FUNC_VPRINTF AC_FUNC_MEMCMP AC_FUNC_MEMMOVE -if test "${ax_cv_c_compiler_vendor}" = "gnu" - then - AC_FUNC_REALLOC - AC_FUNC_MALLOC -fi AC_FUNC_SELECT_ARGTYPES AX_C99_FUNC_LRINT diff --git a/libs/unimrcp/configure.ac b/libs/unimrcp/configure.ac index b13c0fab4c..851f56d71b 100644 --- a/libs/unimrcp/configure.ac +++ b/libs/unimrcp/configure.ac @@ -190,6 +190,18 @@ AC_ARG_ENABLE(test-suites, [enable_test_suites="$enableval"], [enable_test_suites="no"]) +# Enable clang address sanitizer bit build +AC_ARG_ENABLE(address_sanitizer, + [AC_HELP_STRING([--enable-address-sanitizer],[build with address sanitizer])], + [enable_address_sanitizer="$enable_address_sanitizer"], + [enable_address_sanitizer="no"]) + +if test "${enable_address_sanitizer}" = "yes"; then + APR_ADDTO(CFLAGS, -fsanitize=address -fno-omit-frame-pointer) + APR_ADDTO(CXXFLAGS, -fsanitize=address -fno-omit-frame-pointer) + APR_ADDTO(LDFLAGS, -fsanitize=address) +fi + AM_CONDITIONAL([TEST_SUITES],[test "${enable_test_suites}" != "no"]) AM_CONDITIONAL(ISMAC, [test `uname -s` = Darwin]) diff --git a/libs/win32/ffmpeg/ffmpeg.2017.vcxproj b/libs/win32/ffmpeg/ffmpeg.2017.vcxproj index a8c70cd22a..82a1d67c45 100644 --- a/libs/win32/ffmpeg/ffmpeg.2017.vcxproj +++ b/libs/win32/ffmpeg/ffmpeg.2017.vcxproj @@ -1,12 +1,20 @@ - - Debug + + Debug-openh264 x64 - - Release + + Debug-x264 + x64 + + + Release-openh264 + x64 + + + Release-x264 x64 @@ -16,39 +24,55 @@ 10.0.17134.0 {BC1FD72E-1CD5-4525-A7F5-17C5740BFDED} - + + - + StaticLibrary v141 MultiByte false yasm.exe -f x64 -I./../../ffmpeg-$(ffmpegVersion)/ -I./../../ffmpeg-$(ffmpegVersion)/include_x64 -P.\..\..\libs\ffmpeg-$(ffmpegVersion)\include_x64\config.asm - + StaticLibrary v141 MultiByte yasm.exe -f x64 -I./../../ffmpeg-$(ffmpegVersion)/ -I./../../ffmpeg-$(ffmpegVersion)/include_x64 -P.\..\..\libs\ffmpeg-$(ffmpegVersion)\include_x64\config.asm - + + StaticLibrary v141 + MultiByte + false + yasm.exe -f x64 -I./../../ffmpeg-$(ffmpegVersion)/ -I./../../ffmpeg-$(ffmpegVersion)/include_openh264_x64 -P.\..\..\libs\ffmpeg-$(ffmpegVersion)\include_openh264_x64\config.asm - + + StaticLibrary v141 + MultiByte + yasm.exe -f x64 -I./../../ffmpeg-$(ffmpegVersion)/ -I./../../ffmpeg-$(ffmpegVersion)/include_openh264_x64 -P.\..\..\libs\ffmpeg-$(ffmpegVersion)\include_openh264_x64\config.asm - + - + + + + + + + + + @@ -57,7 +81,7 @@ BUILDING_avdevice;BUILDING_avfilter;BUILDING_avformat;BUILDING_avcodec;BUILDING_avresample;BUILDING_swresample;BUILDING_swscale;BUILDING_avutil;%(PreprocessorDefinitions) - + X64 @@ -75,7 +99,25 @@ true - + + + X64 + + + MaxSpeed + "..\..\ffmpeg-$(ffmpegVersion)\include_openh264_x64";"..\..\ffmpeg-$(ffmpegVersion)";"..\..\libx264";"..\..\libx264\SMP";%(AdditionalIncludeDirectories) + WIN32;_DEBUG;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + false + NotUsing + false + 4267;4334;4101;4018;4146;4244;4305;4554;%(DisableSpecificWarnings) + true + true + + + X64 @@ -93,5410 +135,5437 @@ Full + + + X64 + + + "..\..\ffmpeg-$(ffmpegVersion)\include_openh264_x64";"..\..\ffmpeg-$(ffmpegVersion)";"..\..\libx264";"..\..\libx264\SMP";%(AdditionalIncludeDirectories) + WIN32;NDEBUG;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + false + NotUsing + false + 4267;4334;4101;4018;4146;4244;4305;4554;%(DisableSpecificWarnings) + true + true + Full + + <_ProjectFileVersion>10.0.30319.1 - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ Assembling %(Filename)%(Extension) @@ -5504,7 +5573,7 @@ $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ Assembling %(Filename)%(Extension) @@ -5512,7 +5581,7 @@ $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ Assembling %(Filename)%(Extension) @@ -5520,7 +5589,7 @@ $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj - $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ Assembling %(Filename)%(Extension) @@ -6027,7 +6096,7 @@ $(YasmCommand) -I %(RelativeDir) -o $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj "%(FullPath)" $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj - + Assembling %(Filename)%(Extension) $(YasmCommand) -I %(RelativeDir) -o $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj "%(FullPath)" $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj @@ -6173,11 +6242,17 @@ $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_')).%(FileName).obj - - - {20179127-853b-4fe9-b7c0-9e817e6a3a72} - - + + + + + {20179127-853b-4fe9-b7c0-9e817e6a3a72} + + + + + + diff --git a/libs/win32/libvpx/libvpx.2017.vcxproj b/libs/win32/libvpx/libvpx.2017.vcxproj index 95942997c8..17e841c345 100644 --- a/libs/win32/libvpx/libvpx.2017.vcxproj +++ b/libs/win32/libvpx/libvpx.2017.vcxproj @@ -1,1552 +1,1556 @@ - - - - - Debug - Win32 - - - Release - Win32 - - - Debug - x64 - - - Release - x64 - - - - libvpx - {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} - libvpx - ManagedCProj - - - - - StaticLibrary - v141 - Unicode - true - - - StaticLibrary - v141 - Unicode - - - StaticLibrary - v141 - Unicode - true - - - StaticLibrary - v141 - Unicode - - - - - - - - - - - - - - - - Disabled - ".";".\include_x86";"../../libvpx";%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) - MultiThreadedDebug - Level3 - false - NotUsing - false - - - - - Speed - MaxSpeed - ".";".\include_x86";"../../libvpx";%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) - MultiThreaded - Level3 - false - NotUsing - false - - - - - - - - - - - - - Disabled - ".";".\include_x64";"..\..\libvpx";%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) - MultiThreadedDebug - Level3 - false - NotUsing - false - - - - - Speed - MaxSpeed - ".";".\include_x64";"..\..\libvpx";%(AdditionalIncludeDirectories) - WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) - MultiThreaded - Level3 - false - NotUsing - false - - - - - $(IntDir)vpx_src_vpx_decoder.obj - - - $(IntDir)vpx_src_vpx_encoder.obj - - - $(IntDir)vpx_src_vpx_codec.obj - - - $(IntDir)vpx_src_vpx_image.obj - - - $(IntDir)vpx_mem_vpx_mem.obj - - - $(IntDir)vpx_scale_generic_vpx_scale.obj - - - $(IntDir)vpx_scale_generic_yv12config.obj - - - $(IntDir)vpx_scale_generic_yv12extend.obj - - - $(IntDir)vpx_scale_generic_gen_scalers.obj - - - $(IntDir)vpx_scale_vpx_scale_rtcd.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj - $(IntDir)vpx_ports_emms_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj - $(IntDir)vpx_ports_emms_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj - $(IntDir)vpx_ports_emms_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj - $(IntDir)vpx_ports_emms_asm.obj - - - $(IntDir)vpx_dsp_prob.obj - - - $(IntDir)vpx_dsp_bitwriter.obj - - - $(IntDir)vpx_dsp_bitwriter_buffer.obj - - - $(IntDir)vpx_dsp_psnr.obj - - - $(IntDir)vpx_dsp_bitreader.obj - - - $(IntDir)vpx_dsp_bitreader_buffer.obj - - - $(IntDir)vpx_dsp_intrapred.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj - - - $(IntDir)vpx_dsp_add_noise.obj - - - $(IntDir)vpx_dsp_deblock.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj - - - $(IntDir)vpx_dsp_vpx_convolve.obj - - - $(IntDir)vpx_dsp_x86_vpx_asm_stubs.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj - - - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_intrin_avx2.obj - /arch:AVX - - - $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_intrin_ssse3.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj - - - $(IntDir)vpx_dsp_loopfilter.obj - - - $(IntDir)vpx_dsp_x86_loopfilter_sse2.obj - - - $(IntDir)vpx_dsp_x86_loopfilter_avx2.obj - /arch:AVX - - - $(IntDir)vpx_dsp_fwd_txfm.obj - - - $(IntDir)vpx_dsp_x86_fwd_txfm_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj - - - $(IntDir)vpx_dsp_x86_fwd_txfm_avx2.obj - /arch:AVX - - - $(IntDir)vpx_dsp_inv_txfm.obj - - - $(IntDir)vpx_dsp_x86_inv_txfm_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj - - - $(IntDir)vpx_dsp_quantize.obj - - - $(IntDir)vpx_dsp_x86_quantize_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj - - - $(IntDir)vpx_dsp_avg.obj - - - $(IntDir)vpx_dsp_x86_avg_intrin_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj - - - $(IntDir)vpx_dsp_sad.obj - - - $(IntDir)vpx_dsp_subtract.obj - - - $(IntDir)vpx_dsp_sum_squares.obj - - - $(IntDir)vpx_dsp_x86_sum_squares_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj - - - $(IntDir)vpx_dsp_x86_sad4d_avx2.obj - /arch:AVX - - - $(IntDir)vpx_dsp_x86_sad_avx2.obj - /arch:AVX - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj - - - $(IntDir)vpx_dsp_variance.obj - - - $(IntDir)vpx_dsp_x86_variance_sse2.obj - - - $(IntDir)vpx_dsp_x86_variance_avx2.obj - /arch:AVX - - - $(IntDir)vpx_dsp_x86_variance_impl_avx2.obj - /arch:AVX - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj - $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj - - - $(IntDir)vpx_dsp_vpx_dsp_rtcd.obj - - - $(IntDir)vpx_util_vpx_thread.obj - - - $(IntDir)vp8_common_alloccommon.obj - - - $(IntDir)vp8_common_blockd.obj - - - $(IntDir)vp8_common_copy_c.obj - - - $(IntDir)vp8_common_dequantize.obj - - - $(IntDir)vp8_common_entropy.obj - - - $(IntDir)vp8_common_entropymode.obj - - - $(IntDir)vp8_common_entropymv.obj - - - $(IntDir)vp8_common_extend.obj - - - $(IntDir)vp8_common_filter.obj - - - $(IntDir)vp8_common_findnearmv.obj - - - $(IntDir)vp8_common_generic_systemdependent.obj - - - $(IntDir)vp8_common_idct_blk.obj - - - $(IntDir)vp8_common_idctllm.obj - - - $(IntDir)vp8_common_rtcd.obj - - - $(IntDir)vp8_common_vp8_loopfilter.obj - - - $(IntDir)vp8_common_loopfilter_filters.obj - - - $(IntDir)vp8_common_mbpitch.obj - - - $(IntDir)vp8_common_modecont.obj - - - $(IntDir)vp8_common_quant_common.obj - - - $(IntDir)vp8_common_reconinter.obj - - - $(IntDir)vp8_common_reconintra.obj - - - $(IntDir)vp8_common_reconintra4x4.obj - - - $(IntDir)vp8_common_setupintrarecon.obj - - - $(IntDir)vp8_common_swapyv12buffer.obj - - - $(IntDir)vp8_common_treecoder.obj - - - $(IntDir)vp8_common_x86_filter_x86.obj - - - $(IntDir)vp8_common_x86_vp8_asm_stubs.obj - - - $(IntDir)vp8_common_x86_loopfilter_x86.obj - - - $(IntDir)vp8_common_mfqe.obj - - - $(IntDir)vp8_common_postproc.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj - - - $(IntDir)vp8_common_x86_idct_blk_mmx.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj - $(IntDir)vp8_common_x86_recon_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj - $(IntDir)vp8_common_x86_recon_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj - $(IntDir)vp8_common_x86_recon_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj - $(IntDir)vp8_common_x86_recon_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj - $(IntDir)vp8_common_x86_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj - $(IntDir)vp8_common_x86_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj - $(IntDir)vp8_common_x86_copy_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj - $(IntDir)vp8_common_x86_copy_sse2_asm.obj - - - $(IntDir)vp8_common_x86_idct_blk_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj - $(IntDir)vp8_common_x86_recon_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj - $(IntDir)vp8_common_x86_recon_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj - $(IntDir)vp8_common_x86_recon_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj - $(IntDir)vp8_common_x86_recon_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj - $(IntDir)vp8_common_x86_copy_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj - $(IntDir)vp8_common_x86_copy_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj - $(IntDir)vp8_common_x86_copy_sse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj - $(IntDir)vp8_common_x86_copy_sse3_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj - $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj - $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj - - - $(IntDir)vp8_vp8_cx_iface.obj - - - $(IntDir)vp8_encoder_bitstream.obj - - - $(IntDir)vp8_encoder_boolhuff.obj - - - $(IntDir)vp8_encoder_dct.obj - - - $(IntDir)vp8_encoder_encodeframe.obj - - - $(IntDir)vp8_encoder_encodeintra.obj - - - $(IntDir)vp8_encoder_encodemb.obj - - - $(IntDir)vp8_encoder_encodemv.obj - - - $(IntDir)vp8_encoder_ethreading.obj - - - $(IntDir)vp8_encoder_firstpass.obj - - - $(IntDir)vp8_encoder_denoising.obj - - - $(IntDir)vp8_encoder_lookahead.obj - - - $(IntDir)vp8_encoder_mcomp.obj - - - $(IntDir)vp8_encoder_modecosts.obj - - - $(IntDir)vp8_encoder_onyx_if.obj - - - $(IntDir)vp8_encoder_pickinter.obj - - - $(IntDir)vp8_encoder_picklpf.obj - - - $(IntDir)vp8_encoder_vp8_quantize.obj - - - $(IntDir)vp8_encoder_ratectrl.obj - - - $(IntDir)vp8_encoder_rdopt.obj - - - $(IntDir)vp8_encoder_segmentation.obj - - - $(IntDir)vp8_encoder_tokenize.obj - - - $(IntDir)vp8_encoder_treewriter.obj - - - $(IntDir)vp8_encoder_temporal_filter.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj - - - $(IntDir)vp8_encoder_x86_vp8_enc_stubs_mmx.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj - - - $(IntDir)vp8_encoder_x86_vp8_quantize_sse2.obj - - - $(IntDir)vp8_encoder_x86_quantize_ssse3.obj - - - $(IntDir)vp8_encoder_x86_quantize_sse4.obj - - - $(IntDir)vp8_encoder_x86_denoising_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj - - - $(IntDir)vp8_encoder_x86_vp8_enc_stubs_sse2.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - $(IntDir)vp8_encoder_x86_encodeopt_asm.obj - - - $(IntDir)vp8_vp8_dx_iface.obj - - - $(IntDir)vp8_decoder_dboolhuff.obj - - - $(IntDir)vp8_decoder_decodemv.obj - - - $(IntDir)vp8_decoder_decodeframe.obj - - - $(IntDir)vp8_decoder_detokenize.obj - - - $(IntDir)vp8_decoder_onyxd_if.obj - - - $(IntDir)vp8_decoder_threading.obj - - - $(IntDir)vp9_common_vp9_alloccommon.obj - - - $(IntDir)vp9_common_vp9_blockd.obj - - - $(IntDir)vp9_common_vp9_entropy.obj - - - $(IntDir)vp9_common_vp9_entropymode.obj - - - $(IntDir)vp9_common_vp9_entropymv.obj - - - $(IntDir)vp9_common_vp9_frame_buffers.obj - - - $(IntDir)vp9_common_vp9_idct.obj - - - $(IntDir)vp9_common_vp9_filter.obj - - - $(IntDir)vp9_common_vp9_pred_common.obj - - - $(IntDir)vp9_common_vp9_rtcd.obj - - - $(IntDir)vp9_common_vp9_scale.obj - - - $(IntDir)vp9_common_vp9_seg_common.obj - - - $(IntDir)vp9_common_vp9_tile_common.obj - - - $(IntDir)vp9_common_vp9_loopfilter.obj - - - $(IntDir)vp9_common_vp9_thread_common.obj - - - $(IntDir)vp9_common_vp9_mvref_common.obj - - - $(IntDir)vp9_common_vp9_quant_common.obj - - - $(IntDir)vp9_common_vp9_reconinter.obj - - - $(IntDir)vp9_common_vp9_reconintra.obj - - - $(IntDir)vp9_common_vp9_common_data.obj - - - $(IntDir)vp9_common_vp9_scan.obj - - - $(IntDir)vp9_common_x86_vp9_idct_intrin_sse2.obj - - - $(IntDir)vp9_vp9_cx_iface.obj - - - $(IntDir)vp9_encoder_vp9_bitstream.obj - - - $(IntDir)vp9_encoder_vp9_context_tree.obj - - - $(IntDir)vp9_encoder_vp9_cost.obj - - - $(IntDir)vp9_encoder_vp9_dct.obj - - - $(IntDir)vp9_encoder_vp9_encodeframe.obj - - - $(IntDir)vp9_encoder_vp9_encodemb.obj - - - $(IntDir)vp9_encoder_vp9_encodemv.obj - - - $(IntDir)vp9_encoder_vp9_ethread.obj - - - $(IntDir)vp9_encoder_vp9_extend.obj - - - $(IntDir)vp9_encoder_vp9_firstpass.obj - - - $(IntDir)vp9_encoder_vp9_lookahead.obj - - - $(IntDir)vp9_encoder_vp9_mcomp.obj - - - $(IntDir)vp9_encoder_vp9_encoder.obj - - - $(IntDir)vp9_encoder_vp9_picklpf.obj - - - $(IntDir)vp9_encoder_vp9_quantize.obj - - - $(IntDir)vp9_encoder_vp9_ratectrl.obj - - - $(IntDir)vp9_encoder_vp9_rd.obj - - - $(IntDir)vp9_encoder_vp9_rdopt.obj - - - $(IntDir)vp9_encoder_vp9_pickmode.obj - - - $(IntDir)vp9_encoder_vp9_segmentation.obj - - - $(IntDir)vp9_encoder_vp9_speed_features.obj - - - $(IntDir)vp9_encoder_vp9_subexp.obj - - - $(IntDir)vp9_encoder_vp9_svc_layercontext.obj - - - $(IntDir)vp9_encoder_vp9_resize.obj - - - $(IntDir)vp9_encoder_vp9_tokenize.obj - - - $(IntDir)vp9_encoder_vp9_treewriter.obj - - - $(IntDir)vp9_encoder_vp9_aq_variance.obj - - - $(IntDir)vp9_encoder_vp9_aq_360.obj - - - $(IntDir)vp9_encoder_vp9_aq_cyclicrefresh.obj - - - $(IntDir)vp9_encoder_vp9_aq_complexity.obj - - - $(IntDir)vp9_encoder_vp9_alt_ref_aq.obj - - - $(IntDir)vp9_encoder_vp9_skin_detection.obj - - - $(IntDir)vp9_encoder_vp9_noise_estimate.obj - - - $(IntDir)vp9_encoder_vp9_temporal_filter.obj - - - $(IntDir)vp9_encoder_vp9_mbgraph.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj - - - $(IntDir)vp9_encoder_x86_vp9_quantize_sse2.obj - - - $(IntDir)vp9_encoder_x86_vp9_diamond_search_sad_avx.obj - /arch:AVX - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj - - - Assembling %(Filename)%(Extension) - yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj - $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj - Assembling %(Filename)%(Extension) - yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj - $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj - - - $(IntDir)vp9_encoder_x86_vp9_dct_intrin_sse2.obj - - - $(IntDir)vp9_encoder_x86_vp9_dct_ssse3.obj - - - $(IntDir)vp9_encoder_x86_vp9_frame_scale_ssse3.obj - - - $(IntDir)vp9_encoder_x86_vp9_error_intrin_avx2.obj - /arch:AVX - - - $(IntDir)vp9_vp9_dx_iface.obj - - - $(IntDir)vp9_decoder_vp9_decodemv.obj - - - $(IntDir)vp9_decoder_vp9_decodeframe.obj - - - $(IntDir)vp9_decoder_vp9_detokenize.obj - - - $(IntDir)vp9_decoder_vp9_dthread.obj - - - $(IntDir)vp9_decoder_vp9_decoder.obj - - - $(IntDir)vp9_decoder_vp9_dsubexp.obj - - - $(IntDir)vpx_config.obj - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + + Debug + Win32 + + + Release + Win32 + + + Debug + x64 + + + Release + x64 + + + + libvpx + {DCE19DAF-69AC-46DB-B14A-39F0FAA5DB74} + libvpx + ManagedCProj + + + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + + + StaticLibrary + v141 + Unicode + true + + + StaticLibrary + v141 + Unicode + + + + + + + + + + + + + + + + Disabled + ".";".\include_x86";"../../libvpx";%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + false + NotUsing + false + true + + + + + Speed + MaxSpeed + ".";".\include_x86";"../../libvpx";%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) + MultiThreaded + Level3 + false + NotUsing + false + true + + + + + + + + + + + + + Disabled + ".";".\include_x64";"..\..\libvpx";%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) + MultiThreadedDebug + Level3 + false + NotUsing + false + true + + + + + Speed + MaxSpeed + ".";".\include_x64";"..\..\libvpx";%(AdditionalIncludeDirectories) + WIN32;NDEBUG;_CRT_SECURE_NO_WARNINGS;_CRT_SECURE_NO_DEPRECATE;;%(PreprocessorDefinitions) + MultiThreaded + Level3 + false + NotUsing + false + true + + + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj + $(IntDir)vpx_ports_emms_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj + $(IntDir)vpx_ports_emms_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj + $(IntDir)vpx_ports_emms_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_ports_emms_asm.obj + $(IntDir)vpx_ports_emms_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_intrapred_ssse3_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_ssse3_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + $(IntDir)vpx_dsp_x86_add_noise_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + $(IntDir)vpx_dsp_x86_deblock_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_8t_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_vpx_subpixel_bilinear_ssse3_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + $(IntDir)vpx_dsp_x86_vpx_convolve_copy_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_fwd_txfm_ssse3_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + $(IntDir)vpx_dsp_x86_inv_wht_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_inv_txfm_ssse3_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_quantize_ssse3_x86_64_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_quantize_avx_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_avg_ssse3_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse3_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + $(IntDir)vpx_dsp_x86_sad_ssse3_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse4_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad4d_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + $(IntDir)vpx_dsp_x86_sad_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subtract_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj + $(IntDir)vpx_dsp_x86_ssim_opt_x86_64_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + $(IntDir)vpx_dsp_x86_subpel_variance_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + $(IntDir)vp8_common_x86_dequantize_mmx_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + $(IntDir)vp8_common_x86_idctllm_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + $(IntDir)vp8_common_x86_iwalsh_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + $(IntDir)vp8_common_x86_vp8_loopfilter_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj + $(IntDir)vp8_common_x86_recon_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj + $(IntDir)vp8_common_x86_recon_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj + $(IntDir)vp8_common_x86_recon_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_mmx_asm.obj + $(IntDir)vp8_common_x86_recon_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + $(IntDir)vp8_common_x86_subpixel_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj + $(IntDir)vp8_common_x86_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj + $(IntDir)vp8_common_x86_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj + $(IntDir)vp8_common_x86_copy_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse2_asm.obj + $(IntDir)vp8_common_x86_copy_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + $(IntDir)vp8_common_x86_idctllm_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj + $(IntDir)vp8_common_x86_recon_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj + $(IntDir)vp8_common_x86_recon_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj + $(IntDir)vp8_common_x86_recon_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_recon_sse2_asm.obj + $(IntDir)vp8_common_x86_recon_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + $(IntDir)vp8_common_x86_subpixel_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + $(IntDir)vp8_common_x86_loopfilter_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + $(IntDir)vp8_common_x86_iwalsh_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj + $(IntDir)vp8_common_x86_copy_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj + $(IntDir)vp8_common_x86_copy_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj + $(IntDir)vp8_common_x86_copy_sse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_copy_sse3_asm.obj + $(IntDir)vp8_common_x86_copy_sse3_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + $(IntDir)vp8_common_x86_subpixel_ssse3_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + $(IntDir)vp8_common_x86_mfqe_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj + $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj + $(IntDir)vp8_common_x86_loopfilter_block_sse2_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + $(IntDir)vp8_encoder_x86_dct_mmx_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + $(IntDir)vp8_encoder_x86_dct_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + $(IntDir)vp8_encoder_x86_fwalsh_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp8_encoder_x86_temporal_filter_apply_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + $(IntDir)vp8_encoder_x86_quantize_mmx_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + $(IntDir)vp8_encoder_x86_encodeopt_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_temporal_filter_apply_sse2_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_dct_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win32 -I".\include_x86" -I"..\..\libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + $(IntDir)vp9_encoder_x86_vp9_error_sse2_asm.obj + + + Assembling %(Filename)%(Extension) + yasm -Xvc -g cv8 -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj + $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj + Assembling %(Filename)%(Extension) + yasm -Xvc -f win64 -I"./include_x64" -I"../../libvpx" "%(FullPath)" -o $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj + $(IntDir)vp9_encoder_x86_vp9_quantize_ssse3_x86_64_asm.obj + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + /arch:AVX + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + $(IntDir)$([System.String]::Copy(%(RelativeDir)).Replace('\','_'))\ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/scripts/ci/common.sh b/scripts/ci/common.sh index 6158356a1c..cecb1289bc 100755 --- a/scripts/ci/common.sh +++ b/scripts/ci/common.sh @@ -123,11 +123,11 @@ set_fs_ver () { rpm_version="$major.$minor.$micro" fi - sed -e "s|\(%define version \).*|\1$rpm_version|" \ + sed -e "s|\(%define nonparsedversion \).*|\1$rpm_version|" \ freeswitch.spec > freeswitch.spec.$$ mv freeswitch.spec.$$ freeswitch.spec - sed -e "s|\(%define version \).*|\1$rpm_version|" \ + sed -e "s|\(%define nonparsedversion \).*|\1$rpm_version|" \ freeswitch-config-rayo.spec > freeswitch-config-rayo.spec.$$ mv freeswitch-config-rayo.spec.$$ freeswitch-config-rayo.spec diff --git a/scripts/ci/mk-sounds-rpms.sh b/scripts/ci/mk-sounds-rpms.sh index aca867076b..fda715d02a 100755 --- a/scripts/ci/mk-sounds-rpms.sh +++ b/scripts/ci/mk-sounds-rpms.sh @@ -1,7 +1,7 @@ #!/bin/sh ##### -*- mode:shell-script; indent-tabs-mode:nil; sh-basic-offset:2 -*- -declare -a specfiles=('freeswitch-sounds-en-ca-june.spec' 'freeswitch-sounds-fr-ca-june.spec' 'freeswitch-sounds-ru-RU-elena.spec' 'freeswitch-sounds-en-us-callie.spec' 'freeswitch-sounds-sv-se-jakob.spec') +declare -a specfiles=('freeswitch-sounds-en-ca-june.spec' 'freeswitch-sounds-en-us-allison.spec' 'freeswitch-sounds-fr-ca-june.spec' 'freeswitch-sounds-music.spec' 'freeswitch-sounds-pt-BR-karina.spec' 'freeswitch-sounds-ru-RU-elena.spec' 'freeswitch-sounds-en-us-callie.spec' 'freeswitch-sounds-sv-se-jakob.spec') sdir="." [ -n "${0%/*}" ] && sdir="${0%/*}" @@ -15,17 +15,17 @@ basedir=$(pwd); if [ ! -d "$basedir/../freeswitch-sounds" ]; then cd $basedir/.. - git clone https://freeswitch.org/stash/scm/fs/freeswitch-sounds.git + git clone https://freeswitch.org/stash/scm/fs/freeswitch-sounds.git else cd $basedir/../freeswitch-sounds git clean -fdx - git pull + git pull fi for i in "${specfiles[@]}" do -cd $basedir/../freeswitch-sounds/sounds/trunk +cd $basedir/../freeswitch-sounds/ ./dist.pl `echo $i|sed -e 's/freeswitch-sounds-//g' -e 's/\.spec//g' -e 's/-/\//g'` diff --git a/src/include/private/switch_core_pvt.h b/src/include/private/switch_core_pvt.h index 1d61357644..8f8076a5bf 100644 --- a/src/include/private/switch_core_pvt.h +++ b/src/include/private/switch_core_pvt.h @@ -129,6 +129,7 @@ struct switch_core_session { switch_audio_resampler_t *write_resampler; switch_mutex_t *mutex; + switch_mutex_t *stack_count_mutex; switch_mutex_t *resample_mutex; switch_mutex_t *codec_read_mutex; switch_mutex_t *codec_write_mutex; diff --git a/src/include/switch_channel.h b/src/include/switch_channel.h index 8e24893fdc..ec066852c6 100644 --- a/src/include/switch_channel.h +++ b/src/include/switch_channel.h @@ -270,6 +270,9 @@ SWITCH_DECLARE(char *) switch_channel_get_uuid(switch_channel_t *channel); SWITCH_DECLARE(switch_status_t) switch_channel_set_profile_var(switch_channel_t *channel, const char *name, const char *val); +SWITCH_DECLARE(switch_status_t) switch_channel_set_log_tag(switch_channel_t *channel, const char *tagname, const char *tagvalue); +SWITCH_DECLARE(switch_status_t) switch_channel_get_log_tags(switch_channel_t *channel, switch_event_t **log_tags); + SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check); SWITCH_DECLARE(switch_status_t) switch_channel_add_variable_var_check(switch_channel_t *channel, diff --git a/src/include/switch_core.h b/src/include/switch_core.h index 526fe26323..7631fc287f 100644 --- a/src/include/switch_core.h +++ b/src/include/switch_core.h @@ -2427,6 +2427,7 @@ SWITCH_DECLARE(const char *) switch_lookup_timezone(const char *tz_name); SWITCH_DECLARE(switch_status_t) switch_strftime_tz(const char *tz, const char *format, char *date, size_t len, switch_time_t thetime); SWITCH_DECLARE(switch_status_t) switch_time_exp_tz_name(const char *tz, switch_time_exp_t *tm, switch_time_t thetime); SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload); +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_port_token(const char *ip_str, int port, const char *list_name, const char **token); SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token); #define switch_check_network_list_ip(_ip_str, _list_name) switch_check_network_list_ip_token(_ip_str, _list_name, NULL) SWITCH_DECLARE(void) switch_time_set_monotonic(switch_bool_t enable); diff --git a/src/include/switch_core_media.h b/src/include/switch_core_media.h index 1c73c2367a..ef9ddda964 100644 --- a/src/include/switch_core_media.h +++ b/src/include/switch_core_media.h @@ -270,6 +270,10 @@ SWITCH_DECLARE(switch_rtp_stats_t *) switch_core_media_get_stats(switch_core_ses SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, switch_sdp_type_t sdp_type); +SWITCH_DECLARE(void) switch_core_media_merge_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, + switch_sdp_type_t sdp_type, const char *codec_string); + + SWITCH_DECLARE(void) switch_core_media_reset_autofix(switch_core_session_t *session, switch_media_type_t type); SWITCH_DECLARE(void) switch_core_media_check_outgoing_proxy(switch_core_session_t *session, switch_core_session_t *o_session); SWITCH_DECLARE(switch_status_t) switch_core_media_codec_chosen(switch_core_session_t *session, switch_media_type_t media); @@ -381,7 +385,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_print(switch_core_session_t SWITCH_DECLARE(switch_status_t) switch_core_session_printf(switch_core_session_t *session, const char *fmt, ...); SWITCH_DECLARE(switch_msrp_session_t *) switch_core_media_get_msrp_session(switch_core_session_t *session); - +SWITCH_DECLARE(void) switch_core_media_set_smode(switch_core_session_t *session, switch_media_type_t type, switch_media_flow_t smode, switch_sdp_type_t sdp_type); SWITCH_END_EXTERN_C #endif diff --git a/src/include/switch_event.h b/src/include/switch_event.h index 2c6eb48388..50519b8f99 100644 --- a/src/include/switch_event.h +++ b/src/include/switch_event.h @@ -215,7 +215,7 @@ SWITCH_DECLARE(int) switch_event_add_array(switch_event_t *event, const char *va \param event pointer to the pointer to event to destroy */ SWITCH_DECLARE(void) switch_event_destroy(switch_event_t **event); -#define switch_event_safe_destroy(_event) if (_event) switch_event_destroy(_event) +#define switch_event_safe_destroy(_event) if (_event) switch_event_destroy(&_event) /*! \brief Duplicate an event diff --git a/src/include/switch_ivr.h b/src/include/switch_ivr.h index 5a444d552b..69cb038caf 100644 --- a/src/include/switch_ivr.h +++ b/src/include/switch_ivr.h @@ -293,6 +293,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_speech_start_input_timers(swit \return SWITCH_STATUS_SUCCESS if all is well */ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh); +SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh, switch_event_t *variables); SWITCH_DECLARE(switch_status_t) switch_ivr_transfer_recordings(switch_core_session_t *orig_session, switch_core_session_t *new_session); diff --git a/src/include/switch_loadable_module.h b/src/include/switch_loadable_module.h index 9cc99ee0be..87295a641b 100644 --- a/src/include/switch_loadable_module.h +++ b/src/include/switch_loadable_module.h @@ -318,7 +318,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod); \param err pointer to error message \return the status */ -SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, switch_bool_t force, const char **err); +SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(const char *dir, const char *fname, switch_bool_t force, const char **err); /* Prototypes of module interface functions */ @@ -328,7 +328,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, \param filename the path to the module's dll or so file \return SWITCH_STATUS_SUCCESS on a successful load */ -SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(switch_loadable_module_interface_t ** module_interface, char *filename); +SWITCH_MOD_DECLARE(switch_status_t) switch_module_load(switch_loadable_module_interface_t ** module_interface, const char *filename); SWITCH_MOD_DECLARE(switch_status_t) switch_module_runtime(void); /*! diff --git a/src/include/switch_log.h b/src/include/switch_log.h index f0df9d8315..357f20f324 100644 --- a/src/include/switch_log.h +++ b/src/include/switch_log.h @@ -65,6 +65,7 @@ SWITCH_BEGIN_EXTERN_C /* To maintain abi, only add new elements to the end of this struct and do not delete any elements */ switch_text_channel_t channel; switch_log_level_t slevel; + switch_event_t *tags; } switch_log_node_t; typedef switch_status_t (*switch_log_function_t) (const switch_log_node_t *node, switch_log_level_t level); diff --git a/src/include/switch_rtp.h b/src/include/switch_rtp.h index 41e8637683..a16c5f6d5a 100644 --- a/src/include/switch_rtp.h +++ b/src/include/switch_rtp.h @@ -578,7 +578,7 @@ SWITCH_DECLARE(switch_rtp_stats_t *) switch_rtp_get_stats(switch_rtp_t *rtp_sess SWITCH_DECLARE(switch_byte_t) switch_rtp_check_auto_adj(switch_rtp_t *rtp_session); SWITCH_DECLARE(void) switch_rtp_set_interdigit_delay(switch_rtp_t *rtp_session, uint32_t delay); -SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type); +SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type, uint8_t want_DTLSv1_2); SWITCH_DECLARE(switch_status_t) switch_rtp_del_dtls(switch_rtp_t *rtp_session, dtls_type_t type); SWITCH_DECLARE(dtls_state_t) switch_rtp_dtls_state(switch_rtp_t *rtp_session, dtls_type_t type); diff --git a/src/include/switch_ssl.h b/src/include/switch_ssl.h index 3f4d6d696e..f31888b57b 100644 --- a/src/include/switch_ssl.h +++ b/src/include/switch_ssl.h @@ -38,6 +38,7 @@ #endif #include #include +#include #include #include #ifndef OPENSSL_NO_ENGINE diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 926c8a6bea..53c25c395c 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -377,7 +377,9 @@ typedef enum { SCF_DEBUG_SQL = (1 << 21), SCF_API_EXPANSION = (1 << 22), SCF_SESSION_THREAD_POOL = (1 << 23), - SCF_DIALPLAN_TIMESTAMPS = (1 << 24) + SCF_DIALPLAN_TIMESTAMPS = (1 << 24), + SCF_CPF_SOFT_PREFIX = (1 << 25), + SCF_CPF_SOFT_LOOKUP = (1 << 26) } switch_core_flag_enum_t; typedef uint32_t switch_core_flag_t; @@ -554,7 +556,7 @@ struct switch_filenames { typedef struct switch_filenames switch_filenames; SWITCH_DECLARE_DATA extern switch_filenames SWITCH_GLOBAL_filenames; -#define SWITCH_MAX_STACKS 16 +#define SWITCH_MAX_STACKS 32 #define SWITCH_THREAD_STACKSIZE 240 * 1024 #define SWITCH_SYSTEM_THREAD_STACKSIZE 8192 * 1024 #define SWITCH_MAX_INTERVAL 120 /* we only do up to 120ms */ @@ -578,7 +580,9 @@ typedef enum { SWITCH_CPF_NONE = 0, SWITCH_CPF_SCREEN = (1 << 0), SWITCH_CPF_HIDE_NAME = (1 << 1), - SWITCH_CPF_HIDE_NUMBER = (1 << 2) + SWITCH_CPF_HIDE_NUMBER = (1 << 2), + SWITCH_CPF_SOFT_PREFIX = (1 << 3), + SWITCH_CPF_SOFT_LOOKUP = (1 << 4) } switch_caller_profile_flag_enum_t; typedef uint32_t switch_caller_profile_flag_t; @@ -713,6 +717,21 @@ typedef struct { uint32_t init; } switch_rtcp_numbers_t; +typedef struct { + uint16_t nack_count; + uint16_t fir_count; + uint16_t pli_count; + uint16_t sr_count; + uint16_t rr_count; +} switch_rtcp_video_counters_t; + +typedef struct { + /* counters and stats for the incoming video stream and outgoing RTCP*/ + switch_rtcp_video_counters_t video_in; + /* counters and stats for the outgoing video stream and incoming RTCP*/ + switch_rtcp_video_counters_t video_out; +} switch_rtcp_video_stats_t; + typedef struct { switch_rtp_numbers_t inbound; switch_rtp_numbers_t outbound; @@ -1573,6 +1592,7 @@ typedef enum { CF_STREAM_CHANGED, CF_ARRANGED_BRIDGE, CF_STATE_REPEAT, + CF_WANT_DTLSv1_2, /* WARNING: DO NOT ADD ANY FLAGS BELOW THIS LINE */ /* IF YOU ADD NEW ONES CHECK IF THEY SHOULD PERSIST OR ZERO THEM IN switch_core_session.c switch_core_session_request_xml() */ CF_FLAG_MAX @@ -2170,7 +2190,13 @@ typedef enum { SWITCH_CAUSE_INVALID_URL = 610, SWITCH_CAUSE_INVALID_PROFILE = 611, SWITCH_CAUSE_NO_PICKUP = 612, - SWITCH_CAUSE_SRTP_READ_ERROR = 613 + SWITCH_CAUSE_SRTP_READ_ERROR = 613, + SWITCH_CAUSE_BOWOUT = 614, + SWITCH_CAUSE_BUSY_EVERYWHERE = 615, + SWITCH_CAUSE_DECLINE = 616, + SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE = 617, + SWITCH_CAUSE_NOT_ACCEPTABLE = 618, + SWITCH_CAUSE_UNWANTED = 619 } switch_call_cause_t; typedef enum { @@ -2642,7 +2668,8 @@ typedef enum { typedef enum { ICE_GOOGLE_JINGLE = (1 << 0), ICE_VANILLA = (1 << 1), - ICE_CONTROLLED = (1 << 2) + ICE_CONTROLLED = (1 << 2), + ICE_LITE = (1 << 3) } switch_core_media_ice_type_t; typedef enum { diff --git a/src/include/switch_utils.h b/src/include/switch_utils.h index 10242525f1..62ec7c8d41 100644 --- a/src/include/switch_utils.h +++ b/src/include/switch_utils.h @@ -46,6 +46,16 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_URL_UNSAFE "\r\n #%&+:;<=>?@[\\]^`{|}\"" +#define MAX_NETWORK_PORTS 10 + +struct switch_network_port_range { + int port; + int ports[MAX_NETWORK_PORTS]; + int min_port; + int max_port; +}; +typedef struct switch_network_port_range switch_network_port_range_t; +typedef switch_network_port_range_t* switch_network_port_range_p; static inline char *switch_get_hex_bytes(switch_byte_t *buf, switch_size_t datalen, char *new_buf, switch_size_t new_datalen) { @@ -1270,6 +1280,12 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_networ SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str); SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok); + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_port_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token, switch_network_port_range_p port); +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_port_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok, switch_network_port_range_p port); + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_port_token(switch_network_list_t *list, uint32_t ip, int port, const char **token); +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_port_token(switch_network_list_t *list, ip_t ip, int port, const char **token); SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token); SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token); #define switch_network_list_validate_ip(_list, _ip) switch_network_list_validate_ip_token(_list, _ip, NULL); diff --git a/src/mod/Makefile.am b/src/mod/Makefile.am index 36ed523311..b4f3eb5b0a 100644 --- a/src/mod/Makefile.am +++ b/src/mod/Makefile.am @@ -8,6 +8,8 @@ uninstall: $(OUR_UNINSTALL_MODULES) $(OUR_DISABLED_UNINSTALL_MODULES) mod_skypopen-all: mod_gsmopen-all mod_gsmopen-all: mod_spandsp-all mod_unimrcp-all: mod_sofia-all +mod_rayo-all: mod_dingaling-all +mod_ssml-all: mod_rayo-all $(OUR_MODULES) $(OUR_CLEAN_MODULES) $(OUR_INSTALL_MODULES) $(OUR_UNINSTALL_MODULES) $(OUR_DISABLED_MODULES) $(OUR_DISABLED_CLEAN_MODULES) $(OUR_DISABLED_INSTALL_MODULES) $(OUR_DISABLED_UNINSTALL_MODULES): @set fnord $$MAKEFLAGS; amf=$$2; \ diff --git a/src/mod/applications/mod_av/mod_av.2017.vcxproj b/src/mod/applications/mod_av/mod_av.2017.vcxproj index 3bd1816c6f..e2cbaa7315 100644 --- a/src/mod/applications/mod_av/mod_av.2017.vcxproj +++ b/src/mod/applications/mod_av/mod_av.2017.vcxproj @@ -1,155 +1,219 @@ - - - - - Debug - Win32 - - - Debug - x64 - - - Release - Win32 - - - Release - x64 - - - - mod_av - mod_av - Win32Proj - {7AEE504B-23B6-4B05-829E-7CD34855F146} - - - - DynamicLibrary - MultiByte - v141 - - - DynamicLibrary - MultiByte - v141 - - - DynamicLibrary - MultiByte - v141 - - - DynamicLibrary - MultiByte - v141 - - - - - - - - - - - - - - - - - - - - - - - - <_ProjectFileVersion>10.0.30319.1 - - - - "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) - 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) - - - ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) - false - - - - - - - X64 - - - "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) - 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) - - - - - ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) - false - - - MachineX64 - - - - - "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) - 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) - - - - - ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) - false - - - - - - - X64 - - - "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) - WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) - 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) - - - - - ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) - false - - - MachineX64 - - - - - - - - - - {bc1fd72e-1cd5-4525-a7f5-17c5740bfded} - - - {202d7a4e-760d-4d0e-afa1-d7459ced30ff} - false - - - - - + + + + + Debug-x264 + Win32 + + + Debug-x264 + x64 + + + Debug-openh264 + x64 + + + Release-x264 + Win32 + + + Release-x264 + x64 + + + Release-openh264 + x64 + + + + mod_av + mod_av + Win32Proj + {7AEE504B-23B6-4B05-829E-7CD34855F146} + + + + DynamicLibrary + MultiByte + v141 + + + DynamicLibrary + MultiByte + v141 + + + DynamicLibrary + MultiByte + v141 + + + DynamicLibrary + MultiByte + v141 + + + DynamicLibrary + MultiByte + v141 + + + DynamicLibrary + MultiByte + v141 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + <_ProjectFileVersion>10.0.30319.1 + + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + + + + + X64 + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + X64 + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + + + + + X64 + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + X64 + + + "../../libvpx";$(SolutionDir)\src\include;%(AdditionalIncludeDirectories) + WIN32;_DEBUG;_WINDOWS;_USRDLL;MOD_EXPORTS;_CRT_SECURE_NO_DEPRECATE;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + 4244;4127;4018;4389;4146;4057;4204;4706;4305;4152;4324;4013;4100;4214;4273;4554;4701;%(DisableSpecificWarnings) + + + + + ..\..\..\..\libs\libav\Win32\$(OutDir);%(AdditionalLibraryDirectories) + false + + + MachineX64 + + + + + + + + + + {bc1fd72e-1cd5-4525-a7f5-17c5740bfded} + + + {202d7a4e-760d-4d0e-afa1-d7459ced30ff} + false + + + + + \ No newline at end of file diff --git a/src/mod/applications/mod_avmd/mod_avmd.c b/src/mod/applications/mod_avmd/mod_avmd.c index 828cf1fced..aabd96c1ae 100644 --- a/src/mod/applications/mod_avmd/mod_avmd.c +++ b/src/mod/applications/mod_avmd/mod_avmd.c @@ -644,11 +644,11 @@ static switch_bool_t avmd_callback(switch_media_bug_t * bug, void *user_data, sw case SWITCH_ABC_TYPE_CLOSE: avmd_session_close(avmd_session); - switch_mutex_lock(avmd_globals.mutex); + switch_mutex_lock(avmd_globals.mutex); if (avmd_globals.session_n > 0) { --avmd_globals.session_n; } - switch_mutex_unlock(avmd_globals.mutex); + switch_mutex_unlock(avmd_globals.mutex); break; default: @@ -1151,7 +1151,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avmd_load) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "No memory pool assigned!\n"); return SWITCH_STATUS_TERM; } - switch_mutex_init(&avmd_globals.mutex, SWITCH_MUTEX_DEFAULT, pool); + switch_mutex_init(&avmd_globals.mutex, SWITCH_MUTEX_NESTED, pool); avmd_globals.pool = pool; if (avmd_load_xml_configuration(NULL) != SWITCH_STATUS_SUCCESS) { diff --git a/src/mod/applications/mod_callcenter/mod_callcenter.c b/src/mod/applications/mod_callcenter/mod_callcenter.c index bc320eb0d2..b3f5ca6fee 100644 --- a/src/mod/applications/mod_callcenter/mod_callcenter.c +++ b/src/mod/applications/mod_callcenter/mod_callcenter.c @@ -435,6 +435,7 @@ static struct { switch_mutex_t *mutex; switch_memory_pool_t *pool; switch_event_node_t *node; + int agent_originate_timeout; } globals; #define CC_QUEUE_CONFIGITEM_COUNT 100 @@ -1495,6 +1496,8 @@ static switch_status_t load_config(void) globals.global_database_lock = switch_true(val); } else if (!strcasecmp(var, "cc-instance-id")) { globals.cc_instance_id = strdup(val); + } else if (!strcasecmp(var, "agent-originate-timeout")) { + globals.agent_originate_timeout = atoi(val); } } } @@ -1511,9 +1514,11 @@ static switch_status_t load_config(void) } if (!globals.global_database_lock) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disabling global database lock\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Disabling global database lock\n"); } + if (!globals.agent_originate_timeout) globals.agent_originate_timeout = 60; + /* Initialize database */ if (!(dbh = cc_get_db_handle())) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot open DB!\n"); @@ -1707,7 +1712,7 @@ static void *SWITCH_THREAD_FUNC outbound_agent_thread_run(switch_thread_t *threa dialstr = switch_channel_expand_variables(member_channel, h->originate_string); switch_channel_set_app_flag_key(CC_APP_KEY, member_channel, CC_APP_AGENT_CONNECTING); - status = switch_ivr_originate(NULL, &agent_session, &cause, dialstr, 60, NULL, cid_name ? cid_name : h->member_cid_name, cid_number ? cid_number : h->member_cid_number, NULL, ovars, SOF_NONE, NULL, NULL); + status = switch_ivr_originate(NULL, &agent_session, &cause, dialstr, globals.agent_originate_timeout, NULL, cid_name ? cid_name : h->member_cid_name, cid_number ? cid_number : h->member_cid_number, NULL, ovars, SOF_NONE, NULL, NULL); /* Search for loopback agent */ if (status == SWITCH_STATUS_SUCCESS) { diff --git a/src/mod/applications/mod_commands/mod_commands.c b/src/mod/applications/mod_commands/mod_commands.c index 38a688792e..025f27f98b 100644 --- a/src/mod/applications/mod_commands/mod_commands.c +++ b/src/mod/applications/mod_commands/mod_commands.c @@ -3886,8 +3886,11 @@ SWITCH_STANDARD_API(uuid_broadcast_function) flags = SMF_ECHO_ALEG | SMF_HOLD_BLEG; } - switch_ivr_broadcast(argv[0], argv[1], flags); - stream->write_function(stream, "+OK Message sent\n"); + if (switch_ivr_broadcast(argv[0], argv[1], flags) == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Message sent\n"); + } else { + stream->write_function(stream, "-ERR invalid uuid\n"); + } } switch_safe_free(mycmd); @@ -4657,14 +4660,16 @@ SWITCH_STANDARD_API(uuid_bridge_function) return SWITCH_STATUS_SUCCESS; } -#define SESS_REC_SYNTAX " [start|stop|mask|unmask] []" +#define SESS_REC_SYNTAX " [start|stop|mask|unmask] [] []" SWITCH_STANDARD_API(session_record_function) { switch_core_session_t *rsession = NULL; - char *mycmd = NULL, *argv[4] = { 0 }; + char *mycmd = NULL, *argv[5] = { 0 }; char *uuid = NULL, *action = NULL, *path = NULL; int argc = 0; uint32_t limit = 0; + switch_event_t *vars = NULL; + char *new_fp = NULL; if (zstr(cmd)) { goto usage; @@ -4693,11 +4698,16 @@ SWITCH_STANDARD_API(session_record_function) } if (!strcasecmp(action, "start")) { - if (switch_ivr_record_session(rsession, path, limit, NULL) != SWITCH_STATUS_SUCCESS) { + if(argc > 3) { + switch_url_decode(argv[4]); + switch_event_create_brackets(argv[4], '{', '}',',', &vars, &new_fp, SWITCH_FALSE); + } + if (switch_ivr_record_session_event(rsession, path, limit, NULL, vars) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "-ERR Cannot record session!\n"); } else { stream->write_function(stream, "+OK Success\n"); } + switch_event_safe_destroy(vars); } else if (!strcasecmp(action, "stop")) { if (switch_ivr_stop_record_session(rsession, path) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "-ERR Cannot stop record session!\n"); @@ -4934,6 +4944,8 @@ SWITCH_STANDARD_API(break_function) } } + stream->write_function(stream, "+OK\n"); + done: if (psession) { diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index 3e15aa9fd8..7fcf005c30 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -810,10 +810,16 @@ switch_status_t conference_api_sub_hup(conference_member_t *member, switch_strea switch_event_t *event; if (member == NULL) { + if (stream != NULL) { + stream->write_function(stream, "-ERR Invalid member!\n"); + } return SWITCH_STATUS_GENERR; } conference_utils_member_clear_flag(member, MFLAG_RUNNING); + if (stream != NULL) { + stream->write_function(stream, "+OK hup %u\n", member->id); + } if (member->conference && test_eflag(member->conference, EFLAG_HUP_MEMBER)) { if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { @@ -1852,7 +1858,12 @@ switch_status_t conference_api_sub_vid_res(conference_obj_t *conference, switch_ } if (canvas_w < 320 || canvas_h < 180) { - stream->write_function(stream, "-ERR Invalid size\n"); + stream->write_function(stream, "-ERR Invalid size, [%dx%d] is too small\n", canvas_w, canvas_h); + return SWITCH_STATUS_SUCCESS; + } + + if (canvas_w > 7680 || canvas_h > 4320) { + stream->write_function(stream, "-ERR Invalid size, [%dx%d] is too large.\n", canvas_w, canvas_h); return SWITCH_STATUS_SUCCESS; } @@ -1877,7 +1888,11 @@ switch_status_t conference_api_sub_vid_res(conference_obj_t *conference, switch_ id = 1; } - conference_video_change_res(conference, canvas_w, canvas_h, id - 1); + if (conference_video_change_res(conference, canvas_w, canvas_h, id - 1) == SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "+OK Resolution set to [%dx%d]\n", canvas_w, canvas_h); + } else { + stream->write_function(stream, "-ERR Resolution not set\n"); + } return SWITCH_STATUS_SUCCESS; } @@ -3556,9 +3571,9 @@ switch_status_t conference_api_sub_dial(conference_obj_t *conference, switch_str } if (conference) { - conference_outcall(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], NULL, &cause, NULL, NULL); + conference_outcall(conference, NULL, NULL, argv[2], 60, NULL, argv[4], argv[3], NULL, &cause, NULL, NULL, NULL); } else { - conference_outcall(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], NULL, &cause, NULL, NULL); + conference_outcall(NULL, argv[0], NULL, argv[2], 60, NULL, argv[4], argv[3], NULL, &cause, NULL, NULL, NULL); } stream->write_function(stream, "+OK Call Requested: result: [%s]\n", switch_channel_cause2str(cause)); diff --git a/src/mod/applications/mod_conference/conference_event.c b/src/mod/applications/mod_conference/conference_event.c index cd9b5c2b81..083dd35490 100644 --- a/src/mod/applications/mod_conference/conference_event.c +++ b/src/mod/applications/mod_conference/conference_event.c @@ -398,7 +398,7 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json } else if (exec) { cJSON_AddItemToObject(jdata, "conf-command", cJSON_CreateString(exec)); cJSON_AddItemToObject(jdata, "response", cJSON_CreateString((char *)stream.data)); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT,"RES [%s][%s]\n", exec, (char *)stream.data); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"RES [%s][%s]\n", exec, (char *)stream.data); } else { cJSON_AddItemToObject(jdata, "error", cJSON_CreateString("Invalid Command")); } @@ -741,10 +741,12 @@ switch_status_t conference_event_add_data(conference_obj_t *conference, switch_e switch_status_t status = SWITCH_STATUS_SUCCESS; switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Name", conference->name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Domain", conference->domain); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Conference-Size", "%u", conference->count); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Conference-Ghosts", "%u", conference->count_ghosts); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Profile-Name", conference->profile_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Conference-Unique-ID", conference->uuid_str); + switch_event_merge(event, conference->variables); return status; } diff --git a/src/mod/applications/mod_conference/conference_loop.c b/src/mod/applications/mod_conference/conference_loop.c index 49377312c6..78024f10de 100644 --- a/src/mod/applications/mod_conference/conference_loop.c +++ b/src/mod/applications/mod_conference/conference_loop.c @@ -939,6 +939,10 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob goto do_continue; } + if (!switch_channel_test_app_flag(channel, CF_AUDIO)) { + goto do_continue; + } + /* if the member can speak, compute the audio energy level and */ /* generate events when the level crosses the threshold */ if (((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) || @@ -1228,7 +1232,7 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob if (datalen) { switch_size_t ok = 1; - + /* Write the audio into the input buffer */ switch_mutex_lock(member->audio_in_mutex); if (switch_buffer_inuse(member->audio_buffer) > flush_len) { diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 152dfb8aa5..9f43417fe9 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -76,6 +76,7 @@ void conference_member_bind_controls(conference_member_t *member, const char *co switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Conf-Profile", member->conference->profile_name); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-controls"); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Controls", controls); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Fetch-Call-UUID", switch_core_session_get_uuid(member->session)); if (!(cxml = switch_xml_open_cfg(mod_conference_cf_name, &cfg, params))) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Open of %s failed\n", mod_conference_cf_name); @@ -762,7 +763,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m } if ((var = switch_channel_get_variable_dup(member->channel, "conference_join_volume_in", SWITCH_FALSE, -1))) { - uint32_t id = atoi(var); + int id = atoi(var); if (id > -5 && id < 5) { member->volume_in_level = id; @@ -770,7 +771,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m } if ((var = switch_channel_get_variable_dup(member->channel, "conference_join_volume_out", SWITCH_FALSE, -1))) { - uint32_t id = atoi(var); + int id = atoi(var); if (id > -5 && id < 5) { member->volume_out_level = id; @@ -779,15 +780,15 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m if ((var = switch_channel_get_variable_dup(member->channel, "conference_join_energy_level", SWITCH_FALSE, -1))) { - uint32_t id = atoi(var); + int id = atoi(var); - if (id > -5 && id < 5) { + if (id > -2 && id < 1801) { member->energy_level = id; } } if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_canvas", SWITCH_FALSE, -1))) { - uint32_t id = atoi(var) - 1; + int id = atoi(var) - 1; if (id < conference->canvas_count) { member->canvas_id = id; member->layer_timeout = DEFAULT_LAYER_TIMEOUT; @@ -795,7 +796,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m } if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_watching_canvas", SWITCH_FALSE, -1))) { - uint32_t id = atoi(var) - 1; + int id = atoi(var) - 1; if (id == 0) { id = conference->canvas_count; diff --git a/src/mod/applications/mod_conference/conference_record.c b/src/mod/applications/mod_conference/conference_record.c index c02bb3bcff..d4ccf81c5e 100644 --- a/src/mod/applications/mod_conference/conference_record.c +++ b/src/mod/applications/mod_conference/conference_record.c @@ -91,7 +91,6 @@ switch_status_t conference_record_stop(conference_obj_t *conference, switch_stre switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { - conference->record_count--; if (!conference_utils_test_flag(conference, CFLAG_CONF_RESTART_AUTO_RECORD) && member->rec && member->rec->autorec) { stream->write_function(stream, "Stopped AUTO recording file %s (Auto Recording Now Disabled)\n", member->rec_path); conference->auto_record = 0; @@ -155,7 +154,7 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v { int16_t *data_buf; conference_member_t smember = { 0 }, *member; - conference_record_t *rp, *last = NULL, *rec = (conference_record_t *) obj; + conference_record_t *rp, *rec = (conference_record_t *) obj; conference_obj_t *conference = rec->conference; uint32_t samples = switch_samples_per_packet(conference->rate, conference->interval); uint32_t mux_used; @@ -422,6 +421,7 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v switch_core_file_close(&member->rec->fh); } + conference->record_count--; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Recording of %s Stopped\n", rec->path); if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { @@ -455,11 +455,7 @@ void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, v switch_mutex_lock(conference->flag_mutex); for (rp = conference->rec_node_head; rp; rp = rp->next) { if (rec == rp) { - if (last) { - last->next = rp->next; - } else { - conference->rec_node_head = rp->next; - } + conference->rec_node_head = rp->next; } } switch_mutex_unlock(conference->flag_mutex); diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index 7a78e1b1a8..ba736bcea1 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -2031,6 +2031,8 @@ video_layout_t *conference_video_get_layout(conference_obj_t *conference, const layout_group_t *lg = NULL; video_layout_t *vlayout = NULL; + if (!video_layout_name) return NULL; + if (video_layout_group) { lg = switch_core_hash_find(conference->layout_group_hash, video_layout_group); vlayout = conference_video_find_best_layout(conference, lg, 0, 0); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index ccac9cc99f..86be4911a8 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -611,7 +611,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob for (omember = conference->members; omember; omember = omember->next) { switch_size_t ok = 1; - if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING)) { + if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING) || !switch_channel_test_flag(omember->channel, CF_AUDIO)) { continue; } @@ -667,13 +667,14 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob write_frame[x] = (int16_t) z; } - switch_mutex_lock(omember->audio_out_mutex); - ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes); - switch_mutex_unlock(omember->audio_out_mutex); - - if (!ok) { - switch_mutex_unlock(conference->mutex); - goto end; + if (switch_channel_test_flag(omember->channel, CF_AUDIO)) { + switch_mutex_lock(omember->audio_out_mutex); + ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes); + switch_mutex_unlock(omember->audio_out_mutex); + if (!ok) { + switch_mutex_unlock(conference->mutex); + goto end; + } } } } else { /* There is no source audio. Push silence into all of the buffers */ @@ -688,7 +689,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob for (omember = conference->members; omember; omember = omember->next) { switch_size_t ok = 1; - if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING)) { + if (!conference_utils_member_test_flag(omember, MFLAG_RUNNING) || !switch_channel_test_flag(omember->channel, CF_AUDIO)) { continue; } @@ -1133,7 +1134,8 @@ switch_xml_t add_x_tag(switch_xml_t x_member, const char *name, const char *valu void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, int off) { conference_member_t *member = NULL; - switch_xml_t x_member = NULL, x_members = NULL, x_flags; + switch_xml_t x_member = NULL, x_members = NULL, x_flags, x_variables; + switch_event_header_t *hp; int moff = 0; char i[30] = ""; char *ival = i; @@ -1218,6 +1220,13 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i switch_snprintf(i, sizeof(i), "%d", switch_epoch_time_now(NULL) - conference->run_time); switch_xml_set_attr_d(x_conference, "run_time", ival); + x_variables = switch_xml_add_child_d(x_conference, "variables", 0); + for (hp = conference->variables->headers; hp; hp = hp->next) { + switch_xml_t x_variable = switch_xml_add_child_d(x_variables, "variable", 0); + switch_xml_set_attr_d(x_variable, "name", hp->name); + switch_xml_set_attr_d(x_variable, "value", hp->value); + } + x_members = switch_xml_add_child_d(x_conference, "members", 0); switch_assert(x_members); @@ -1339,7 +1348,8 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i void conference_jlist(conference_obj_t *conference, cJSON *json_conferences) { conference_member_t *member = NULL; - static cJSON *json_conference, *json_conference_members, *json_conference_member, *json_conference_member_flags; + static cJSON *json_conference, *json_conference_variables, *json_conference_members, *json_conference_member, *json_conference_member_flags; + switch_event_header_t *hp; switch_assert(conference != NULL); json_conference = cJSON_CreateObject(); @@ -1379,6 +1389,11 @@ void conference_jlist(conference_obj_t *conference, cJSON *json_conferences) cJSON_AddNumberToObject(json_conference, "max_members", conference->max_members); } + cJSON_AddItemToObject(json_conference, "variables", json_conference_variables = cJSON_CreateObject()); + for (hp = conference->variables->headers; hp; hp = hp->next) { + cJSON_AddStringToObject(json_conference_variables, hp->name, hp->value); + } + cJSON_AddItemToObject(json_conference, "members", json_conference_members = cJSON_CreateArray()); switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { @@ -1498,7 +1513,10 @@ switch_status_t conference_outcall(conference_obj_t *conference, char *cid_num, char *profile, switch_call_cause_t *cause, - switch_call_cause_t *cancel_cause, switch_event_t *var_event) + switch_call_cause_t *cancel_cause, + switch_event_t *var_event, + char** peer_uuid + ) { switch_core_session_t *peer_session = NULL; switch_channel_t *peer_channel; @@ -1608,6 +1626,10 @@ switch_status_t conference_outcall(conference_obj_t *conference, if (switch_channel_test_flag(peer_channel, CF_ANSWERED) || switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA)) { switch_caller_extension_t *extension = NULL; + if(peer_uuid) { + *peer_uuid = switch_channel_get_uuid(peer_channel); + } + /* build an extension name object */ if ((extension = switch_caller_extension_new(peer_session, conference_name, conference_name)) == 0) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); @@ -1654,6 +1676,7 @@ switch_status_t conference_outcall(conference_obj_t *conference, void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread, void *obj) { struct bg_call *call = (struct bg_call *) obj; + char* peer_uuid = NULL; if (call) { switch_call_cause_t cause; @@ -1662,7 +1685,7 @@ void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread, void *o conference_outcall(call->conference, call->conference_name, call->session, call->bridgeto, call->timeout, - call->flags, call->cid_name, call->cid_num, call->profile, &cause, call->cancel_cause, call->var_event); + call->flags, call->cid_name, call->cid_num, call->profile, &cause, call->cancel_cause, call->var_event, &peer_uuid); if (call->conference && test_eflag(call->conference, EFLAG_BGDIAL_RESULT) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { @@ -1670,6 +1693,7 @@ void *SWITCH_THREAD_FUNC conference_outcall_run(switch_thread_t *thread, void *o switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "bgdial-result"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Result", switch_channel_cause2str(cause)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Job-UUID", call->uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Peer-UUID", peer_uuid); switch_event_fire(&event); } @@ -1715,6 +1739,8 @@ switch_status_t conference_outcall_bg(conference_obj_t *conference, if (var_event) { call->var_event = *var_event; var_event = NULL; + } else { + switch_event_create_plain(&call->var_event, SWITCH_EVENT_GENERAL); } if (conference) { @@ -1743,6 +1769,9 @@ switch_status_t conference_outcall_bg(conference_obj_t *conference, if (call_uuid) { call->uuid = strdup(call_uuid); + if (call->var_event) { + switch_event_add_header_string(call->var_event, SWITCH_STACK_BOTTOM, "conference_bgdial_jobid", call->uuid); + } } if (profile) { @@ -1986,6 +2015,7 @@ SWITCH_STANDARD_APP(conference_function) switch_assert(params); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "conference_name", conference_name); switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "profile_name", profile_name); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Fetch-Call-UUID", switch_core_session_get_uuid(session)); /* Open the config from the xml registry */ if (!(cxml = switch_xml_open_cfg(mod_conference_cf_name, &cfg, params))) { @@ -2340,7 +2370,7 @@ SWITCH_STANDARD_APP(conference_function) /* if we're using "bridge:" make an outbound call and bridge it in */ if (!zstr(bridgeto) && strcasecmp(bridgeto, "none")) { switch_call_cause_t cause; - if (conference_outcall(conference, NULL, session, bridgeto, 60, NULL, NULL, NULL, NULL, &cause, NULL, NULL) != SWITCH_STATUS_SUCCESS) { + if (conference_outcall(conference, NULL, session, bridgeto, 60, NULL, NULL, NULL, NULL, &cause, NULL, NULL, NULL) != SWITCH_STATUS_SUCCESS) { goto done; } } else { @@ -3748,10 +3778,22 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co } } + if (cfg.profile) { + switch_xml_t xml_profile_variables; + if ((xml_profile_variables = switch_xml_child(cfg.profile, "variables")) != NULL) { + for (xml_kvp = switch_xml_child(xml_profile_variables, "variable"); xml_kvp; xml_kvp = xml_kvp->next) { + char *var = (char *) switch_xml_attr_soft(xml_kvp, "name"); + char *val = (char *) switch_xml_attr_soft(xml_kvp, "value"); + if (var && val) { + conference_set_variable(conference, var, val); + } + } + } + } switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT); conference_event_add_data(conference, event); - if(conference->verbose_events && channel) { + if (conference->verbose_events && channel) { switch_channel_event_set_data(channel, event); } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create"); diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index bb887536e1..ccded3bfb5 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -1135,7 +1135,9 @@ switch_status_t conference_outcall(conference_obj_t *conference, char *cid_num, char *profile, switch_call_cause_t *cause, - switch_call_cause_t *cancel_cause, switch_event_t *var_event); + switch_call_cause_t *cancel_cause, + switch_event_t *var_event, + char** peer_uuid); switch_status_t conference_outcall_bg(conference_obj_t *conference, char *conference_name, switch_core_session_t *session, char *bridgeto, uint32_t timeout, const char *flags, const char *cid_name, diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index aa68cb2c5b..60105de3c9 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -587,6 +587,23 @@ SWITCH_STANDARD_APP(sched_heartbeat_function) } +#define FILTER_CODECS_SYNTAX "" +SWITCH_STANDARD_APP(filter_codecs_function) +{ + const char *r_sdp; + switch_channel_t *channel = switch_core_session_get_channel(session); + + + r_sdp = switch_channel_get_variable(channel, SWITCH_R_SDP_VARIABLE); + + if (data && r_sdp) { + switch_core_media_merge_sdp_codec_string(session, r_sdp, SDP_TYPE_REQUEST, data); + switch_channel_set_variable(channel, "filter_codec_string", data); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Incomplete data\n"); + } +} + #define HEARTBEAT_SYNTAX "[0|]" SWITCH_STANDARD_APP(heartbeat_function) @@ -2913,6 +2930,50 @@ SWITCH_STANDARD_APP(phrase_function) } +SWITCH_STANDARD_APP(broadcast_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + char * uuid = switch_channel_get_uuid(channel); + switch_media_flag_t flags = SMF_ECHO_ALEG | SMF_ECHO_BLEG; + char *mycmd = NULL, *argv[4] = { 0 }; + int argc = 0; + + if (zstr(data)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid args for broadcast app\n"); + return; + } + + mycmd = switch_core_session_strdup(session, data); + argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))); + + if (argc > 2) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "invalid args for broadcast app [%s]\n", data); + return; + } else { + if (argv[1]) { + if (switch_stristr("both", (argv[1]))) { + flags |= (SMF_ECHO_ALEG | SMF_ECHO_BLEG); + } + + if (switch_stristr("aleg", argv[1])) { + flags |= SMF_ECHO_ALEG; + } + + if (switch_stristr("bleg", argv[1])) { + flags &= ~SMF_HOLD_BLEG; + flags |= SMF_ECHO_BLEG; + } + + if (switch_stristr("holdb", argv[1])) { + flags &= ~SMF_ECHO_BLEG; + flags |= SMF_HOLD_BLEG; + } + } + switch_ivr_broadcast(uuid, argv[0], flags); + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "BROADCAST_SENT"); + } +} + SWITCH_STANDARD_APP(playback_function) { switch_input_args_t args = { 0 }; @@ -3190,40 +3251,43 @@ SWITCH_STANDARD_APP(record_session_unmask_function) SWITCH_STANDARD_APP(record_session_function) { + char *array[5] = {0}; + char *args = NULL; + int argc; + char *path = NULL; - char *path_end; uint32_t limit = 0; + switch_event_t *vars = NULL; + char *new_fp = NULL; if (zstr(data)) { return; } - path = switch_core_session_strdup(session, data); + args = switch_core_session_strdup(session, data); + argc = switch_split(args, ' ', array); - /* Search for a space then a plus followed by only numbers at the end of the path, - if found trim any spaces to the left/right of the plus use the left side as the - path and right side as a time limit on the recording - */ + if (argc == 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "usage: [+] [{var1=x,var2=y}]\n"); + } - /* if we find a + and the character before it is a space */ - if ((path_end = strrchr(path, '+')) && path_end > path && *(path_end - 1) == ' ') { - char *limit_start = path_end + 1; + path = array[0]; - /* not at the end and the rest is numbers lets parse out the limit and fix up the path */ - if (*limit_start != '\0' && switch_is_number(limit_start) == SWITCH_TRUE) { - limit = atoi(limit_start); - /* back it off by one character to the char before the + */ - path_end--; - - /* trim spaces to the left of the plus */ - while (path_end > path && *path_end == ' ') { - path_end--; + if (argc > 1) { + if (*array[1] == '+') { + limit = atoi(++array[1]); + if (argc > 2) { + switch_url_decode(array[2]); + switch_event_create_brackets(array[2], '{', '}',',', &vars, &new_fp, SWITCH_FALSE); } - - *(path_end + 1) = '\0'; + } else { + switch_url_decode(array[1]); + switch_event_create_brackets(array[1], '{', '}',',', &vars, &new_fp, SWITCH_FALSE); } } - switch_ivr_record_session(session, path, limit, NULL); + + switch_ivr_record_session_event(session, path, limit, NULL, vars); + switch_event_safe_destroy(vars); } SWITCH_STANDARD_APP(stop_record_session_function) @@ -5646,7 +5710,7 @@ void *SWITCH_THREAD_FUNC page_thread(switch_thread_t *thread, void *obj) switch_mutex_unlock(pd->mutex); } - switch_event_safe_destroy(&pd->var_event); + switch_event_safe_destroy(pd->var_event); if (pool) { switch_core_destroy_memory_pool(&pool); @@ -6460,6 +6524,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_APP(app_interface, "enable_heartbeat", "Enable Media Heartbeat", "Enable Media Heartbeat", heartbeat_function, HEARTBEAT_SYNTAX, SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "filter_codecs", "Filter Codecs", "Filter Codecs", filter_codecs_function, FILTER_CODECS_SYNTAX, SAF_SUPPORT_NOMEDIA); + SWITCH_ADD_APP(app_interface, "enable_keepalive", "Enable Keepalive", "Enable Keepalive", keepalive_function, KEEPALIVE_SYNTAX, SAF_SUPPORT_NOMEDIA); @@ -6495,6 +6561,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_dptools_load) SWITCH_ADD_APP(app_interface, "park_state", "Park State", "Park State", park_state_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "gentones", "Generate Tones", "Generate tones to the channel", gentones_function, "[|]", SAF_NONE); SWITCH_ADD_APP(app_interface, "playback", "Playback File", "Playback a file to the channel", playback_function, "", SAF_NONE); + SWITCH_ADD_APP(app_interface, "broadcast", "Broadcast File", "Broadcast a file to the session", broadcast_function, " ", SAF_NONE); SWITCH_ADD_APP(app_interface, "endless_playback", "Playback File Endlessly", "Endlessly Playback a file to the channel", endless_playback_function, "", SAF_NONE); SWITCH_ADD_APP(app_interface, "loop_playback", "Playback File looply", "Playback a file to the channel looply for limted times", diff --git a/src/mod/applications/mod_enum/mod_enum.c b/src/mod/applications/mod_enum/mod_enum.c index 493e2c176a..3e458dd129 100644 --- a/src/mod/applications/mod_enum/mod_enum.c +++ b/src/mod/applications/mod_enum/mod_enum.c @@ -833,12 +833,14 @@ SWITCH_STANDARD_API(enum_function) if (!strcasecmp(dest, "reload")) { do_load(); stream->write_function(stream, "+OK ENUM Reloaded.\n"); + switch_safe_free(mydata); return SWITCH_STATUS_SUCCESS; } if (enum_lookup(root, dest, &results, NULL, session) != SWITCH_STATUS_SUCCESS) { stream->write_function(stream, "No Match!\n"); + switch_safe_free(mydata); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/applications/mod_http_cache/mod_http_cache.c b/src/mod/applications/mod_http_cache/mod_http_cache.c index dd4b1ef2c8..e3f8d06493 100644 --- a/src/mod/applications/mod_http_cache/mod_http_cache.c +++ b/src/mod/applications/mod_http_cache/mod_http_cache.c @@ -416,10 +416,10 @@ static switch_status_t http_put(url_cache_t *cache, http_profile_t *profile, swi if (!zstr(cache->ssl_cacert)) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, cache->ssl_cacert); } - /* verify that the host name matches the cert */ - if (!cache->ssl_verifyhost) { - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); - } + } + /* verify that the host name matches the cert */ + if (!cache->ssl_verifyhost) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); } switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, httpRes); @@ -1098,6 +1098,7 @@ static switch_status_t http_get(url_cache_t *cache, http_profile_t *profile, cac http_get_data_t get_data = {0}; long httpRes = 0; int start_time_ms = switch_time_now() / 1000; + switch_CURLcode curl_status = CURLE_UNKNOWN_OPTION; /* set up HTTP GET */ get_data.fd = 0; @@ -1117,6 +1118,7 @@ static switch_status_t http_get(url_cache_t *cache, http_profile_t *profile, cac if ((get_data.fd = open(get_data.url->filename, O_CREAT | O_RDWR | O_TRUNC, S_IRUSR | S_IWUSR)) > -1) { switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); + switch_curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_NOSIGNAL, 1); if (headers) { switch_curl_easy_setopt(curl_handle, CURLOPT_HTTPHEADER, headers); @@ -1140,12 +1142,14 @@ static switch_status_t http_get(url_cache_t *cache, http_profile_t *profile, cac if (!zstr(cache->ssl_cacert)) { switch_curl_easy_setopt(curl_handle, CURLOPT_CAINFO, cache->ssl_cacert); } - /* verify that the host name matches the cert */ - if (!cache->ssl_verifyhost) { - switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); - } } - switch_curl_easy_perform(curl_handle); + + /* verify that the host name matches the cert */ + if (!cache->ssl_verifyhost) { + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYHOST, 0L); + } + + curl_status = switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); switch_curl_easy_cleanup(curl_handle); close(get_data.fd); @@ -1155,7 +1159,7 @@ static switch_status_t http_get(url_cache_t *cache, http_profile_t *profile, cac goto done; } - if (httpRes == 200) { + if (curl_status == CURLE_OK) { int duration_ms = (switch_time_now() / 1000) - start_time_ms; if (duration_ms > 500) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "URL %s downloaded in %d ms\n", url->url, duration_ms); @@ -1167,7 +1171,7 @@ static switch_status_t http_get(url_cache_t *cache, http_profile_t *profile, cac } } else { url->size = 0; // nothing downloaded or download interrupted - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received HTTP error %ld trying to fetch %s\n", httpRes, url->url); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Received curl error %d HTTP error code %ld trying to fetch %s\n", curl_status, httpRes, url->url); status = SWITCH_STATUS_GENERR; goto done; } @@ -1729,6 +1733,7 @@ static switch_status_t http_cache_file_open(switch_file_handle_t *handle, const } } + context->fh.pre_buffer_datalen = handle->pre_buffer_datalen; if ((status = switch_core_file_open(&context->fh, context->local_path, handle->channels, @@ -1750,6 +1755,7 @@ static switch_status_t http_cache_file_open(switch_file_handle_t *handle, const handle->interval = context->fh.interval; handle->channels = context->fh.channels; handle->flags |= SWITCH_FILE_NOMUX; + handle->pre_buffer_datalen = 0; if (switch_test_flag((&context->fh), SWITCH_FILE_NATIVE)) { switch_set_flag_locked(handle, SWITCH_FILE_NATIVE); @@ -1858,6 +1864,17 @@ static switch_status_t http_file_close(switch_file_handle_t *handle) return status; } +static switch_status_t http_cache_file_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence) +{ + struct http_context *context = (struct http_context *)handle->private_info; + + if (!handle->seekable) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File is not seekable\n"); + return SWITCH_STATUS_NOTIMPL; + } + return switch_core_file_seek(&context->fh, cur_sample, samples, whence); +} + static char *http_supported_formats[] = { "http", NULL }; static char *https_supported_formats[] = { "https", NULL }; static char *http_cache_supported_formats[] = { "http_cache", NULL }; @@ -1901,6 +1918,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load) file_interface->file_write = http_file_write; file_interface->file_read_video = http_file_read_video; file_interface->file_write_video = http_file_write_video; + file_interface->file_seek = http_cache_file_seek; if (gcache.enable_file_formats) { file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE); @@ -1912,6 +1930,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load) file_interface->file_write = http_file_write; file_interface->file_read_video = http_file_read_video; file_interface->file_write_video = http_file_write_video; + file_interface->file_seek = http_cache_file_seek; file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE); file_interface->interface_name = modname; @@ -1922,6 +1941,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_http_cache_load) file_interface->file_write = http_file_write; file_interface->file_read_video = http_file_read_video; file_interface->file_write_video = http_file_write_video; + file_interface->file_seek = http_cache_file_seek; } /* create the queue from configuration */ diff --git a/src/mod/applications/mod_spandsp/mod_spandsp.h b/src/mod/applications/mod_spandsp/mod_spandsp.h index 4e8f1d2427..7ffd334ef3 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp.h +++ b/src/mod/applications/mod_spandsp/mod_spandsp.h @@ -110,7 +110,7 @@ typedef enum { * TONE DETECTION WITH CADENCE */ -#define MAX_TONES 32 +#define MAX_TONES 128 #define STRLEN 128 /** * Tone descriptor diff --git a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c index a78b63e5b1..b75ac89423 100644 --- a/src/mod/applications/mod_spandsp/mod_spandsp_fax.c +++ b/src/mod/applications/mod_spandsp/mod_spandsp_fax.c @@ -59,6 +59,25 @@ typedef enum { T38_MODE_REFUSED = -1, } t38_mode_t; +const char * get_t38_status(t38_mode_t mode) +{ + const char *str = "off"; + switch(mode) { + case T38_MODE_NEGOTIATED: + str = "negotiated"; + break; + case T38_MODE_REQUESTED: + str = "requested"; + break; + case T38_MODE_REFUSED: + str = "refused"; + break; + default: + break; + } + return str; +} + struct pvt_s { switch_core_session_t *session; @@ -316,6 +335,7 @@ static int phase_b_handler(void *user_data, int result) } switch_channel_set_variable(channel, "fax_ecm_used", (t30_stats.error_correcting_mode) ? "on" : "off"); + switch_channel_set_variable(channel, "fax_t38_status", get_t38_status(pvt->t38_mode)); switch_channel_set_variable(channel, "fax_local_station_id", local_ident); switch_channel_set_variable(channel, "fax_remote_station_id", far_ident); switch_channel_set_variable(channel, "fax_remote_country", switch_str_nil(t30_get_rx_country(pvt->t30))); @@ -328,9 +348,10 @@ static int phase_b_handler(void *user_data, int result) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Local station id: %s\n", local_ident); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer Rate: %i\n", t30_stats.bit_rate); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "ECM status %s\n", (t30_stats.error_correcting_mode) ? "on" : "off"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote country: %s\n", switch_str_nil(t30_get_rx_country(pvt->t30))); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote vendor: %s\n", switch_str_nil(t30_get_rx_vendor(pvt->t30))); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote model: %s\n", switch_str_nil(t30_get_rx_model(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38 status %s\n", get_t38_status(pvt->t38_mode)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote country: %s\n", switch_str_nil(t30_get_rx_country(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote vendor: %s\n", switch_str_nil(t30_get_rx_vendor(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote model: %s\n", switch_str_nil(t30_get_rx_model(pvt->t30))); if (pvt->app_mode == FUNCTION_TX) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Total fax pages: %s\n", fax_document_total_pages); } @@ -347,6 +368,7 @@ static int phase_b_handler(void *user_data, int result) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "uuid", switch_core_session_get_uuid(session)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-transfer-rate", fax_transfer_rate); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-ecm-used", (t30_stats.error_correcting_mode) ? "on" : "off"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-t38-status", get_t38_status(pvt->t38_mode)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-local-station-id", local_ident); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-station-id", far_ident); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-country", switch_str_nil(t30_get_rx_country(pvt->t30))); @@ -546,9 +568,10 @@ static void phase_e_handler(void *user_data, int result) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer Rate: %i\n", t.bit_rate); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "ECM status %s\n", (t.error_correcting_mode) ? "on" : "off"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote country: %s\n", switch_str_nil(t30_get_rx_country(pvt->t30))); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote vendor: %s\n", switch_str_nil(t30_get_rx_vendor(pvt->t30))); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote model: %s\n", switch_str_nil(t30_get_rx_model(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "T38 status %s\n", get_t38_status(pvt->t38_mode)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote country: %s\n", switch_str_nil(t30_get_rx_country(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote vendor: %s\n", switch_str_nil(t30_get_rx_vendor(pvt->t30))); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "remote model: %s\n", switch_str_nil(t30_get_rx_model(pvt->t30))); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "==============================================================================\n"); @@ -564,6 +587,7 @@ static void phase_e_handler(void *user_data, int result) switch_channel_set_variable(channel, "fax_result_text", t30_completion_code_to_str(result)); switch_channel_set_variable(channel, "fax_ecm_used", (t.error_correcting_mode) ? "on" : "off"); + switch_channel_set_variable(channel, "fax_t38_status", get_t38_status(pvt->t38_mode)); switch_channel_set_variable(channel, "fax_local_station_id", local_ident); switch_channel_set_variable(channel, "fax_remote_station_id", far_ident); @@ -616,6 +640,7 @@ static void phase_e_handler(void *user_data, int result) switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-bad-rows", fax_bad_rows); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-transfer-rate", fax_transfer_rate); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-ecm-used", (t.error_correcting_mode) ? "on" : "off"); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-t38-status", get_t38_status(pvt->t38_mode)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-local-station-id", local_ident); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "fax-remote-station-id", far_ident); switch_event_fire(&event); diff --git a/src/mod/codecs/mod_com_g729/Makefile.am b/src/mod/codecs/mod_com_g729/Makefile.am index 8af9c4d795..128a9f9628 100644 --- a/src/mod/codecs/mod_com_g729/Makefile.am +++ b/src/mod/codecs/mod_com_g729/Makefile.am @@ -1,13 +1,13 @@ include $(top_srcdir)/build/modmake.rulesam MODNAME=mod_com_g729 -VERSION=201506221434 +VERSION=latest if ISLINUX G729INSTALLER = $(top_srcdir)/libs/fs-$(VERSION)-installer -LICSERVER=/usr/sbin/freeswitch_licence_server -VALIDATOR=$(bindir)/validator +LICSERVER=/usr/sbin/freeswitch-license-server +VALIDATOR=$(bindir)/freeswitch-license-validator MOD=$(moddir)/mod_com_g729.so BUILT_SOURCES = $(G729INSTALLER) diff --git a/src/mod/endpoints/mod_loopback/mod_loopback.c b/src/mod/endpoints/mod_loopback/mod_loopback.c index 202dfa186b..cf52370aa8 100644 --- a/src/mod/endpoints/mod_loopback/mod_loopback.c +++ b/src/mod/endpoints/mod_loopback/mod_loopback.c @@ -94,7 +94,14 @@ typedef struct loopback_private_object loopback_private_t; static struct { int debug; -} globals; + int early_set_loopback_id; + int fire_bowout_event_bridge; + int ignore_channel_ready; + switch_call_cause_t bowout_hangup_cause; + int bowout_controlled_hangup; + int bowout_transfer_recordings; + int bowout_disable_on_inner_bridge; +} loopback_globals; static switch_status_t channel_on_init(switch_core_session_t *session); static switch_status_t channel_on_hangup(switch_core_session_t *session); @@ -263,6 +270,10 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_snprintf(name, sizeof(name), "loopback/%s-b", tech_pvt->caller_profile->destination_number); switch_channel_set_name(b_channel, name); + if (loopback_globals.early_set_loopback_id) { + switch_channel_set_variable(channel, "loopback_leg", "B"); + switch_channel_set_variable(channel, "is_loopback", "1"); + } if (tech_init(b_tech_pvt, b_session, switch_core_session_get_read_codec(session)) != SWITCH_STATUS_SUCCESS) { switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); switch_core_session_destroy(&b_session); @@ -320,7 +331,7 @@ static switch_status_t channel_on_init(switch_core_session_t *session) if (!zstr(argv[i])) { const char *val = switch_channel_get_variable(channel, argv[i]); - if(!zstr(val)) { + if (!zstr(val)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Transfer variable [%s]=[%s] %s -> %s\n", argv[i], val, switch_channel_get_name(channel), switch_channel_get_name(tech_pvt->other_channel)); @@ -338,6 +349,8 @@ static switch_status_t channel_on_init(switch_core_session_t *session) switch_channel_set_variable(channel, "other_loopback_leg_uuid", switch_channel_get_uuid(b_channel)); switch_channel_set_variable(b_channel, "other_loopback_leg_uuid", switch_channel_get_uuid(channel)); + switch_channel_set_variable(b_channel, "other_loopback_from_uuid", switch_channel_get_variable(channel, "loopback_from_uuid")); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(b_session), SWITCH_LOG_DEBUG, "setting other_loopback_from_uuid on b leg to %s\n", switch_channel_get_variable(channel, "loopback_from_uuid")); if (switch_core_session_thread_launch(b_session) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Error spawning thread\n"); @@ -474,6 +487,7 @@ static switch_status_t channel_on_execute(switch_core_session_t *session) if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "loopback::bowout") == SWITCH_STATUS_SUCCESS) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-UUID", switch_channel_get_uuid(channel)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-Peer-UUID", switch_channel_get_uuid(tech_pvt->other_channel)); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Acquired-UUID", switch_channel_get_uuid(other_channel)); switch_event_fire(&event); } @@ -485,12 +499,14 @@ static switch_status_t channel_on_execute(switch_core_session_t *session) switch_channel_set_caller_profile(other_channel, clone); } + switch_channel_set_variable(channel, "loopback_hangup_cause", "bowout"); + switch_channel_set_variable(tech_pvt->channel, "loopback_bowout_other_uuid", switch_channel_get_uuid(other_channel)); switch_channel_caller_extension_masquerade(channel, other_channel, 0); switch_channel_set_state(other_channel, CS_RESET); switch_channel_wait_for_state(other_channel, NULL, CS_RESET); switch_channel_set_state(other_channel, CS_EXECUTE); switch_core_session_rwunlock(other_session); - switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_UNSPECIFIED); + switch_channel_hangup(channel, loopback_globals.bowout_hangup_cause); } } @@ -588,6 +604,7 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int case SWITCH_SIG_BREAK: break; case SWITCH_SIG_KILL: + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel)); switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); switch_clear_flag_locked(tech_pvt, TFLAG_LINKED); switch_mutex_lock(tech_pvt->mutex); @@ -600,8 +617,6 @@ static switch_status_t channel_kill_channel(switch_core_session_t *session, int break; } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s CHANNEL KILL\n", switch_channel_get_name(channel)); - return SWITCH_STATUS_SUCCESS; } @@ -700,7 +715,12 @@ static switch_status_t channel_read_frame(switch_core_session_t *session, switch *frame = NULL; if (!switch_channel_ready(channel)) { - goto end; + if (loopback_globals.ignore_channel_ready) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL NOT READY - IGNORED\n"); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "CHANNEL NOT READY\n"); + goto end; + } } switch_core_timer_next(&tech_pvt->timer); @@ -840,6 +860,7 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc tech_pvt->other_tech_pvt && switch_test_flag(tech_pvt, TFLAG_BRIDGE) && !switch_test_flag(tech_pvt, TFLAG_BLEG) && + (!loopback_globals.bowout_disable_on_inner_bridge || !switch_channel_test_flag(tech_pvt->channel, CF_INNER_BRIDGE)) && switch_test_flag(tech_pvt->other_tech_pvt, TFLAG_BRIDGE) && switch_channel_test_flag(tech_pvt->channel, CF_BRIDGED) && switch_channel_test_flag(tech_pvt->other_channel, CF_BRIDGED) && @@ -889,8 +910,47 @@ static switch_status_t channel_write_frame(switch_core_session_t *session, switc switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s detected bridge on both ends, attempting direct connection.\n", switch_channel_get_name(channel)); + if (loopback_globals.bowout_transfer_recordings) { + switch_ivr_transfer_recordings(session, br_a); + switch_ivr_transfer_recordings(tech_pvt->other_session, br_b); + } + + if (loopback_globals.fire_bowout_event_bridge) { + switch_event_t *event = NULL; + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "loopback::direct") == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(tech_pvt->channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-UUID", switch_channel_get_uuid(tech_pvt->channel)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-Peer-UUID", switch_channel_get_uuid(tech_pvt->other_channel)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Connecting-Leg-A-UUID", switch_channel_get_uuid(ch_a)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Connecting-Leg-B-UUID", switch_channel_get_uuid(ch_b)); + switch_event_fire(&event); + } + + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "loopback::direct") == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(tech_pvt->other_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-UUID", switch_channel_get_uuid(tech_pvt->other_channel)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Resigning-Peer-UUID", switch_channel_get_uuid(tech_pvt->channel)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Connecting-Leg-A-UUID", switch_channel_get_uuid(ch_b)); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Connecting-Leg-B-UUID", switch_channel_get_uuid(ch_a)); + switch_event_fire(&event); + } + } + /* channel_masquerade eat your heart out....... */ switch_ivr_uuid_bridge(a_uuid, b_uuid); + + switch_channel_set_variable(tech_pvt->channel, "loopback_hangup_cause", "bridge"); + switch_channel_set_variable(tech_pvt->channel, "loopback_bowout_other_uuid", switch_channel_get_uuid(ch_a)); + switch_channel_set_variable(tech_pvt->other_channel, "loopback_hangup_cause", "bridge"); + switch_channel_set_variable(tech_pvt->other_channel, "loopback_bowout_other_uuid", switch_channel_get_uuid(ch_b)); + + if (loopback_globals.bowout_controlled_hangup) { + switch_channel_set_flag(tech_pvt->channel, CF_INTERCEPTED); + switch_channel_set_flag(tech_pvt->other_channel, CF_INTERCEPTED); + switch_channel_hangup(tech_pvt->channel, loopback_globals.bowout_hangup_cause); + switch_channel_hangup(tech_pvt->other_channel, loopback_globals.bowout_hangup_cause); + } + good_to_go = 1; switch_mutex_unlock(tech_pvt->mutex); } @@ -971,6 +1031,18 @@ static switch_status_t channel_receive_message(switch_core_session_t *session, s case SWITCH_MESSAGE_INDICATE_BRIDGE: { switch_set_flag_locked(tech_pvt, TFLAG_BRIDGE); + if (switch_test_flag(tech_pvt, TFLAG_BLEG)) { + if (msg->string_arg) { + switch_core_session_t *bridged_session; + switch_channel_t *bridged_channel; + if ((bridged_session = switch_core_session_force_locate(msg->string_arg)) != NULL) { + bridged_channel = switch_core_session_get_channel(bridged_session); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(bridged_session), SWITCH_LOG_DEBUG, "setting other_leg_true_id to %s\n", switch_channel_get_variable(channel, "other_loopback_from_uuid")); + switch_channel_set_variable(bridged_channel, "other_leg_true_id", switch_channel_get_variable(channel, "other_loopback_from_uuid")); + switch_core_session_rwunlock(bridged_session); + } + } + } } break; case SWITCH_MESSAGE_INDICATE_UNBRIDGE: @@ -1092,6 +1164,10 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi channel = switch_core_session_get_channel(*new_session); switch_snprintf(name, sizeof(name), "loopback/%s-a", outbound_profile->destination_number); switch_channel_set_name(channel, name); + if (loopback_globals.early_set_loopback_id) { + switch_channel_set_variable(channel, "loopback_leg", "A"); + switch_channel_set_variable(channel, "is_loopback", "1"); + } if (tech_init(tech_pvt, *new_session, session ? switch_core_session_get_read_codec(session) : NULL) != SWITCH_STATUS_SUCCESS) { switch_core_session_destroy(new_session); return SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER; @@ -1106,6 +1182,11 @@ static switch_call_cause_t channel_outgoing_channel(switch_core_session_t *sessi switch_channel_set_private(channel, "__loopback_vars__", clone); } + if (ochannel) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_DEBUG, "setting loopback_from_uuid to %s\n", switch_channel_get_uuid(ochannel)); + switch_channel_set_variable(channel, "loopback_from_uuid", switch_channel_get_uuid(ochannel)); + } + if (outbound_profile) { char *dialplan = NULL, *context = NULL; @@ -1566,6 +1647,62 @@ static switch_io_routines_t null_channel_io_routines = { /*.receive_message */ null_channel_receive_message }; +switch_status_t load_loopback_configuration(switch_bool_t reload) +{ + switch_xml_t xml = NULL, x_lists = NULL, x_list = NULL, cfg = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + + memset(&loopback_globals, 0, sizeof(loopback_globals)); + + loopback_globals.bowout_hangup_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED; + + if ((xml = switch_xml_open_cfg("loopback.conf", &cfg, NULL))) { + status = SWITCH_STATUS_SUCCESS; + + if ((x_lists = switch_xml_child(cfg, "settings"))) { + for (x_list = switch_xml_child(x_lists, "param"); x_list; x_list = x_list->next) { + const char *name = switch_xml_attr(x_list, "name"); + const char *value = switch_xml_attr(x_list, "value"); + + if (zstr(name)) { + continue; + } + + if (zstr(value)) { + continue; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s = %s\n", name, value); + + if (!strcmp(name, "early-set-loopback-id")) { + loopback_globals.early_set_loopback_id = switch_true(value); + } else if (!strcmp(name, "fire-bowout-on-bridge")) { + loopback_globals.fire_bowout_event_bridge = switch_true(value); + } else if (!strcmp(name, "ignore-channel-ready")) { + loopback_globals.ignore_channel_ready = switch_true(value); + } else if (!strcmp(name, "bowout-hangup-cause")) { + loopback_globals.bowout_hangup_cause = switch_channel_str2cause(value); + } else if (!strcmp(name, "bowout-controlled-hangup")) { + loopback_globals.bowout_controlled_hangup = switch_true(value); + } else if (!strcmp(name, "bowout-transfer-recording")) { + loopback_globals.bowout_transfer_recordings = switch_true(value); + } else if (!strcmp(name, "bowout-disable-on-inner-bridge")) { + loopback_globals.bowout_disable_on_inner_bridge = switch_true(value); + } + + } + } + + switch_xml_free(xml); + } + + return status; +} + +static void loopback_reload_xml_event_handler(switch_event_t *event) +{ + load_loopback_configuration(1); +} SWITCH_MODULE_LOAD_FUNCTION(mod_loopback_load) { @@ -1576,8 +1713,12 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_loopback_load) return SWITCH_STATUS_TERM; } + if (switch_event_reserve_subclass("loopback::direct") != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't register subclass %s!\n", "loopback::direct"); + return SWITCH_STATUS_TERM; + } - memset(&globals, 0, sizeof(globals)); + load_loopback_configuration(0); /* connect my internal structure to the blank pointer passed to me */ *module_interface = switch_loadable_module_create_module_interface(pool, modname); @@ -1593,6 +1734,11 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_loopback_load) SWITCH_ADD_APP(app_interface, "unloop", "Tell loopback to unfold", "Tell loopback to unfold", unloop_function, "", SAF_NO_LOOPBACK); + if ((switch_event_bind(modname, SWITCH_EVENT_RELOADXML, NULL, loopback_reload_xml_event_handler, NULL) != SWITCH_STATUS_SUCCESS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind our reloadxml handler!\n"); + /* Not such severe to prevent loading */ + } + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } @@ -1601,6 +1747,8 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_loopback_shutdown) { switch_event_free_subclass("loopback::bowout"); + switch_event_free_subclass("loopback::direct"); + switch_event_unbind_callback(loopback_reload_xml_event_handler); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/endpoints/mod_sofia/Makefile.am b/src/mod/endpoints/mod_sofia/Makefile.am index 9d98a976a3..3adcb8ccea 100644 --- a/src/mod/endpoints/mod_sofia/Makefile.am +++ b/src/mod/endpoints/mod_sofia/Makefile.am @@ -9,7 +9,7 @@ SOFIAUA_BUILDDIR=$(SOFIA_BUILDDIR)/libsofia-sip-ua SOFIALA=$(SOFIAUA_BUILDDIR)/libsofia-sip-ua.la mod_LTLIBRARIES = mod_sofia.la -mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h +mod_sofia_la_SOURCES = mod_sofia.c sofia.c sofia_json_api.c sofia_glue.c sofia_presence.c sofia_reg.c sofia_media.c sip-dig.c rtp.c mod_sofia.h mod_sofia_la_CFLAGS = $(AM_CFLAGS) -I. $(SOFIA_CMD_LINE_CFLAGS) mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/bnf -I$(SOFIAUA_BUILDDIR)/bnf mod_sofia_la_CFLAGS += -I$(SOFIAUA_DIR)/http -I$(SOFIAUA_BUILDDIR)/http diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.2017.vcxproj b/src/mod/endpoints/mod_sofia/mod_sofia.2017.vcxproj index 442a50e830..e90e806c9d 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.2017.vcxproj +++ b/src/mod/endpoints/mod_sofia/mod_sofia.2017.vcxproj @@ -167,6 +167,7 @@ + diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index d4e6bb2285..c2900cf515 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -340,6 +340,17 @@ static int hangup_cause_to_sip(switch_call_cause_t cause) return 487; case SWITCH_CAUSE_EXCHANGE_ROUTING_ERROR: return 483; + /* Custom mappings not part of RFC */ + case SWITCH_CAUSE_BUSY_EVERYWHERE: + return 600; + case SWITCH_CAUSE_DECLINE: + return 603; + case SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE: + return 604; + case SWITCH_CAUSE_NOT_ACCEPTABLE: + return 606; + case SWITCH_CAUSE_UNWANTED: + return 607; default: return 480; } @@ -502,7 +513,7 @@ switch_status_t sofia_on_hangup(switch_core_session_t *session) switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Sending BYE to %s\n", switch_channel_get_name(channel)); if (!sofia_test_flag(tech_pvt, TFLAG_BYE)) { nua_bye(tech_pvt->nh, - TAG_IF(tech_pvt->record_route, NUTAG_PROXY(tech_pvt->record_route)), + TAG_IF(!zstr(tech_pvt->route_uri), NUTAG_PROXY(tech_pvt->route_uri)), SIPTAG_CONTACT(SIP_NONE), TAG_IF(!zstr(reason), SIPTAG_REASON_STR(reason)), TAG_IF(call_info, SIPTAG_CALL_INFO_STR(call_info)), @@ -2172,7 +2183,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi break; case SWITCH_MESSAGE_INDICATE_RESPOND: { - + printf("WHAT THE FUCKING HELL? %d\n", switch_channel_test_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE)); if (switch_channel_test_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE)) { switch_channel_clear_flag(tech_pvt->channel, CF_AWAITING_STREAM_CHANGE); @@ -2627,7 +2638,7 @@ static switch_status_t sofia_receive_event(switch_core_session_t *session, switc typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream); -static const char *sofia_state_names[] = { +const char *sofia_state_names[] = { "UNREGED", "TRYING", "REGISTER", @@ -2755,7 +2766,7 @@ static int sql2str_callback(void *pArg, int argc, char **argv, char **columnName return 0; } -static uint32_t sofia_profile_reg_count(sofia_profile_t *profile) +uint32_t sofia_profile_reg_count(sofia_profile_t *profile) { struct cb_helper_sql2str cb; char reg_count[80] = ""; @@ -4363,6 +4374,8 @@ SWITCH_STANDARD_API(sofia_function) func = cmd_status; } else if (!strcasecmp(argv[0], "xmlstatus")) { func = cmd_xml_status; + } else if (!strcasecmp(argv[0], "jsonstatus")) { + func = cmd_json_status; } else if (!strcasecmp(argv[0], "filter")) { if (argc > 1) { if (!strcasecmp(argv[1],"off")) { @@ -6265,6 +6278,8 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_sofia_load) management_interface->relative_oid = "1001"; management_interface->management_function = sofia_manage; + add_sofia_json_apis(module_interface); + SWITCH_ADD_APP(app_interface, "sofia_sla", "private sofia sla function", "private sofia sla function", sofia_sla_function, "", SAF_NONE); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.h b/src/mod/endpoints/mod_sofia/mod_sofia.h index cdb311f35a..de44aac283 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.h +++ b/src/mod/endpoints/mod_sofia/mod_sofia.h @@ -303,12 +303,16 @@ typedef enum { PFLAG_MAKE_EVERY_TRANSFER_A_NIGHTMARE, PFLAG_FIRE_TRANFER_EVENTS, PFLAG_BLIND_AUTH_ENFORCE_RESULT, + PFLAG_BLIND_AUTH_REPLY_403, PFLAG_PROXY_HOLD, PFLAG_PROXY_INFO, PFLAG_PROXY_MESSAGE, PFLAG_FIRE_BYE_RESPONSE_EVENTS, PFLAG_AUTO_INVITE_100, PFLAG_UPDATE_REFRESHER, + PFLAG_AUTH_REQUIRE_USER, + PFLAG_AUTH_CALLS_ACL_ONLY, + PFLAG_USE_PORT_FOR_ACL_CHECK, /* No new flags below this line */ PFLAG_MAX @@ -786,6 +790,8 @@ struct sofia_profile { int bind_attempt_interval; char *proxy_notify_events; char *proxy_info_content_types; + char *acl_inbound_x_token_header; + char *acl_proxy_x_token_header; }; @@ -964,6 +970,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t switch_status_t sofia_proxy_sip_i_message(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, switch_core_session_t *session, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]); void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]); +void sofia_handle_sip_i_invite_replaces(switch_core_session_t *session, switch_channel_t *channel, switch_channel_t *b_channel, char* uuid, private_object_t *tech_pvt, sip_call_info_t *call_info, sofia_profile_t *profile, char *is_nat, sip_t const *sip); void sofia_reg_handle_sip_i_register(nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t **sofia_private, sip_t const *sip, @@ -1163,6 +1170,11 @@ void sofia_glue_restart_all_profiles(void); const char *sofia_state_string(int state); void sofia_wait_for_reply(struct private_object *tech_pvt, nua_event_t event, uint32_t timeout); +/* sofia api */ +switch_status_t cmd_json_status(char **argv, int argc, switch_stream_handle_t *stream); +uint32_t sofia_profile_reg_count(sofia_profile_t *profile); +void add_sofia_json_apis(switch_loadable_module_interface_t **module_interface); + /* * Logging control functions */ diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 4a5f64fa51..d1e32a096f 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -4591,6 +4591,10 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_clear_pflag(profile, PFLAG_MAKE_EVERY_TRANSFER_A_NIGHTMARE); sofia_clear_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS); sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); + sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_REPLY_403); + sofia_clear_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + sofia_clear_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + sofia_clear_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); profile->shutdown_type = "false"; profile->local_network = "localnet.auto"; sofia_set_flag(profile, TFLAG_ENABLE_SOA); @@ -5486,6 +5490,12 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) profile->nonce_ttl = atoi(val); } else if (!strcasecmp(var, "max-auth-validity") && !zstr(val)) { profile->max_auth_validity = atoi(val); + } else if (!strcasecmp(var, "auth-require-user")) { + if (switch_true(val)) { + sofia_set_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + } else { + sofia_clear_pflag(profile, PFLAG_AUTH_REQUIRE_USER); + } } else if (!strcasecmp(var, "accept-blind-reg")) { if (switch_true(val)) { sofia_set_pflag(profile, PFLAG_BLIND_REG); @@ -5901,6 +5911,28 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) } else { sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT); } + } else if (!strcasecmp(var, "blind-auth-reply-403")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_BLIND_AUTH_REPLY_403); + } else { + sofia_clear_pflag(profile, PFLAG_BLIND_AUTH_REPLY_403); + } + } else if (!strcasecmp(var, "auth-calls-acl-only")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + } else { + sofia_clear_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY); + } + } else if (!strcasecmp(var, "use-port-for-acl-check")) { + if(switch_true(val)) { + sofia_set_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); + } else { + sofia_clear_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK); + } + } else if (!strcasecmp(var, "apply-inbound-acl-x-token")) { + profile->acl_inbound_x_token_header = switch_core_strdup(profile->pool, val); + } else if (!strcasecmp(var, "apply-proxy-acl-x-token")) { + profile->acl_proxy_x_token_header = switch_core_strdup(profile->pool, val); } else if (!strcasecmp(var, "proxy-hold")) { if(switch_true(val)) { sofia_set_pflag(profile, PFLAG_PROXY_HOLD); @@ -9992,6 +10024,46 @@ void sofia_handle_sip_i_reinvite(switch_core_session_t *session, } +switch_status_t sofia_locate_user(char* user, switch_core_session_t *session, sip_t const *sip, switch_xml_t* x_user) +{ + char *username, *domain; + switch_event_t *v_event = NULL; + switch_status_t result = SWITCH_STATUS_FALSE; + + if (!session) { + return SWITCH_STATUS_FALSE; + } + + if (zstr(user)) { + return SWITCH_STATUS_FALSE; + } + + if (!(username = switch_core_session_strdup(session, user))) { + return SWITCH_STATUS_FALSE; + } + + if (!(domain = strchr(username, '@'))) { + return SWITCH_STATUS_FALSE; + } + + *domain++ = '\0'; + + if (switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS) == SWITCH_STATUS_SUCCESS) { + sip_unknown_t *un; + for (un = sip->sip_unknown; un; un = un->un_next) { + switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); + }; + } + + result = switch_xml_locate_user_merged("id", username, domain, NULL, x_user, v_event); + + if (v_event) { + switch_event_destroy(&v_event); + } + + return result; +} + void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, sofia_dispatch_event_t *de, tagi_t tags[]) { char key[128] = ""; @@ -10181,14 +10253,23 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia int ok = 1; char *last_acl = NULL; const char *token = NULL; + int acl_port = sofia_test_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK) ? network_port : 0; for (x = 0; x < profile->acl_count; x++) { last_acl = profile->acl[x]; - if ((ok = switch_check_network_list_ip_token(network_ip, last_acl, &token))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "verifying acl \"%s\" for ip/port %s:%i.\n", + switch_str_nil(last_acl), network_ip, acl_port); + if ((ok = switch_check_network_list_ip_port_token(network_ip, acl_port, last_acl, &token))) { if (profile->acl_pass_context[x]) { acl_context = profile->acl_pass_context[x]; } + if(!token && profile->acl_inbound_x_token_header) { + const char * x_auth_token = sofia_glue_get_unknown_header(sip, profile->acl_inbound_x_token_header); + if (!zstr(x_auth_token)) { + token = x_auth_token; + } + } break; } @@ -10213,75 +10294,105 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } } else { int network_ip_is_proxy = 0; + const char* x_auth_ip = network_ip; /* Check if network_ip is a proxy allowed to send us calls */ if (profile->proxy_acl_count) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%d acls to check for proxy\n", profile->proxy_acl_count); - } - - for (x = 0; x < profile->proxy_acl_count; x++) { - last_acl = profile->proxy_acl[x]; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "checking %s against acl %s\n", network_ip, last_acl); - if (switch_check_network_list_ip_token(network_ip, last_acl, &token)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is a proxy according to the %s acl\n", network_ip, last_acl); - network_ip_is_proxy = 1; - break; + for (x = 0; x < profile->proxy_acl_count; x++) { + last_acl = profile->proxy_acl[x]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "checking %s against acl %s\n", network_ip, last_acl); + if (switch_check_network_list_ip_port_token(network_ip, network_port, last_acl, &token)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s is a proxy according to the %s acl\n", network_ip, last_acl); + network_ip_is_proxy = 1; + break; + } } } + /* * if network_ip is a proxy allowed to send calls, check for auth * ip header and see if it matches against the inbound acl */ if (network_ip_is_proxy) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "network ip is a proxy\n"); + const char * x_auth_port = sofia_glue_get_unknown_header(sip, "X-AUTH-PORT"); + int x_auth_port_i = sofia_test_pflag(profile, PFLAG_USE_PORT_FOR_ACL_CHECK) ? zstr(x_auth_port) ? 0 : atoi(x_auth_port) : 0; - for (un = sip->sip_unknown; un; un = un->un_next) { - if (!strcasecmp(un->un_name, "X-AUTH-IP")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found auth ip [%s] header of [%s]\n", un->un_name, un->un_value); - if (!zstr(un->un_value)) { - for (x = 0; x < profile->acl_count; x++) { - last_acl = profile->acl[x]; - if ((ok = switch_check_network_list_ip_token(un->un_value, last_acl, &token))) { - switch_copy_string(proxied_client_ip, un->un_value, sizeof(proxied_client_ip)); - break; - } + /* + * if network_ip is a proxy allowed to send calls, + * authorize call if proxy provided matched token header + */ + if (profile->acl_proxy_x_token_header) { + const char * x_auth_token = sofia_glue_get_unknown_header(sip, profile->acl_proxy_x_token_header); + if (!zstr(x_auth_token)) { + token = x_auth_token; + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + ok = 1; + } + } + + if (!ok && (x_auth_ip = sofia_glue_get_unknown_header(sip, "X-AUTH-IP")) && !zstr(x_auth_ip)) { + for (x = 0; x < profile->acl_count; x++) { + last_acl = profile->acl[x]; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "verifying acl \"%s\" from proxy for ip/port %s:%i.\n", + switch_str_nil(last_acl), x_auth_ip, x_auth_port_i); + if ((ok = switch_check_network_list_ip_port_token(x_auth_ip, x_auth_port_i, last_acl, &token))) { + + switch_copy_string(proxied_client_ip, x_auth_ip, sizeof(proxied_client_ip)); + + if (profile->acl_pass_context[x]) { + acl_context = profile->acl_pass_context[x]; } + + break; + } + + if (profile->acl_fail_context[x]) { + acl_context = profile->acl_fail_context[x]; + } else { + acl_context = NULL; } } + } else { + x_auth_ip = network_ip; } } - if (!ok) { - - if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", network_ip, switch_str_nil(last_acl)); - - if (!acl_context) { - nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); - goto fail; - } - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", - network_ip, switch_str_nil(last_acl)); - } - } else { + if (ok) { if (token) { switch_set_string(acl_token, token); } if (sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Approved by acl \"%s[%s]\". Access Granted.\n", - proxied_client_ip, switch_str_nil(last_acl), acl_token); + x_auth_ip, switch_str_nil(last_acl), acl_token); switch_set_string(sip_acl_authed_by, last_acl); switch_set_string(sip_acl_token, acl_token); - is_auth = 1; - + } + } else { + if (!sofia_test_pflag(profile, PFLAG_AUTH_CALLS)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "IP %s Rejected by acl \"%s\"\n", x_auth_ip, switch_str_nil(last_acl)); + if (!acl_context) { + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP %s Rejected by acl \"%s\". Falling back to Digest auth.\n", + x_auth_ip, switch_str_nil(last_acl)); + } } } } } + + if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_AUTH_CALLS_ACL_ONLY)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "IP/Port %s %i Rejected by acls and auth-calls-acl-only flag is set, rejecting call\n", + network_ip, network_port); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; + } + if (!is_auth && sofia_test_pflag(profile, PFLAG_AUTH_CALLS) && sofia_test_pflag(profile, PFLAG_BLIND_AUTH)) { - char *user; + char *user = NULL; switch_status_t blind_result = SWITCH_STATUS_FALSE; if (!strcmp(network_ip, profile->sipip) && network_port == profile->sip_port) { @@ -10290,15 +10401,14 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (sip && sip->sip_from) { user = switch_core_session_sprintf(session, "%s@%s", sip->sip_from->a_url->url_user, sip->sip_from->a_url->url_host); - switch_event_create(&v_event, SWITCH_EVENT_REQUEST_PARAMS); - for (un = sip->sip_unknown; un; un = un->un_next) { - switch_event_add_header_string(v_event, SWITCH_STACK_BOTTOM, un->un_name, un->un_value); - }; - blind_result = switch_ivr_set_user_extended(session, user, v_event); - switch_event_destroy(&v_event); + blind_result = sofia_locate_user(user, session, sip, &x_user); } - if(!sofia_test_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT) || blind_result == SWITCH_STATUS_SUCCESS) { + if (!sofia_test_pflag(profile, PFLAG_BLIND_AUTH_ENFORCE_RESULT) || blind_result == SWITCH_STATUS_SUCCESS) { is_auth++; + } else if (sofia_test_pflag(profile, PFLAG_BLIND_AUTH_REPLY_403)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "blind auth enforce 403 enabled and couldn't find user %s, rejecting call\n", user); + nua_respond(nh, SIP_403_FORBIDDEN, TAG_END()); + goto fail; } } @@ -10342,11 +10452,13 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia if (*acl_token) { switch_channel_set_variable(channel, "acl_token", acl_token); - if (strchr(acl_token, '@')) { - if (switch_ivr_set_user(session, acl_token) == SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token); - } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token); + if (sofia_locate_user(acl_token, session, sip, &x_user) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user %s\n", acl_token); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user %s\n", acl_token); + if (sofia_test_pflag(profile, PFLAG_AUTH_REQUIRE_USER)) { + nua_respond(nh, SIP_480_TEMPORARILY_UNAVAILABLE, TAG_END()); + goto fail; } } } @@ -11016,186 +11128,44 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } } + if (sip && sip->sip_replaces) { + msg_common_t *rp_common = sip->sip_replaces->rp_common; + switch_channel_set_variable(channel, "sip_replaces_call_id", sip->sip_replaces->rp_call_id); + if (rp_common && rp_common->h_class->hc_params) { + int i, n; + msg_param_t const *params = * (msg_param_t const **) ((char *)rp_common + rp_common->h_class->hc_params); + for (i = 0; params[i]; i++) { + msg_param_t param = params[i]; + if (strchr(param, '=')) { + n = strcspn(param, "="); + switch_channel_set_variable_name_printf(channel, param + n + 1, "sip_replaces_%.*s", n, param); + } else { + switch_channel_set_variable_name_printf(channel, "true", "sip_replaces_%s", param); + } + } + } + } + if (bnh) { sofia_private_t *b_private = NULL; if ((b_private = nua_handle_magic(bnh))) { switch_core_session_t *b_session = NULL; - if ((b_session = switch_core_session_locate(b_private->uuid))) { switch_channel_t *b_channel = switch_core_session_get_channel(b_session); - const char *bridge_uuid; - switch_caller_profile_t *orig_cp, *cp; - //const char *sent_name, *sent_number; - orig_cp = switch_channel_get_caller_profile(b_channel); - tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name); - tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number); - - if (!call_info) { - tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name); - tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number); - } - - if (orig_cp) { - cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool, orig_cp); - switch_channel_set_originator_caller_profile(channel, cp); - } - -#if 0 - sent_name = switch_channel_get_variable(b_channel, "last_sent_callee_id_name"); - sent_number = switch_channel_get_variable(b_channel, "last_sent_callee_id_number"); - - if (!zstr(sent_name) && !zstr(sent_number)) { - tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, sent_name); - tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, sent_number); - } else { - if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { - tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name); - tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number); - } else { - tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name); - tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number); - } - } -#endif - - if (is_nat) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Setting NAT mode based on %s\n", is_nat); - } - - tech_pvt->caller_profile->dialplan = "inline"; - - bridge_uuid = switch_channel_get_partner_uuid(b_channel); - - if (call_info) { - switch_event_t *event = NULL; - - if (!zstr(bridge_uuid) && switch_channel_test_flag(b_channel, CF_LEG_HOLDING)) { - const char *b_call_id = switch_channel_get_variable(b_channel, "sip_call_id"); - - if (b_call_id) { - char *sql = switch_mprintf("update sip_dialogs set call_info_state='idle' where call_id='%q'", b_call_id); - if (mod_sofia_globals.debug_sla > 1) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "QUERY SQL %s\n", sql); - } - sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); - - switch_channel_presence(b_channel, "unknown", "idle", NULL); - } - switch_channel_set_flag(tech_pvt->channel, CF_SLA_INTERCEPT); - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,intercept:%s", bridge_uuid); - - if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) - && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_REPLACED) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(b_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_by", sip->sip_call_id->i_id); - switch_event_fire(&event); - } - } else { - switch_caller_profile_t *bcp = switch_channel_get_caller_profile(b_channel); - - if (switch_channel_test_flag(b_channel, CF_BRIDGE_ORIGINATOR)) { - switch_channel_set_flag(tech_pvt->channel, CF_BRIDGE_ORIGINATOR); - } - - if (!zstr(bcp->callee_id_name)) { - tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_name); - } - - if (!zstr(bcp->callee_id_number)) { - tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_number); - } - - - if (!zstr(bcp->caller_id_name)) { - tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_name); - } - - if (!zstr(bcp->caller_id_number)) { - tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_number); - } - - if (bcp->originatee_caller_profile) { - switch_caller_profile_t *cp; - - cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool, - bcp->originatee_caller_profile); - - switch_channel_set_originatee_caller_profile(tech_pvt->channel, cp); - } - - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, - "answer,sofia_sla:%s", b_private->uuid); - } - } else { - char const *a_leg = NULL; - char const *nightmare_xfer_uuid = NULL; - - switch_event_t *event = NULL; - if (sip->sip_replaces && sip->sip_replaces->rp_params && sip->sip_replaces->rp_call_id) { - a_leg = msg_header_find_param(sip->sip_replaces->rp_common, "a-leg"); - } - if(a_leg && switch_true(a_leg)) { - switch_channel_mark_hold(b_channel, SWITCH_FALSE); - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,intercept:%s", sip->sip_replaces->rp_call_id); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s picked up on a-leg\n", sip->sip_replaces->rp_call_id); - if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) - && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_INTERCEPTED) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(b_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "intercepted_by", sip->sip_call_id->i_id); - switch_event_fire(&event); - } - } else { - if ((nightmare_xfer_uuid = sofia_glue_get_unknown_header(sip, "X-FS-Refer-For"))) { - switch_channel_set_variable(b_channel, "transfer_refer_for", nightmare_xfer_uuid); - } - if ((nightmare_xfer_uuid = sofia_glue_get_unknown_header(sip, "X-FS-Refer-From"))) { - switch_channel_set_variable(b_channel, "transfer_refer_from", nightmare_xfer_uuid); - } - - if (!zstr(bridge_uuid)) { - if (sip->sip_replaces && sip->sip_replaces->rp_params && sip->sip_replaces->rp_call_id && switch_channel_test_flag(b_channel, CF_BRIDGED) && - switch_true(switch_find_parameter(*(sip->sip_replaces->rp_params), "early-only", switch_core_session_get_pool(session)))) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s intercept rejected\n", bridge_uuid); - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "hangup:CALL_REJECTED"); - } else { - switch_channel_mark_hold(b_channel, SWITCH_FALSE); - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,intercept:%s", bridge_uuid); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s intercepted\n", bridge_uuid); - if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) && - switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_INTERCEPTED) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(b_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "intercepted_by", sip->sip_call_id->i_id); - switch_event_fire(&event); - } - } - } else { - const char *b_app = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_VARIABLE); - const char *b_data = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE); - if (b_data && b_app) { - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s:%s", b_app, b_data); - } else if (b_app) { - tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s", b_app); - } - if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) - && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_REPLACED) == SWITCH_STATUS_SUCCESS) { - switch_channel_event_set_data(b_channel, event); - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_by", sip->sip_call_id->i_id); - switch_event_fire(&event); - } - switch_channel_hangup(b_channel, SWITCH_CAUSE_ATTENDED_TRANSFER); - } - } - } - + sofia_handle_sip_i_invite_replaces(session, channel, b_channel, b_private->uuid, tech_pvt, call_info, profile, is_nat, sip); switch_core_session_rwunlock(b_session); } } nua_handle_unref(bnh); + } else if (sip && sip->sip_replaces && sip->sip_replaces->rp_call_id) { + switch_core_session_t *b_session = NULL; + if ((b_session = switch_core_session_locate((char*) sip->sip_replaces->rp_call_id))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + sofia_handle_sip_i_invite_replaces(session, channel, b_channel, (char*) sip->sip_replaces->rp_call_id, tech_pvt, call_info, profile, is_nat, sip); + switch_core_session_rwunlock(b_session); + } } - - if (tech_pvt->caller_profile) { int first_history_info = 1; @@ -11410,6 +11380,183 @@ void sofia_handle_sip_i_invite(switch_core_session_t *session, nua_t *nua, sofia } +void sofia_handle_sip_i_invite_replaces(switch_core_session_t *session, switch_channel_t *channel, switch_channel_t *b_channel, char* uuid, private_object_t *tech_pvt, sip_call_info_t *call_info, sofia_profile_t *profile, char *is_nat, sip_t const *sip) +{ + const char *bridge_uuid; + switch_caller_profile_t *orig_cp, *cp; + //const char *sent_name, *sent_number; + orig_cp = switch_channel_get_caller_profile(b_channel); + tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name); + tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number); + + if (!call_info) { + tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name); + tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number); + } + + if (orig_cp) { + cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool, orig_cp); + switch_channel_set_originator_caller_profile(channel, cp); + } + +#if 0 + sent_name = switch_channel_get_variable(b_channel, "last_sent_callee_id_name"); + sent_number = switch_channel_get_variable(b_channel, "last_sent_callee_id_number"); + + if (!zstr(sent_name) && !zstr(sent_number)) { + tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, sent_name); + tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, sent_number); + } else { + if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_name); + tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->callee_id_number); + } else { + tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_name); + tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, orig_cp->caller_id_number); + } + } +#endif + + if (is_nat) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Setting NAT mode based on %s\n", is_nat); + } + + tech_pvt->caller_profile->dialplan = "inline"; + + bridge_uuid = switch_channel_get_partner_uuid(b_channel); + if (bridge_uuid) { + switch_core_session_t *bridge_session = NULL; + if ((bridge_session = switch_core_session_locate(bridge_uuid))) { + switch_core_session_rwunlock(bridge_session); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "could not locate partner_uuid %s, resetting\n", bridge_uuid); + bridge_uuid = NULL; + } + } + + if (call_info) { + switch_event_t *event = NULL; + + if (!zstr(bridge_uuid) && switch_channel_test_flag(b_channel, CF_LEG_HOLDING)) { + const char *b_call_id = switch_channel_get_variable(b_channel, "sip_call_id"); + + if (b_call_id) { + char *sql = switch_mprintf("update sip_dialogs set call_info_state='idle' where call_id='%q'", b_call_id); + if (mod_sofia_globals.debug_sla > 1) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "QUERY SQL %s\n", sql); + } + sofia_glue_execute_sql_now(profile, &sql, SWITCH_TRUE); + + switch_channel_presence(b_channel, "unknown", "idle", NULL); + } + switch_channel_set_flag(tech_pvt->channel, CF_SLA_INTERCEPT); + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, + "answer,intercept:%s", bridge_uuid); + + if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) + && sip && sip->sip_call_id + && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_REPLACED) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(b_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_by", sip->sip_call_id->i_id); + switch_event_fire(&event); + } + } else { + switch_caller_profile_t *bcp = switch_channel_get_caller_profile(b_channel); + + if (switch_channel_test_flag(b_channel, CF_BRIDGE_ORIGINATOR)) { + switch_channel_set_flag(tech_pvt->channel, CF_BRIDGE_ORIGINATOR); + } + + if (!zstr(bcp->callee_id_name)) { + tech_pvt->caller_profile->callee_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_name); + } + + if (!zstr(bcp->callee_id_number)) { + tech_pvt->caller_profile->callee_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->callee_id_number); + } + + + if (!zstr(bcp->caller_id_name)) { + tech_pvt->caller_profile->caller_id_name = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_name); + } + + if (!zstr(bcp->caller_id_number)) { + tech_pvt->caller_profile->caller_id_number = switch_core_strdup(tech_pvt->caller_profile->pool, bcp->caller_id_number); + } + + if (bcp->originatee_caller_profile) { + switch_caller_profile_t *cp; + + cp = switch_caller_profile_dup(tech_pvt->caller_profile->pool, + bcp->originatee_caller_profile); + + switch_channel_set_originatee_caller_profile(tech_pvt->channel, cp); + } + + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, + "answer,sofia_sla:%s", uuid); + } + } else { + char const *nightmare_xfer_uuid = NULL; + switch_event_t *event = NULL; + if (switch_channel_var_true(channel, "sip_replaces_a-leg")) { + switch_channel_mark_hold(b_channel, SWITCH_FALSE); + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,intercept:%s", sip->sip_replaces->rp_call_id); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s picked up on a-leg\n", sip->sip_replaces->rp_call_id); + if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) + && sip && sip->sip_call_id + && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_INTERCEPTED) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(b_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "intercepted_by", sip->sip_call_id->i_id); + switch_event_fire(&event); + } + } else { + if ((nightmare_xfer_uuid = sofia_glue_get_unknown_header(sip, "X-FS-Refer-For"))) { + switch_channel_set_variable(b_channel, "transfer_refer_for", nightmare_xfer_uuid); + } + if ((nightmare_xfer_uuid = sofia_glue_get_unknown_header(sip, "X-FS-Refer-From"))) { + switch_channel_set_variable(b_channel, "transfer_refer_from", nightmare_xfer_uuid); + } + + if (!zstr(bridge_uuid)) { + if (sip->sip_replaces && sip->sip_replaces->rp_params && sip->sip_replaces->rp_call_id && switch_channel_test_flag(b_channel, CF_BRIDGED) && + switch_true(switch_find_parameter(*(sip->sip_replaces->rp_params), "early-only", switch_core_session_get_pool(session)))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s intercept rejected\n", bridge_uuid); + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "hangup:CALL_REJECTED"); + } else { + switch_channel_mark_hold(b_channel, SWITCH_FALSE); + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,intercept:%s", bridge_uuid); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "call %s intercepted\n", bridge_uuid); + if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) + && sip && sip->sip_call_id + && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_INTERCEPTED) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(b_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "intercepted_by", sip->sip_call_id->i_id); + switch_event_fire(&event); + } + } + } else { + const char *b_app = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_VARIABLE); + const char *b_data = switch_channel_get_variable(b_channel, SWITCH_CURRENT_APPLICATION_DATA_VARIABLE); + if (b_data && b_app) { + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s:%s", b_app, b_data); + } else if (b_app) { + tech_pvt->caller_profile->destination_number = switch_core_sprintf(tech_pvt->caller_profile->pool, "answer,%s", b_app); + } + if (sofia_test_pflag(profile, PFLAG_FIRE_TRANFER_EVENTS) + && sip && sip->sip_call_id + && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, MY_EVENT_REPLACED) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(b_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_by", sip->sip_call_id->i_id); + switch_event_fire(&event); + } + switch_channel_hangup(b_channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + } + } + } + +} + void sofia_handle_sip_i_options(int status, char const *phrase, nua_t *nua, sofia_profile_t *profile, nua_handle_t *nh, sofia_private_t *sofia_private, sip_t const *sip, diff --git a/src/mod/endpoints/mod_sofia/sofia_glue.c b/src/mod/endpoints/mod_sofia/sofia_glue.c index d1431a1e57..46853771b9 100644 --- a/src/mod/endpoints/mod_sofia/sofia_glue.c +++ b/src/mod/endpoints/mod_sofia/sofia_glue.c @@ -926,12 +926,21 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) rpid_domain = "cluecon.com"; } + if (!zstr(tech_pvt->dest)) { + dst = sofia_glue_get_destination(tech_pvt->dest); + } + /* * Ignore transport chanvar and uri parameter for gateway connections * since all of them have been already taken care of in mod_sofia.c:sofia_outgoing_channel() */ if (tech_pvt->transport == SOFIA_TRANSPORT_UNKNOWN && zstr(tech_pvt->gateway_name)) { - if ((p = (char *) switch_stristr("port=", url))) { + if (dst && dst->route_uri) { + p = dst->route_uri; + } else { + p = url; + } + if ((p = (char *) switch_stristr("port=", p))) { p += 5; tech_pvt->transport = sofia_glue_str2transport(p); } else { @@ -1079,7 +1088,9 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) || ((val = switch_channel_get_variable(channel, "sip_sticky_contact")) && switch_true(val)))) { sofia_set_flag(tech_pvt, TFLAG_NAT); tech_pvt->record_route = switch_core_session_strdup(tech_pvt->session, url_str); - route_uri = tech_pvt->record_route; + if (!dst || !dst->route_uri) { + route_uri = tech_pvt->record_route; + } session_timeout = SOFIA_NAT_SESSION_TIMEOUT; switch_channel_set_variable(channel, "sip_nat_detected", "true"); } @@ -1251,7 +1262,9 @@ switch_status_t sofia_glue_do_invite(switch_core_session_t *session) } if (!zstr(tech_pvt->dest)) { - dst = sofia_glue_get_destination(tech_pvt->dest); + if (!dst) { + dst = sofia_glue_get_destination(tech_pvt->dest); + } if (dst->route_uri) { route_uri = sofia_overcome_sip_uri_weakness(tech_pvt->session, dst->route_uri, tech_pvt->transport, SWITCH_TRUE, NULL, NULL); @@ -1449,6 +1462,7 @@ switch_call_cause_t sofia_glue_sip_cause_to_freeswitch(int status) case 403: case 407: case 603: + case 607: return SWITCH_CAUSE_CALL_REJECTED; case 404: return SWITCH_CAUSE_UNALLOCATED_NUMBER; diff --git a/src/mod/endpoints/mod_sofia/sofia_json_api.c b/src/mod/endpoints/mod_sofia/sofia_json_api.c new file mode 100644 index 0000000000..49005b2021 --- /dev/null +++ b/src/mod/endpoints/mod_sofia/sofia_json_api.c @@ -0,0 +1,229 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2014, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Ken Rice + * Paul D. Tinsley + * Bret McDanel + * Raymond Chandler + * Emmanuel Schmidbauer + * Kathleen King + * + * + * mod_sofia.c -- SOFIA SIP Endpoint + * + */ + +/* Best viewed in a 160 x 60 VT100 Terminal or so the line below at least fits across your screen*/ +/*************************************************************************************************************************************************************/ +#include "mod_sofia.h" + + +typedef switch_status_t (*sofia_command_t) (char **argv, int argc, switch_stream_handle_t *stream); + +extern const char *sofia_state_names[]; + +switch_status_t build_sofia_status_json(cJSON * container) +{ + sofia_profile_t *profile = NULL; + sofia_gateway_t *gp; + switch_hash_index_t *hi; + void *val; + const void *vvar; + switch_mutex_lock(mod_sofia_globals.hash_mutex); + for (hi = switch_core_hash_first(mod_sofia_globals.profile_hash); hi; hi = switch_core_hash_next(&hi)) { + cJSON * jprofile = cJSON_CreateObject(); + cJSON * jstatus = cJSON_CreateObject(); + switch_core_hash_this(hi, &vvar, NULL, &val); + cJSON_AddItemToObject(container, (const char *)vvar, jprofile); + cJSON_AddItemToObject(jprofile, "status", jstatus); + profile = (sofia_profile_t *) val; + if (strcmp(vvar, profile->name)) { + cJSON_AddItemToObject(jstatus, "type", cJSON_CreateString("alias")); + cJSON_AddItemToObject(jstatus, "data", cJSON_CreateString(profile->name)); + cJSON_AddItemToObject(jstatus, "state", cJSON_CreateString("ALIASED")); + } else { + cJSON_AddItemToObject(jstatus, "type", cJSON_CreateString("profile")); + cJSON_AddItemToObject(jstatus, "state", cJSON_CreateString(sofia_test_pflag(profile, PFLAG_RUNNING) ? "RUNNING" : "DOWN")); + cJSON_AddItemToObject(jstatus, "in-use", cJSON_CreateNumber(profile->inuse)); + if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) { + cJSON_AddItemToObject(jstatus, "data", cJSON_CreateString(profile->url)); + } else if (sofia_test_pflag(profile, PFLAG_TLS)) { + cJSON_AddItemToObject(jstatus, "data", cJSON_CreateString(profile->tls_url)); + cJSON_AddItemToObject(jstatus, "transport", cJSON_CreateString("tls")); + } else if (profile->ws_bindurl) { + cJSON_AddItemToObject(jprofile, "data", cJSON_CreateString(profile->ws_bindurl)); + cJSON_AddItemToObject(jprofile, "transport", cJSON_CreateString("ws")); + } else if (profile->wss_bindurl) { + cJSON_AddItemToObject(jprofile, "data", cJSON_CreateString(profile->wss_bindurl)); + cJSON_AddItemToObject(jprofile, "transport", cJSON_CreateString("wss")); + } + + if (profile->gateways) { + cJSON *gateways = cJSON_CreateObject(); + cJSON_AddItemToObject(jprofile, "gateways", gateways); + for (gp = profile->gateways; gp; gp = gp->next) { + cJSON *gateway = cJSON_CreateObject(); + cJSON_AddItemToObject(gateways, gp->name, gateway); + switch_assert(gp->state < REG_STATE_LAST); + cJSON_AddItemToObject(gateway, "type", cJSON_CreateString("gateway")); + cJSON_AddItemToObject(gateway, "data", cJSON_CreateString(gp->register_to)); + cJSON_AddItemToObject(gateway, "state", cJSON_CreateString(sofia_state_names[gp->state])); + if (gp->state == REG_STATE_FAILED || gp->state == REG_STATE_TRYING) { + time_t now = switch_epoch_time_now(NULL); + if (gp->retry > now) { + cJSON_AddItemToObject(gateway, "retry", cJSON_CreateNumber(gp->retry - now)); + } else { + cJSON_AddItemToObject(gateway, "retry", cJSON_CreateString("never")); + } + } + } + } + } + } + switch_mutex_unlock(mod_sofia_globals.hash_mutex); + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t build_sofia_profile_info_json(cJSON * container) +{ + sofia_profile_t *profile = NULL; + cJSON *item, *iter = container->child; + while(iter) { + if ( (profile = sofia_glue_find_profile(iter->string))) { + cJSON *info = cJSON_CreateObject(); + cJSON_AddItemToObject(iter, "info", info); + + cJSON_AddItemToObject(info, "domain-name", cJSON_CreateString(profile->domain_name ? profile->domain_name : "N/A")); + if (strcasecmp(iter->string, profile->name)) { + cJSON_AddItemToObject(info, "alias-of", cJSON_CreateString(switch_str_nil(profile->name))); + } + + cJSON_AddItemToObject(info, "auto-nat", cJSON_CreateString(sofia_test_pflag(profile, PFLAG_AUTO_NAT) ? "true" : "false")); + cJSON_AddItemToObject(info, "db-name", cJSON_CreateString(profile->dbname ? profile->dbname : switch_str_nil(profile->odbc_dsn))); + cJSON_AddItemToObject(info, "pres-hosts", cJSON_CreateString(switch_str_nil(profile->presence_hosts))); + cJSON_AddItemToObject(info, "dialplan", cJSON_CreateString(switch_str_nil(profile->dialplan))); + cJSON_AddItemToObject(info, "context", cJSON_CreateString(switch_str_nil(profile->context))); + cJSON_AddItemToObject(info, "challenge-realm", cJSON_CreateString(zstr(profile->challenge_realm) ? "auto_to" : profile->challenge_realm)); + + item = cJSON_CreateStringArray((const char **)profile->rtpip, profile->rtpip_index); + cJSON_AddItemToObject(info, "rtp-ip", item); + + cJSON_AddItemToObject(info, "ext-rtp-ip", cJSON_CreateString(profile->extrtpip)); + cJSON_AddItemToObject(info, "sip-ip", cJSON_CreateString(switch_str_nil(profile->sipip))); + cJSON_AddItemToObject(info, "ext-sip-ip", cJSON_CreateString(switch_str_nil(profile->extsipip))); + + if (! sofia_test_pflag(profile, PFLAG_TLS) || ! profile->tls_only) { + cJSON_AddItemToObject(info, "url", cJSON_CreateString(switch_str_nil(profile->url))); + cJSON_AddItemToObject(info, "bind-url", cJSON_CreateString(switch_str_nil(profile->bindurl))); + } + if (sofia_test_pflag(profile, PFLAG_TLS)) { + cJSON_AddItemToObject(info, "tls-url", cJSON_CreateString(switch_str_nil(profile->tls_url))); + cJSON_AddItemToObject(info, "tls-bind-url", cJSON_CreateString(switch_str_nil(profile->tls_bindurl))); + } + if (profile->ws_bindurl) { + cJSON_AddItemToObject(info, "ws-bind-url", cJSON_CreateString(switch_str_nil(profile->ws_bindurl))); + } + if (profile->wss_bindurl) { + cJSON_AddItemToObject(info, "wss-bind-url", cJSON_CreateString(switch_str_nil(profile->wss_bindurl))); + } + + cJSON_AddItemToObject(info, "hold-music", cJSON_CreateString(switch_str_nil(profile->hold_music))); + cJSON_AddItemToObject(info, "outbound-proxy", cJSON_CreateString(zstr(profile->outbound_proxy) ? "N/A" : profile->outbound_proxy)); + + sofia_glue_release_profile(profile); + + } + + iter = iter->next; + + } + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_JSON_API(sofia_status_json_function) +{ + cJSON *ret = cJSON_CreateObject(); + cJSON *profiles = cJSON_CreateObject(); + cJSON_AddItemToObject(ret, "profiles", profiles); + build_sofia_status_json(profiles); + + *json_reply = ret; + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_JSON_API(sofia_status_info_json_function) +{ + cJSON *ret = cJSON_CreateObject(); + cJSON *profiles = cJSON_CreateObject(); + cJSON_AddItemToObject(ret, "profiles", profiles); + build_sofia_status_json(profiles); + build_sofia_profile_info_json(profiles); + + *json_reply = ret; + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t cmd_json_status(char **argv, int argc, switch_stream_handle_t *stream) +{ + char * json; + cJSON *ret = cJSON_CreateObject(); + cJSON *profiles = cJSON_CreateObject(); + cJSON_AddItemToObject(ret, "profiles", profiles); + build_sofia_status_json(profiles); + build_sofia_profile_info_json(profiles); + + json = cJSON_Print(ret); + stream->write_function(stream, "%s\n", json); + + switch_safe_free(json); + cJSON_Delete(ret); + + return SWITCH_STATUS_SUCCESS; +} + +void add_sofia_json_apis(switch_loadable_module_interface_t **module_interface) +{ + switch_json_api_interface_t *json_api_interface; + SWITCH_ADD_JSON_API(json_api_interface, "sofia.status", "sofia status JSON API", sofia_status_json_function, ""); + SWITCH_ADD_JSON_API(json_api_interface, "sofia.status.info", "sofia status JSON API", sofia_status_info_json_function, ""); +} + + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 6ad57d2760..0143b8487f 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -62,7 +62,8 @@ SWITCH_MODULE_DEFINITION(mod_verto, mod_verto_load, mod_verto_shutdown, mod_vert #define strerror_r(errno, buf, len) strerror_s(buf, len, errno) #endif -#define die(...) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, __VA_ARGS__); goto error +#define log_and_exit(severity, ...) switch_log_printf(SWITCH_CHANNEL_LOG, (severity), __VA_ARGS__); goto error +#define die(...) log_and_exit(SWITCH_LOG_WARNING, __VA_ARGS__) #define die_errno(fmt) do { char errbuf[BUFSIZ] = {0}; strerror_r(errno, (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", errno, (char *)&errbuf); } while(0) #define die_errnof(fmt, ...) do { char errbuf[BUFSIZ] = {0}; strerror_r(errno, (char *)&errbuf, sizeof(errbuf)); die(fmt ", errno=%d, %s\n", __VA_ARGS__, errno, (char *)&errbuf); } while(0) @@ -915,7 +916,7 @@ static switch_bool_t check_auth(jsock_t *jsock, cJSON *params, int *code, char * } - if (!strcmp(login, "root")) { + if (!strcmp(login, "root") && jsock->profile->root_passwd) { if (!(r = !strcmp(passwd, jsock->profile->root_passwd))) { *code = CODE_AUTH_FAILED; switch_snprintf(message, mlen, "Authentication Failure"); @@ -1797,14 +1798,21 @@ done: *wsh->buffer = '\0'; while(jsock->profile->running) { - int pflags = switch_wait_sock(jsock->client_socket, 3000, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP); + int pflags; + + if (wsh->ssl && SSL_pending(wsh->ssl) > 0) { + pflags = SWITCH_POLL_READ; + } else { + pflags = switch_wait_sock(jsock->client_socket, 3000, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP); + } if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); } - if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED", jsock->name); } - if (pflags & SWITCH_POLL_HUP) { die("%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); } - if (pflags & SWITCH_POLL_ERROR) { die("%s POLL ERROR\n", jsock->name); } - if (pflags & SWITCH_POLL_INVALID) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); } - if (pflags & SWITCH_POLL_READ) { + if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); } + if (pflags == 0) { /* keepalive socket poll timeout */ break; } + if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_READ)) { ssize_t bytes; bytes = ws_raw_read(wsh, wsh->buffer + wsh->datalen, wsh->buflen - wsh->datalen - 1, wsh->block); @@ -1834,8 +1842,6 @@ done: switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "socket %s is going to handle a new request\n", jsock->name); goto new_req; } - } else { - break; } } } @@ -1862,19 +1868,26 @@ static void client_run(jsock_t *jsock) ws_close(&jsock->ws, WS_NONE); goto error; } else { - die("%s WS SETUP FAILED\n", jsock->name); + log_and_exit(SWITCH_LOG_NOTICE, "%s WS SETUP FAILED\n", jsock->name); } } while(jsock->profile->running) { - int pflags = switch_wait_sock(jsock->client_socket, 50, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP); + int pflags; + + if (jsock->ws.ssl && SSL_pending(jsock->ws.ssl) > 0) { + pflags = SWITCH_POLL_READ; + } else { + pflags = switch_wait_sock(jsock->client_socket, 50, SWITCH_POLL_READ | SWITCH_POLL_ERROR | SWITCH_POLL_HUP); + } if (jsock->drop) { die("%s Dropping Connection\n", jsock->name); } - if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED", jsock->name); } - if (pflags & SWITCH_POLL_HUP) { die("%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); } - if (pflags & SWITCH_POLL_ERROR) { die("%s POLL ERROR\n", jsock->name); } - if (pflags & SWITCH_POLL_INVALID) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); } - if (pflags & SWITCH_POLL_READ) { + if (pflags < 0 && (errno != EINTR)) { die_errnof("%s POLL FAILED with %d", jsock->name, pflags); } + if (pflags == 0) {/* socket poll timeout */ jsock_check_event_queue(jsock); } + if (pflags > 0 && (pflags & SWITCH_POLL_HUP)) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_ERROR)) { die("%s POLL ERROR\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_INVALID)) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", jsock->name); } + if (pflags > 0 && (pflags & SWITCH_POLL_READ)) { switch_ssize_t bytes; ws_opcode_t oc; uint8_t *data; @@ -1883,7 +1896,7 @@ static void client_run(jsock_t *jsock) if (bytes < 0) { if (bytes == -WS_RECV_CLOSE) { - die("%s Client sent close request\n", jsock->name); + log_and_exit(SWITCH_LOG_INFO, "%s Client sent close request\n", jsock->name); } else { die("%s BAD READ %" SWITCH_SSIZE_T_FMT "\n", jsock->name, bytes); } @@ -1963,8 +1976,6 @@ static void client_run(jsock_t *jsock) switch_set_flag(jsock, JPFLAG_CHECK_ATTACH); } } - } else { - jsock_check_event_queue(jsock); } } @@ -4410,8 +4421,9 @@ static int profile_one_loop(verto_profile_t *profile) if ((res = switch_wait_socklist(pfds, max, 100)) < 0) { if (errno != EINTR) { - die_errnof("%s POLL FAILED", profile->name); + die_errnof("%s POLL FAILED with %d", profile->name, res); } + return 0; } if (res == 0) { @@ -4419,7 +4431,7 @@ static int profile_one_loop(verto_profile_t *profile) } for (x = 0; x < max; x++) { - if (pfds[x].revents & SWITCH_POLL_HUP) { die("%s POLL HANGUP DETECTED (peer closed its end of socket)\n", profile->name); } + if (pfds[x].revents & SWITCH_POLL_HUP) { log_and_exit(SWITCH_LOG_INFO, "%s POLL HANGUP DETECTED (peer closed its end of socket)\n", profile->name); } if (pfds[x].revents & SWITCH_POLL_ERROR) { die("%s POLL ERROR\n", profile->name); } if (pfds[x].revents & SWITCH_POLL_INVALID) { die("%s POLL INVALID SOCKET (not opened or already closed)\n", profile->name); } if (pfds[x].revents & SWITCH_POLL_READ) { @@ -4523,9 +4535,9 @@ static int runtime(verto_profile_t *profile) } if (ok) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s MCAST Bound to %s:%d/%d\n", profile->name, profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s MCAST Bound to %s:%d/%d\n", profile->name, profile->mcast_ip, profile->mcast_port, profile->mcast_port + 1); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s MCAST Disabled\n", profile->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s MCAST Disabled\n", profile->name); } } diff --git a/src/mod/event_handlers/mod_amqp/mod_amqp_producer.c b/src/mod/event_handlers/mod_amqp/mod_amqp_producer.c index 305b366ddb..d4479b1752 100644 --- a/src/mod/event_handlers/mod_amqp/mod_amqp_producer.c +++ b/src/mod/event_handlers/mod_amqp/mod_amqp_producer.c @@ -175,7 +175,7 @@ switch_status_t mod_amqp_producer_create(char *name, switch_xml_t cfg) char *format_fields[MAX_ROUTING_KEY_FORMAT_FIELDS+1]; int format_fields_size = 0; - memset(format_fields, 0, MAX_ROUTING_KEY_FORMAT_FIELDS + 1); + memset(format_fields, 0, (MAX_ROUTING_KEY_FORMAT_FIELDS + 1) * sizeof(char *)); if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { goto err; diff --git a/src/mod/event_handlers/mod_kazoo/Makefile.am b/src/mod/event_handlers/mod_kazoo/Makefile.am index 53fd7112e1..668d9ffed2 100644 --- a/src/mod/event_handlers/mod_kazoo/Makefile.am +++ b/src/mod/event_handlers/mod_kazoo/Makefile.am @@ -3,12 +3,31 @@ MODNAME=mod_kazoo if HAVE_ERLANG +KAZOO_DEFS=kazoo_definitions.o + mod_LTLIBRARIES = mod_kazoo.la -mod_kazoo_la_SOURCES = mod_kazoo.c kazoo_utils.c kazoo_node.c kazoo_event_stream.c kazoo_fetch_agent.c kazoo_commands.c kazoo_dptools.c -mod_kazoo_la_CFLAGS = $(AM_CFLAGS) @ERLANG_CFLAGS@ -D_REENTRANT -mod_kazoo_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_kazoo_la_SOURCES = mod_kazoo.c kazoo_utils.c kazoo_dptools.c kazoo_tweaks.c +mod_kazoo_la_SOURCES += kazoo_api.c kazoo_commands.c kazoo_config.c +mod_kazoo_la_SOURCES += kazoo_message.c +mod_kazoo_la_SOURCES += kazoo_ei_config.c kazoo_ei_utils.c kazoo_event_stream.c +mod_kazoo_la_SOURCES += kazoo_fetch_agent.c kazoo_node.c +mod_kazoo_la_SOURCES += kazoo_endpoints.c +mod_kazoo_la_SOURCES += kz_node.c + +mod_kazoo_la_CFLAGS = $(AM_CFLAGS) @ERLANG_CFLAGS@ -D_REENTRANT -DERLANG_VERSION=@ERLANG_VERSION@ -DERLANG_MAJOR=@ERLANG_MAJOR@ -DERLANG_MINOR=@ERLANG_MINOR@ +mod_kazoo_la_LIBADD = $(KAZOO_DEFS) $(switch_builddir)/libfreeswitch.la mod_kazoo_la_LDFLAGS = -avoid-version -module -no-undefined -shared @ERLANG_LDFLAGS@ +BUILT_SOURCES = $(KAZOO_DEFS) + +$(KAZOO_DEFS): kazoo.conf.xml + +.S.o: $< + @$(CC) $(CFLAGS) -o $@ -c $< + +install-exec-am: + @install `which epmd` $(DESTDIR)$(bindir)/fs_epmd + else install: error all: error diff --git a/src/mod/event_handlers/mod_kazoo/kazoo.conf.xml b/src/mod/event_handlers/mod_kazoo/kazoo.conf.xml new file mode 100644 index 0000000000..a869420681 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo.conf.xml @@ -0,0 +1,1205 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_api.c b/src/mod/event_handlers/mod_kazoo/kazoo_api.c new file mode 100644 index 0000000000..b070f86336 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_api.c @@ -0,0 +1,551 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Karl Anderson + * Darren Schreiber + * + * + * mod_kazoo.c -- Socket Controlled Event Handler + * + */ +#include "mod_kazoo.h" + +#define KAZOO_DESC "kazoo information" +#define KAZOO_SYNTAX " []" + +#define API_COMMAND_DISCONNECT 0 +#define API_COMMAND_REMOTE_IP 1 +#define API_COMMAND_STREAMS 2 +#define API_COMMAND_BINDINGS 3 +#define API_COMMAND_OPTION 4 + +#define API_NODE_OPTION_FRAMING 0 +#define API_NODE_OPTION_LEGACY 1 +#define API_NODE_OPTION_MAX 99 + +static const char *node_runtime_options[] = { + "event-stream-framing", + "enable-legacy", + NULL +}; + +static int api_find_node_option(char *option) { + int i; + for(i = 0; node_runtime_options[i] != NULL; i++) { + if(!strcasecmp(option, node_runtime_options[i])) { + return i; + } + } + return API_NODE_OPTION_MAX; +} + +static switch_status_t api_get_node_option(ei_node_t *ei_node, switch_stream_handle_t *stream, char *arg) { + int option = api_find_node_option(arg); + switch_status_t ret = SWITCH_STATUS_SUCCESS; + switch (option) { + case API_NODE_OPTION_FRAMING: + stream->write_function(stream, "+OK %i", ei_node->event_stream_framing); + break; + + case API_NODE_OPTION_LEGACY: + stream->write_function(stream, "+OK %s", ei_node->legacy ? "true" : "false"); + break; + + default: + stream->write_function(stream, "-ERR invalid option %s", arg); + ret = SWITCH_STATUS_NOTFOUND; + break; + } + + return ret; +} + +static switch_status_t api_set_node_option(ei_node_t *ei_node, switch_stream_handle_t *stream, char *name, char *value) { + int option = api_find_node_option(name); + short val; + switch_status_t ret = SWITCH_STATUS_SUCCESS; + switch (option) { + case API_NODE_OPTION_FRAMING: + val = atoi(value); + if (val != 1 && val != 2 && val != 4) { + stream->write_function(stream, "-ERR Invalid event stream framing value (%i)", val); + ret = SWITCH_STATUS_GENERR; + } else { + stream->write_function(stream, "+OK %i", val); + ei_node->event_stream_framing = val; + } + break; + + case API_NODE_OPTION_LEGACY: + ei_node->legacy = switch_true(value); + stream->write_function(stream, "+OK %s", ei_node->legacy ? "true" : "false"); + break; + + default: + stream->write_function(stream, "-ERR invalid option %s", name); + ret = SWITCH_STATUS_NOTFOUND; + break; + } + + return ret; +} + +static switch_status_t api_erlang_status(switch_stream_handle_t *stream) { + switch_sockaddr_t *sa; + uint16_t port; + char ipbuf[48]; + const char *ip_addr; + ei_node_t *ei_node; + + switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor); + + port = switch_sockaddr_get_port(sa); + ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); + + stream->write_function(stream, "Running %s\n", VERSION); + stream->write_function(stream, "Listening for new Erlang connections on %s:%u with cookie %s\n", ip_addr, port, kazoo_globals.ei_cookie); + stream->write_function(stream, "Registered as Erlang node %s, visible as %s\n", kazoo_globals.ei_cnode.thisnodename, kazoo_globals.ei_cnode.thisalivename); + + if (kazoo_globals.ei_compat_rel) { + stream->write_function(stream, "Using Erlang compatibility mode: %d\n", kazoo_globals.ei_compat_rel); + } + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + if (!ei_node) { + stream->write_function(stream, "No erlang nodes connected\n"); + } else { + stream->write_function(stream, "Connected to:\n"); + while(ei_node != NULL) { + unsigned int year, day, hour, min, sec, delta; + + delta = (switch_micro_time_now() - ei_node->created_time) / 1000000; + sec = delta % 60; + min = delta / 60 % 60; + hour = delta / 3600 % 24; + day = delta / 86400 % 7; + year = delta / 31556926 % 12; + stream->write_function(stream, " %s (%s:%d) up %d years, %d days, %d hours, %d minutes, %d seconds\n" + ,ei_node->peer_nodename, ei_node->remote_ip, ei_node->remote_port, year, day, hour, min, sec); + ei_node = ei_node->next; + } + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t api_erlang_event_filter(switch_stream_handle_t *stream) { + switch_hash_index_t *hi = NULL; + int column = 0; + int idx = 0; + + for (hi = (switch_hash_index_t *)switch_core_hash_first_iter(kazoo_globals.event_filter, hi); hi; hi = switch_core_hash_next(&hi)) { + const void *key; + void *val; + switch_core_hash_this(hi, &key, NULL, &val); + stream->write_function(stream, "%-50s", (char *)key); + if (++column > 2) { + stream->write_function(stream, "\n"); + column = 0; + } + } + + if (++column > 2) { + stream->write_function(stream, "\n"); + column = 0; + } + + while(kazoo_globals.kazoo_var_prefixes[idx] != NULL) { + char var[100]; + char *prefix = kazoo_globals.kazoo_var_prefixes[idx]; + sprintf(var, "%s*", prefix); + stream->write_function(stream, "%-50s", var); + idx++; + } + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t api_erlang_nodes_list(switch_stream_handle_t *stream) { + ei_node_t *ei_node; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + stream->write_function(stream, "%s (%s)\n", ei_node->peer_nodename, ei_node->remote_ip); + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t api_erlang_nodes_count(switch_stream_handle_t *stream) { + ei_node_t *ei_node; + int count = 0; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + count++; + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + stream->write_function(stream, "%d\n", count); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t api_complete_erlang_node(const char *line, const char *cursor, switch_console_callback_match_t **matches) { + switch_console_callback_match_t *my_matches = NULL; + switch_status_t status = SWITCH_STATUS_FALSE; + ei_node_t *ei_node; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + switch_console_push_match(&my_matches, ei_node->peer_nodename); + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + if (my_matches) { + *matches = my_matches; + status = SWITCH_STATUS_SUCCESS; + } + + return status; +} + +static switch_status_t handle_node_api_event_stream(ei_event_stream_t *event_stream, switch_stream_handle_t *stream) { + ei_event_binding_t *binding; + int column = 0; + + switch_mutex_lock(event_stream->socket_mutex); + if (event_stream->connected == SWITCH_FALSE) { + switch_sockaddr_t *sa; + uint16_t port; + char ipbuf[48] = {0}; + const char *ip_addr; + + switch_socket_addr_get(&sa, SWITCH_TRUE, event_stream->acceptor); + port = switch_sockaddr_get_port(sa); + ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); + + if (zstr(ip_addr)) { + ip_addr = kazoo_globals.ip; + } + + stream->write_function(stream, "%s:%d -> disconnected\n" + ,ip_addr, port); + } else { + stream->write_function(stream, "%s:%d -> %s:%d\n" + ,event_stream->local_ip, event_stream->local_port + ,event_stream->remote_ip, event_stream->remote_port); + } + + binding = event_stream->bindings; + while(binding != NULL) { + if (binding->type == SWITCH_EVENT_CUSTOM) { + stream->write_function(stream, "CUSTOM %-43s", binding->subclass_name); + } else { + stream->write_function(stream, "%-50s", switch_event_name(binding->type)); + } + + if (++column > 2) { + stream->write_function(stream, "\n"); + column = 0; + } + + binding = binding->next; + } + switch_mutex_unlock(event_stream->socket_mutex); + + if (!column) { + stream->write_function(stream, "\n"); + } else { + stream->write_function(stream, "\n\n"); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t handle_node_api_event_streams(ei_node_t *ei_node, switch_stream_handle_t *stream) { + ei_event_stream_t *event_stream; + + switch_mutex_lock(ei_node->event_streams_mutex); + event_stream = ei_node->event_streams; + while(event_stream != NULL) { + handle_node_api_event_stream(event_stream, stream); + event_stream = event_stream->next; + } + switch_mutex_unlock(ei_node->event_streams_mutex); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t handle_node_api_command(ei_node_t *ei_node, switch_stream_handle_t *stream, uint32_t command) { + unsigned int year, day, hour, min, sec, delta; + + switch (command) { + case API_COMMAND_DISCONNECT: + stream->write_function(stream, "Disconnecting erlang node %s at managers request\n", ei_node->peer_nodename); + switch_clear_flag(ei_node, LFLAG_RUNNING); + break; + case API_COMMAND_REMOTE_IP: + delta = (switch_micro_time_now() - ei_node->created_time) / 1000000; + sec = delta % 60; + min = delta / 60 % 60; + hour = delta / 3600 % 24; + day = delta / 86400 % 7; + year = delta / 31556926 % 12; + + stream->write_function(stream, "Uptime %d years, %d days, %d hours, %d minutes, %d seconds\n", year, day, hour, min, sec); + stream->write_function(stream, "Local Address %s:%d\n", ei_node->local_ip, ei_node->local_port); + stream->write_function(stream, "Remote Address %s:%d\n", ei_node->remote_ip, ei_node->remote_port); + break; + case API_COMMAND_STREAMS: + handle_node_api_event_streams(ei_node, stream); + break; + case API_COMMAND_BINDINGS: + handle_api_command_streams(ei_node, stream); + break; + default: + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t api_erlang_node_command(switch_stream_handle_t *stream, const char *nodename, uint32_t command) { + ei_node_t *ei_node; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + int length = strlen(ei_node->peer_nodename); + + if (!strncmp(ei_node->peer_nodename, nodename, length)) { + handle_node_api_command(ei_node, stream, command); + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + return SWITCH_STATUS_SUCCESS; + } + + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + return SWITCH_STATUS_NOTFOUND; +} + +static switch_status_t handle_node_api_command_arg(ei_node_t *ei_node, switch_stream_handle_t *stream, uint32_t command, char *arg) { + + switch (command) { + case API_COMMAND_OPTION: + return api_get_node_option(ei_node, stream, arg); + break; + default: + break; + } + + return SWITCH_STATUS_NOTFOUND; +} + +static switch_status_t handle_node_api_command_args(ei_node_t *ei_node, switch_stream_handle_t *stream, uint32_t command, int argc, char *argv[]) { + + switch (command) { + case API_COMMAND_OPTION: + return api_set_node_option(ei_node, stream, argv[0], argv[1]); + break; + default: + break; + } + + return SWITCH_STATUS_NOTFOUND; +} + +static switch_status_t api_erlang_node_command_arg(switch_stream_handle_t *stream, const char *nodename, uint32_t command, char *arg) { + ei_node_t *ei_node; + switch_status_t ret = SWITCH_STATUS_NOTFOUND; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + int length = strlen(ei_node->peer_nodename); + + if (!strncmp(ei_node->peer_nodename, nodename, length)) { + ret = handle_node_api_command_arg(ei_node, stream, command, arg); + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + return ret ; + } + + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + return ret; +} + +static switch_status_t api_erlang_node_command_args(switch_stream_handle_t *stream, const char *nodename, uint32_t command, int argc, char *argv[]) { + ei_node_t *ei_node; + switch_status_t ret = SWITCH_STATUS_NOTFOUND; + + switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); + ei_node = kazoo_globals.ei_nodes; + while(ei_node != NULL) { + int length = strlen(ei_node->peer_nodename); + + if (!strncmp(ei_node->peer_nodename, nodename, length)) { + ret = handle_node_api_command_args(ei_node, stream, command, argc, argv); + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + return ret; + } + + ei_node = ei_node->next; + } + switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); + + return ret; +} + +SWITCH_STANDARD_API(exec_api_cmd) +{ + char *argv[1024] = { 0 }; + int unknown_command = 1, argc = 0; + char *mycmd = NULL; + + const char *usage_string = "USAGE:\n" + "--------------------------------------------------------------------------------------------------------------------\n" + "erlang status - provides an overview of the current status\n" + "erlang event_filter - lists the event headers that will be sent to Erlang nodes\n" + "erlang nodes list - lists connected Erlang nodes (usefull for monitoring tools)\n" + "erlang nodes count - provides a count of connected Erlang nodes (usefull for monitoring tools)\n" + "erlang node disconnect - disconnects an Erlang node\n" + "erlang node connection - Shows the connection info\n" + "erlang node event_streams - lists the event streams for an Erlang node\n" + "erlang node fetch_bindings - lists the XML fetch bindings for an Erlang node\n" + "---------------------------------------------------------------------------------------------------------------------\n"; + + if (zstr(cmd)) { + stream->write_function(stream, "%s", usage_string); + return SWITCH_STATUS_SUCCESS; + } + + if (!(mycmd = strdup(cmd))) { + return SWITCH_STATUS_MEMERR; + } + + if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { + stream->write_function(stream, "%s", usage_string); + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; + } + + if (zstr(argv[0])) { + stream->write_function(stream, "%s", usage_string); + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; + } + + if (!strncmp(argv[0], "status", 7)) { + unknown_command = 0; + api_erlang_status(stream); + } else if (!strncmp(argv[0], "event_filter", 13)) { + unknown_command = 0; + api_erlang_event_filter(stream); + } else if (!strncmp(argv[0], "nodes", 6) && !zstr(argv[1])) { + if (!strncmp(argv[1], "list", 6)) { + unknown_command = 0; + api_erlang_nodes_list(stream); + } else if (!strncmp(argv[1], "count", 6)) { + unknown_command = 0; + api_erlang_nodes_count(stream); + } + } else if (!strncmp(argv[0], "node", 6) && !zstr(argv[1]) && !zstr(argv[2])) { + if (!strncmp(argv[2], "disconnect", 11)) { + unknown_command = 0; + api_erlang_node_command(stream, argv[1], API_COMMAND_DISCONNECT); + } else if (!strncmp(argv[2], "connection", 11)) { + unknown_command = 0; + api_erlang_node_command(stream, argv[1], API_COMMAND_REMOTE_IP); + } else if (!strncmp(argv[2], "event_streams", 14)) { + unknown_command = 0; + api_erlang_node_command(stream, argv[1], API_COMMAND_STREAMS); + } else if (!strncmp(argv[2], "fetch_bindings", 15)) { + unknown_command = 0; + api_erlang_node_command(stream, argv[1], API_COMMAND_BINDINGS); + } else if (!strncmp(argv[2], "option", 7) && !zstr(argv[3])) { + unknown_command = 0; + if(argc > 4 && !zstr(argv[4])) + api_erlang_node_command_args(stream, argv[1], API_COMMAND_OPTION, argc - 3, &argv[3]); + else + api_erlang_node_command_arg(stream, argv[1], API_COMMAND_OPTION, argv[3]); + } + } + + if (unknown_command) { + stream->write_function(stream, "%s", usage_string); + } + + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + +void add_cli_api(switch_loadable_module_interface_t **module_interface, switch_api_interface_t *api_interface) +{ + SWITCH_ADD_API(api_interface, "erlang", KAZOO_DESC, exec_api_cmd, KAZOO_SYNTAX); + switch_console_set_complete("add erlang status"); + switch_console_set_complete("add erlang event_filter"); + switch_console_set_complete("add erlang nodes list"); + switch_console_set_complete("add erlang nodes count"); + switch_console_set_complete("add erlang node ::erlang::node disconnect"); + switch_console_set_complete("add erlang node ::erlang::node connection"); + switch_console_set_complete("add erlang node ::erlang::node event_streams"); + switch_console_set_complete("add erlang node ::erlang::node fetch_bindings"); + switch_console_add_complete_func("::erlang::node", api_complete_erlang_node); + +} + +void remove_cli_api() +{ + switch_console_set_complete("del erlang"); + switch_console_del_complete_func("::erlang::node"); + +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_commands.c b/src/mod/event_handlers/mod_kazoo/kazoo_commands.c index 2494bb9495..d61a1054ac 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_commands.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_commands.c @@ -31,6 +31,7 @@ * */ #include "mod_kazoo.h" +#include #include #define UUID_SET_DESC "Set a variable" @@ -42,7 +43,146 @@ #define KZ_HTTP_PUT_DESC "upload a local freeswitch file to a url" #define KZ_HTTP_PUT_SYNTAX "localfile url" -SWITCH_STANDARD_API(uuid_setvar_function) { +#define KZ_FIRST_OF_DESC "returns first-of existing event header in params" +#define KZ_FIRST_OF_SYNTAX "list of headers to check" + +#define MAX_FIRST_OF 25 + +#define MAX_HISTORY 50 +#define HST_ARRAY_DELIM "|:" +#define HST_ITEM_DELIM ':' + +static void process_history_item(char* value, cJSON *json) +{ + char *argv[4] = { 0 }; + char *item = strdup(value); + int argc = switch_separate_string(item, HST_ITEM_DELIM, argv, (sizeof(argv) / sizeof(argv[0]))); + cJSON *jitem = cJSON_CreateObject(); + char *epoch = NULL, *callid = NULL, *type = NULL; + int add = 0; + if(argc == 4) { + add = 1; + epoch = argv[0]; + callid = argv[1]; + type = argv[2]; + + if(!strncmp(type, "bl_xfer", 7)) { + char *split = strchr(argv[3], '/'); + if(split) *(split++) = '\0'; + cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid)); + cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("blind")); + cJSON_AddItemToObject(jitem, "Extension", cJSON_CreateString(argv[3])); + } else if(!strncmp(type, "att_xfer", 8)) { + char *split = strchr(argv[3], '/'); + if(split) { + *(split++) = '\0'; + cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid)); + cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("attended")); + cJSON_AddItemToObject(jitem, "Transferee", cJSON_CreateString(argv[3])); + cJSON_AddItemToObject(jitem, "Transferer", cJSON_CreateString(split)); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item); + add = 0; + } + } else if(!strncmp(type, "uuid_br", 7)) { + cJSON_AddItemToObject(jitem, "Call-ID", cJSON_CreateString(callid)); + cJSON_AddItemToObject(jitem, "Type", cJSON_CreateString("bridge")); + cJSON_AddItemToObject(jitem, "Other-Leg", cJSON_CreateString(argv[3])); + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE '%s' NOT HANDLED => %s\n", type, item); + add = 0; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER TYPE SPLIT ERROR %i => %s\n", argc, item); + } + if(add) { + cJSON_AddItemToObject(json, epoch, jitem); + } else { + cJSON_Delete(jitem); + } + switch_safe_free(item); +} + +SWITCH_STANDARD_API(kz_json_history) { + char *mycmd = NULL, *argv[MAX_HISTORY] = { 0 }; + int n, argc = 0; + cJSON *json = cJSON_CreateObject(); + char* output = NULL; + switch_event_header_t *header = NULL; + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + if (!strncmp(mycmd, "ARRAY::", 7)) { + mycmd += 7; + argc = switch_separate_string_string(mycmd, HST_ARRAY_DELIM, argv, (sizeof(argv) / sizeof(argv[0]))); + for(n=0; n < argc; n++) { + process_history_item(argv[n], json); + } + } else if (strchr(mycmd, HST_ITEM_DELIM)) { + process_history_item(mycmd, json); + } else if (stream->param_event) { + header = switch_event_get_header_ptr(stream->param_event, mycmd); + if (header != NULL) { + if(header->idx) { + for(n = 0; n < header->idx; n++) { + process_history_item(header->array[n], json); + } + } else { + process_history_item(header->value, json); + } + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER HISTORY HEADER NOT FOUND => %s\n", mycmd); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "TRANSFER HISTORY NOT PARSED => %s\n", mycmd); + } + } + output = cJSON_PrintUnformatted(json); + stream->write_function(stream, "%s", output); + switch_safe_free(output); + cJSON_Delete(json); + + return SWITCH_STATUS_SUCCESS; +} + +SWITCH_STANDARD_API(kz_first_of) { + char delim = '|'; + char *mycmd = NULL, *argv[MAX_FIRST_OF] = { 0 }; + int n, argc = 0; + switch_event_header_t *header = NULL; + if (!zstr(cmd) && (mycmd = strdup(cmd))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "FIRST-OF %s\n", mycmd); + if (!zstr(mycmd) && *mycmd == '^' && *(mycmd+1) == '^') { + mycmd += 2; + delim = *mycmd++; + } + argc = switch_separate_string(mycmd, delim, argv, (sizeof(argv) / sizeof(argv[0]))); + for(n=0; n < argc; n++) { + char* item = argv[n]; + if(*item == '#') { + if(*(++item) != '\0') { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING default %s\n", item); + stream->write_function(stream, item); + break; + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "CHECKING %s\n", item); + header = switch_event_get_header_ptr(stream->param_event, item); + if(header) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "RETURNING %s : %s\n", item, header->value); + stream->write_function(stream, header->value); + break; + } + } + } + } + + switch_safe_free(mycmd); + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t kz_uuid_setvar(int urldecode, const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) +{ switch_core_session_t *psession = NULL; char *mycmd = NULL, *argv[3] = { 0 }; int argc = 0; @@ -67,7 +207,11 @@ SWITCH_STANDARD_API(uuid_setvar_function) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n"); stream->write_function(stream, "-ERR No variable specified\n"); } else { + if(urldecode) { + switch_url_decode(var_value); + } switch_channel_set_variable(channel, var_name, var_value); + kz_check_set_profile_var(channel, var_name, var_value); stream->write_function(stream, "+OK\n"); } @@ -92,8 +236,20 @@ SWITCH_STANDARD_API(uuid_setvar_function) { return SWITCH_STATUS_SUCCESS; } -SWITCH_STANDARD_API(uuid_setvar_multi_function) { +SWITCH_STANDARD_API(uuid_setvar_function) +{ + return kz_uuid_setvar(0, cmd, session, stream); +} + +SWITCH_STANDARD_API(uuid_setvar_encoded_function) +{ + return kz_uuid_setvar(1, cmd, session, stream); +} + +switch_status_t kz_uuid_setvar_multi(int urldecode, const char *cmd, switch_core_session_t *session, switch_stream_handle_t *stream) +{ switch_core_session_t *psession = NULL; + char delim = ';'; char *mycmd = NULL, *vars, *argv[64] = { 0 }; int argc = 0; char *var_name, *var_value = NULL; @@ -104,12 +260,15 @@ SWITCH_STANDARD_API(uuid_setvar_multi_function) { goto done; } *vars++ = '\0'; - + if (*vars == '^' && *(vars+1) == '^') { + vars += 2; + delim = *vars++; + } if ((psession = switch_core_session_locate(uuid))) { switch_channel_t *channel = switch_core_session_get_channel(psession); switch_event_t *event; int x, y = 0; - argc = switch_separate_string(vars, ';', argv, (sizeof(argv) / sizeof(argv[0]))); + argc = switch_separate_string(vars, delim, argv, (sizeof(argv) / sizeof(argv[0]))); for (x = 0; x < argc; x++) { var_name = argv[x]; @@ -120,16 +279,11 @@ SWITCH_STANDARD_API(uuid_setvar_multi_function) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n"); stream->write_function(stream, "-ERR No variable specified\n"); } else { + if(urldecode) { + switch_url_decode(var_value); + } switch_channel_set_variable(channel, var_name, var_value); - if (!strcasecmp(var_name, "effective_callee_id_number")) { - switch_channel_set_profile_var(channel, "callee_id_number", var_value); - } else if (!strcasecmp(var_name, "effective_callee_id_name")) { - switch_channel_set_profile_var(channel, "callee_id_name", var_value); - } else if (!strcasecmp(var_name, "effective_caller_id_number")) { - switch_channel_set_profile_var(channel, "caller_id_number", var_value); - } else if (!strcasecmp(var_name, "effective_caller_id_name")) { - switch_channel_set_profile_var(channel, "caller_id_name", var_value); - }; + kz_check_set_profile_var(channel, var_name, var_value); y++; } @@ -158,6 +312,21 @@ SWITCH_STANDARD_API(uuid_setvar_multi_function) { return SWITCH_STATUS_SUCCESS; } +SWITCH_STANDARD_API(uuid_setvar_multi_function) +{ + return kz_uuid_setvar_multi(0, cmd, session, stream); +} + +SWITCH_STANDARD_API(uuid_setvar_multi_encoded_function) +{ + return kz_uuid_setvar_multi(1, cmd, session, stream); +} + +static size_t body_callback(char *buffer, size_t size, size_t nitems, void *userdata) +{ + return size * nitems; +} + static size_t header_callback(char *buffer, size_t size, size_t nitems, void *userdata) { switch_event_t* event = (switch_event_t*)userdata; @@ -182,6 +351,7 @@ SWITCH_STANDARD_API(kz_http_put) switch_event_t *params = NULL; char *url = NULL; char *filename = NULL; + int delete_file = 0; switch_curl_slist_t *headers = NULL; /* optional linked-list of HTTP headers */ char *ext; /* file extension, used for MIME type identification */ @@ -276,9 +446,12 @@ SWITCH_STANDARD_API(kz_http_put) switch_curl_easy_setopt(curl_handle, CURLOPT_INFILESIZE_LARGE, (curl_off_t)file_info.st_size); switch_curl_easy_setopt(curl_handle, CURLOPT_FOLLOWLOCATION, 1); switch_curl_easy_setopt(curl_handle, CURLOPT_MAXREDIRS, 10); - switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-http-cache/1.0"); + switch_curl_easy_setopt(curl_handle, CURLOPT_FAILONERROR, 1); + switch_curl_easy_setopt(curl_handle, CURLOPT_USERAGENT, "freeswitch-kazoo/1.0"); switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERDATA, stream->param_event); switch_curl_easy_setopt(curl_handle, CURLOPT_HEADERFUNCTION, header_callback); + switch_curl_easy_setopt(curl_handle, CURLOPT_WRITEFUNCTION, body_callback); + switch_curl_easy_setopt(curl_handle, CURLOPT_SSL_VERIFYPEER, 0L); switch_curl_easy_perform(curl_handle); switch_curl_easy_getinfo(curl_handle, CURLINFO_RESPONSE_CODE, &httpRes); @@ -286,22 +459,24 @@ SWITCH_STANDARD_API(kz_http_put) if (httpRes == 200 || httpRes == 201 || httpRes == 202 || httpRes == 204) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s saved to %s\n", filename, url); - switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-Output", "%s saved to %s\n", filename, url); - stream->write_function(stream, "+OK\n"); + switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-Output", "%s saved to %s", filename, url); + stream->write_function(stream, "+OK %s saved to %s", filename, url); + delete_file = 1; } else { error = switch_mprintf("Received HTTP error %ld trying to save %s to %s", httpRes, filename, url); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s\n", error); switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-Error", "%s", error); switch_event_add_header(stream->param_event, SWITCH_STACK_BOTTOM, "API-HTTP-Error", "%ld", httpRes); - stream->write_function(stream, "-ERR "); - stream->write_function(stream, error); - stream->write_function(stream, "\n"); + stream->write_function(stream, "-ERR %s", error); status = SWITCH_STATUS_GENERR; } done: if (file_to_put) { fclose(file_to_put); + if(delete_file) { + remove(filename); + } } if (headers) { @@ -326,9 +501,15 @@ done: void add_kz_commands(switch_loadable_module_interface_t **module_interface, switch_api_interface_t *api_interface) { SWITCH_ADD_API(api_interface, "kz_uuid_setvar_multi", UUID_SET_DESC, uuid_setvar_multi_function, UUID_MULTISET_SYNTAX); + SWITCH_ADD_API(api_interface, "kz_uuid_setvar_multi_encoded", UUID_SET_DESC, uuid_setvar_multi_encoded_function, UUID_MULTISET_SYNTAX); switch_console_set_complete("add kz_uuid_setvar_multi ::console::list_uuid"); + switch_console_set_complete("add kz_uuid_setvar_multi_encoded ::console::list_uuid"); SWITCH_ADD_API(api_interface, "kz_uuid_setvar", UUID_MULTISET_DESC, uuid_setvar_function, UUID_SET_SYNTAX); + SWITCH_ADD_API(api_interface, "kz_uuid_setvar_encoded", UUID_MULTISET_DESC, uuid_setvar_encoded_function, UUID_SET_SYNTAX); switch_console_set_complete("add kz_uuid_setvar ::console::list_uuid"); + switch_console_set_complete("add kz_uuid_setvar_encoded ::console::list_uuid"); SWITCH_ADD_API(api_interface, "kz_http_put", KZ_HTTP_PUT_DESC, kz_http_put, KZ_HTTP_PUT_SYNTAX); + SWITCH_ADD_API(api_interface, "first-of", KZ_FIRST_OF_DESC, kz_first_of, KZ_FIRST_OF_SYNTAX); + SWITCH_ADD_API(api_interface, "kz_json_history", KZ_FIRST_OF_DESC, kz_json_history, KZ_FIRST_OF_SYNTAX); } diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_config.c b/src/mod/event_handlers/mod_kazoo/kazoo_config.c new file mode 100644 index 0000000000..fcda9012ff --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_config.c @@ -0,0 +1,536 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#include "mod_kazoo.h" + +static const char *LOG_LEVEL_NAMES[] = { + "SWITCH_LOG_DEBUG10", + "SWITCH_LOG_DEBUG9", + "SWITCH_LOG_DEBUG8", + "SWITCH_LOG_DEBUG7", + "SWITCH_LOG_DEBUG6", + "SWITCH_LOG_DEBUG5", + "SWITCH_LOG_DEBUG4", + "SWITCH_LOG_DEBUG3", + "SWITCH_LOG_DEBUG2", + "SWITCH_LOG_DEBUG1", + "SWITCH_LOG_DEBUG", + "SWITCH_LOG_INFO", + "SWITCH_LOG_NOTICE", + "SWITCH_LOG_WARNING", + "SWITCH_LOG_ERROR", + "SWITCH_LOG_CRIT", + "SWITCH_LOG_ALERT", + "SWITCH_LOG_CONSOLE", + "SWITCH_LOG_INVALID", + "SWITCH_LOG_UNINIT", + NULL +}; + +static const switch_log_level_t LOG_LEVEL_VALUES[] = { + SWITCH_LOG_DEBUG10, + SWITCH_LOG_DEBUG9, + SWITCH_LOG_DEBUG8, + SWITCH_LOG_DEBUG7, + SWITCH_LOG_DEBUG6, + SWITCH_LOG_DEBUG5, + SWITCH_LOG_DEBUG4, + SWITCH_LOG_DEBUG3, + SWITCH_LOG_DEBUG2, + SWITCH_LOG_DEBUG1, + SWITCH_LOG_DEBUG, + SWITCH_LOG_INFO, + SWITCH_LOG_NOTICE, + SWITCH_LOG_WARNING, + SWITCH_LOG_ERROR, + SWITCH_LOG_CRIT, + SWITCH_LOG_ALERT, + SWITCH_LOG_CONSOLE, + SWITCH_LOG_INVALID, + SWITCH_LOG_UNINIT +}; + +switch_log_level_t log_str2level(const char *str) +{ + int x = 0; + switch_log_level_t level = SWITCH_LOG_INVALID; + + if (switch_is_number(str)) { + x = atoi(str); + + if (x > SWITCH_LOG_INVALID) { + return SWITCH_LOG_INVALID - 1; + } else if (x < 0) { + return 0; + } else { + return x; + } + } + + + for (x = 0;; x++) { + if (!LOG_LEVEL_NAMES[x]) { + break; + } + + if (!strcasecmp(LOG_LEVEL_NAMES[x], str)) { + level = LOG_LEVEL_VALUES[x]; //(switch_log_level_t) x; + break; + } + } + + return level; +} + +switch_status_t kazoo_config_loglevels(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_loglevels_ptr *ptr) +{ + switch_xml_t xml_level, xml_logging; + kazoo_loglevels_ptr loglevels = (kazoo_loglevels_ptr) switch_core_alloc(pool, sizeof(kazoo_loglevels_t)); + + loglevels->failed_log_level = SWITCH_LOG_ALERT; + loglevels->filtered_event_log_level = SWITCH_LOG_DEBUG1; + loglevels->filtered_field_log_level = SWITCH_LOG_DEBUG1; + loglevels->info_log_level = SWITCH_LOG_INFO; + loglevels->warn_log_level = SWITCH_LOG_WARNING; + loglevels->success_log_level = SWITCH_LOG_DEBUG; + loglevels->time_log_level = SWITCH_LOG_DEBUG1; + + if ((xml_logging = switch_xml_child(cfg, "logging")) != NULL) { + for (xml_level = switch_xml_child(xml_logging, "log"); xml_level; xml_level = xml_level->next) { + char *var = (char *) switch_xml_attr_soft(xml_level, "name"); + char *val = (char *) switch_xml_attr_soft(xml_level, "value"); + + if (!var) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "logging param missing 'name' attribute\n"); + continue; + } + + if (!val) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "logging param[%s] missing 'value' attribute\n", var); + continue; + } + + if (!strncmp(var, "success", 7)) { + loglevels->success_log_level = log_str2level(val); + } else if (!strncmp(var, "failed", 6)) { + loglevels->failed_log_level = log_str2level(val); + } else if (!strncmp(var, "info", 4)) { + loglevels->info_log_level = log_str2level(val); + } else if (!strncmp(var, "warn", 4)) { + loglevels->warn_log_level = log_str2level(val); + } else if (!strncmp(var, "time", 4)) { + loglevels->time_log_level = log_str2level(val); + } else if (!strncmp(var, "filtered-event", 14)) { + loglevels->filtered_event_log_level = log_str2level(val); + } else if (!strncmp(var, "filtered-field", 14)) { + loglevels->filtered_field_log_level = log_str2level(val); + } + } /* xml_level for loop */ + } + + *ptr = loglevels; + return SWITCH_STATUS_SUCCESS; + +} + +switch_status_t kazoo_config_filters(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_filter_ptr *ptr) +{ + switch_xml_t filters, filter; +// char *routing_key = NULL; + kazoo_filter_ptr root = NULL, prv = NULL, cur = NULL; + + + if ((filters = switch_xml_child(cfg, "filters")) != NULL) { + for (filter = switch_xml_child(filters, "filter"); filter; filter = filter->next) { + const char *var = switch_xml_attr(filter, "name"); + const char *val = switch_xml_attr(filter, "value"); + const char *type = switch_xml_attr(filter, "type"); + const char *compare = switch_xml_attr(filter, "compare"); + cur = (kazoo_filter_ptr) switch_core_alloc(pool, sizeof(kazoo_filter)); + memset(cur, 0, sizeof(kazoo_filter)); + if(prv == NULL) { + root = prv = cur; + } else { + prv->next = cur; + prv = cur; + } + cur->type = FILTER_EXCLUDE; + cur->compare = FILTER_COMPARE_VALUE; + + if(var) + cur->name = switch_core_strdup(pool, var); + + if(val) + cur->value = switch_core_strdup(pool, val); + + if(type) { + if (!strncmp(type, "exclude", 7)) { + cur->type = FILTER_EXCLUDE; + } else if (!strncmp(type, "include", 7)) { + cur->type = FILTER_INCLUDE; + } + } + + if(compare) { + if (!strncmp(compare, "value", 7)) { + cur->compare = FILTER_COMPARE_VALUE; + } else if (!strncmp(compare, "prefix", 6)) { + cur->compare = FILTER_COMPARE_PREFIX; + } else if (!strncmp(compare, "list", 4)) { + cur->compare = FILTER_COMPARE_LIST; + } else if (!strncmp(compare, "exists", 6)) { + cur->compare = FILTER_COMPARE_EXISTS; + } else if (!strncmp(compare, "regex", 5)) { + cur->compare = FILTER_COMPARE_REGEX; + } else if (!strncmp(compare, "field", 5)) { + cur->compare = FILTER_COMPARE_FIELD; + } + } + + if(cur->value == NULL) + cur->compare = FILTER_COMPARE_EXISTS; + + if(cur->compare == FILTER_COMPARE_LIST) { + cur->list.size = switch_separate_string(cur->value, '|', cur->list.value, MAX_LIST_FIELDS); + } + + } + + } + + *ptr = root; + + return SWITCH_STATUS_SUCCESS; + +} + +switch_status_t kazoo_config_field(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_field_ptr *ptr) +{ + const char *var = switch_xml_attr(cfg, "name"); + const char *val = switch_xml_attr(cfg, "value"); + const char *as = switch_xml_attr(cfg, "as"); + const char *type = switch_xml_attr(cfg, "type"); + const char *exclude_prefix = switch_xml_attr(cfg, "exclude-prefix"); + const char *serialize_as = switch_xml_attr(cfg, "serialize-as"); + kazoo_field_ptr cur = (kazoo_field_ptr) switch_core_alloc(pool, sizeof(kazoo_field)); + cur->in_type = FIELD_NONE; + cur->out_type = JSON_NONE; + + if(var) + cur->name = switch_core_strdup(pool, var); + + if(val) + cur->value = switch_core_strdup(pool, val); + + if(as) + cur->as = switch_core_strdup(pool, as); + + if(type) { + if (!strncmp(type, "copy", 4)) { + cur->in_type = FIELD_COPY; + } else if (!strncmp(type, "static", 6)) { + cur->in_type = FIELD_STATIC; + } else if (!strncmp(type, "first-of", 8)) { + cur->in_type = FIELD_FIRST_OF; + } else if (!strncmp(type, "expand", 6)) { + cur->in_type = FIELD_EXPAND; + } else if (!strncmp(type, "prefix", 10)) { + cur->in_type = FIELD_PREFIX; + } else if (!strncmp(type, "group", 5)) { + cur->in_type = FIELD_GROUP; + } else if (!strncmp(type, "reference", 9)) { + cur->in_type = FIELD_REFERENCE; + } + } + + if(serialize_as) { + if (!strncmp(serialize_as, "string", 5)) { + cur->out_type = JSON_STRING; + } else if (!strncmp(serialize_as, "number", 6)) { + cur->out_type = JSON_NUMBER; + } else if (!strncmp(serialize_as, "boolean", 7)) { + cur->out_type = JSON_BOOLEAN; + } else if (!strncmp(serialize_as, "object", 6)) { + cur->out_type = JSON_OBJECT; + } else if (!strncmp(serialize_as, "raw", 6)) { + cur->out_type = JSON_RAW; + } + } + + if(exclude_prefix) + cur->exclude_prefix = switch_true(exclude_prefix); + + kazoo_config_filters(pool, cfg, &cur->filter); + kazoo_config_fields(definitions, pool, cfg, &cur->children); + + if(cur->children != NULL + && (cur->in_type == FIELD_STATIC) + && (cur->out_type == JSON_NONE) + ) { + cur->out_type = JSON_OBJECT; + } + if(cur->in_type == FIELD_NONE) { + cur->in_type = FIELD_COPY; + } + + if(cur->out_type == JSON_NONE) { + cur->out_type = JSON_STRING; + } + + if(cur->in_type == FIELD_FIRST_OF) { + cur->list.size = switch_separate_string(cur->value, '|', cur->list.value, MAX_LIST_FIELDS); + } + + if(cur->in_type == FIELD_REFERENCE) { + cur->ref = (kazoo_definition_ptr)switch_core_hash_find(definitions->hash, cur->name); + if(cur->ref == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "referenced field %s not found\n", cur->name); + } + } + + *ptr = cur; + + return SWITCH_STATUS_SUCCESS; + +} + +switch_status_t kazoo_config_fields_loop(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_field_ptr *ptr) +{ + switch_xml_t field; + kazoo_field_ptr root = NULL, prv = NULL; + + + for (field = switch_xml_child(cfg, "field"); field; field = field->next) { + kazoo_field_ptr cur = NULL; + kazoo_config_field(definitions, pool, field, &cur); + if(root == NULL) { + root = prv = cur; + } else { + prv->next = cur; + prv = cur; + } + } + + *ptr = root; + + return SWITCH_STATUS_SUCCESS; + +} + +switch_status_t kazoo_config_fields(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_fields_ptr *ptr) +{ + switch_xml_t fields; + kazoo_fields_ptr root = NULL; + + + if ((fields = switch_xml_child(cfg, "fields")) != NULL) { + const char *verbose = switch_xml_attr(fields, "verbose"); + root = (kazoo_fields_ptr) switch_core_alloc(pool, sizeof(kazoo_fields)); + root->verbose = SWITCH_TRUE; + if(verbose) { + root->verbose = switch_true(verbose); + } + + kazoo_config_fields_loop(definitions, pool, fields, &root->head); + + } + + *ptr = root; + + return SWITCH_STATUS_SUCCESS; + +} + +kazoo_config_ptr kazoo_config_event_handlers(kazoo_config_ptr definitions, switch_xml_t cfg) +{ + switch_xml_t xml_profiles = NULL, xml_profile = NULL; + kazoo_config_ptr profiles = NULL; + switch_memory_pool_t *pool = NULL; + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for producers\n"); + return NULL; + } + + profiles = switch_core_alloc(pool, sizeof(kazoo_config)); + profiles->pool = pool; + switch_core_hash_init(&profiles->hash); + + if ((xml_profiles = switch_xml_child(cfg, "event-handlers"))) { + if ((xml_profile = switch_xml_child(xml_profiles, "profile"))) { + for (; xml_profile; xml_profile = xml_profile->next) { + const char *name = switch_xml_attr(xml_profile, "name"); + if(name == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing attr name\n" ); + continue; + } + kazoo_config_event_handler(definitions, profiles, xml_profile, NULL); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to locate a event-handler profile for kazoo\n" ); + } + } else { + destroy_config(&profiles); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate event-handlers section for kazoo, using default\n" ); + } + + return profiles; + +} + +kazoo_config_ptr kazoo_config_fetch_handlers(kazoo_config_ptr definitions, switch_xml_t cfg) +{ + switch_xml_t xml_profiles = NULL, xml_profile = NULL; + kazoo_config_ptr profiles = NULL; + switch_memory_pool_t *pool = NULL; + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for producers\n"); + return NULL; + } + + profiles = switch_core_alloc(pool, sizeof(kazoo_config)); + profiles->pool = pool; + switch_core_hash_init(&profiles->hash); + + if ((xml_profiles = switch_xml_child(cfg, "fetch-handlers"))) { + if ((xml_profile = switch_xml_child(xml_profiles, "profile"))) { + for (; xml_profile; xml_profile = xml_profile->next) { + const char *name = switch_xml_attr(xml_profile, "name"); + if(name == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing attr name\n" ); + continue; + } + kazoo_config_fetch_handler(definitions, profiles, xml_profile, NULL); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "unable to locate a fetch-handler profile for kazoo\n" ); + } + } else { + destroy_config(&profiles); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate fetch-handlers section for kazoo, using default\n" ); + } + + return profiles; + +} + + +switch_status_t kazoo_config_definition(kazoo_config_ptr root, switch_xml_t cfg) +{ + kazoo_definition_ptr definition = NULL; + char *name = (char *) switch_xml_attr_soft(cfg, "name"); + + if (zstr(name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to load kazoo profile, check definition missing name attr\n"); + return SWITCH_STATUS_GENERR; + } + + definition = switch_core_alloc(root->pool, sizeof(kazoo_definition)); + definition->name = switch_core_strdup(root->pool, name); + + kazoo_config_filters(root->pool, cfg, &definition->filter); + kazoo_config_fields_loop(root, root->pool, cfg, &definition->head); + + if ( switch_core_hash_insert(root->hash, name, (void *) definition) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to insert new definition [%s] into kazoo definitions hash\n", name); + return SWITCH_STATUS_GENERR; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "definition[%s] successfully configured\n", definition->name); + return SWITCH_STATUS_SUCCESS; +} + +kazoo_config_ptr kazoo_config_definitions(switch_xml_t cfg) +{ + switch_xml_t xml_definitions = NULL, xml_definition = NULL; + kazoo_config_ptr definitions = NULL; + switch_memory_pool_t *pool = NULL; + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "error creating memory pool for definitions\n"); + return NULL; + } + + definitions = switch_core_alloc(pool, sizeof(kazoo_config)); + definitions->pool = pool; + switch_core_hash_init(&definitions->hash); + + if ((xml_definitions = switch_xml_child(cfg, "definitions"))) { + if ((xml_definition = switch_xml_child(xml_definitions, "definition"))) { + for (; xml_definition; xml_definition = xml_definition->next) { + kazoo_config_definition(definitions, xml_definition); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "no definitions for kazoo\n" ); + } + } else { + destroy_config(&definitions); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "unable to locate definitions section for kazoo, using default\n" ); + } + + return definitions; +} + +void destroy_config(kazoo_config_ptr *ptr) +{ + kazoo_config_ptr config = NULL; + switch_memory_pool_t *pool; + + if (!ptr || !*ptr) { + return; + } + config = *ptr; + pool = config->pool; + + switch_core_hash_destroy(&(config->hash)); + switch_core_destroy_memory_pool(&pool); + + *ptr = NULL; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_config.h b/src/mod/event_handlers/mod_kazoo/kazoo_config.h new file mode 100644 index 0000000000..d0117fda5f --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_config.h @@ -0,0 +1,63 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#ifndef KAZOO_CONFIG_H +#define KAZOO_CONFIG_H + +#include + + +struct kazoo_config_t { + switch_hash_t *hash; + switch_memory_pool_t *pool; +}; + +switch_status_t kazoo_config_loglevels(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_loglevels_ptr *ptr); +switch_status_t kazoo_config_filters(switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_filter_ptr *ptr); +switch_status_t kazoo_config_fields(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_fields_ptr *ptr); + +switch_status_t kazoo_config_event_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_event_profile_ptr *ptr); +switch_status_t kazoo_config_fetch_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_fetch_profile_ptr *ptr); +kazoo_config_ptr kazoo_config_event_handlers(kazoo_config_ptr definitions, switch_xml_t cfg); +kazoo_config_ptr kazoo_config_fetch_handlers(kazoo_config_ptr definitions, switch_xml_t cfg); +kazoo_config_ptr kazoo_config_definitions(switch_xml_t cfg); +switch_status_t kazoo_config_field(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_field_ptr *ptr); +void destroy_config(kazoo_config_ptr *ptr); + +#endif /* KAZOO_CONFIG_H */ + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_definitions.S b/src/mod/event_handlers/mod_kazoo/kazoo_definitions.S new file mode 100644 index 0000000000..0bbe0137cb --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_definitions.S @@ -0,0 +1,8 @@ + .global kz_default_config + .global kz_default_config_size + .section .rodata +kz_default_config: + .incbin "kazoo.conf.xml" +1: +kz_default_config_size: + .int 1b - kz_default_config diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_dptools.c b/src/mod/event_handlers/mod_kazoo/kazoo_dptools.c index 0ea4cf6f2c..72e2afa18f 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_dptools.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_dptools.c @@ -52,7 +52,24 @@ #define EXPORT_LONG_DESC "Export many channel variables for the channel calling the application" #define EXPORT_SYNTAX "[^^]= =" -static void base_set (switch_core_session_t *session, const char *data, switch_stack_t stack) { +#define PREFIX_UNSET_SHORT_DESC "clear variables by prefix" +#define PREFIX_UNSET_LONG_DESC "clears the channel variables that start with prefix supplied" +#define PREFIX_UNSET_SYNTAX "" + +#define UUID_MULTISET_SHORT_DESC "Set many channel variables" +#define UUID_MULTISET_LONG_DESC "Set many channel variables for a specific channel" +#define UUID_MULTISET_SYNTAX " [^^]= =" + +#define KZ_ENDLESS_PLAYBACK_SHORT_DESC "Playback File Endlessly until break" +#define KZ_ENDLESS_PLAYBACK_LONG_DESC "Endlessly Playback a file to the channel until a break occurs" +#define KZ_ENDLESS_PLAYBACK_SYNTAX "" + +#define NOOP_SHORT_DESC "no operation" +#define NOOP_LONG_DESC "no operation. serves as a control point" +#define NOOP_SYNTAX "[]" + +static void base_set (switch_core_session_t *session, const char *data, int urldecode, switch_stack_t stack) +{ char *var, *val = NULL; if (zstr(data)) { @@ -75,31 +92,40 @@ static void base_set (switch_core_session_t *session, const char *data, switch_s } if (val) { + if(urldecode) { + switch_url_decode(val); + } expanded = switch_channel_expand_variables(channel, val); } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s]\n", switch_channel_get_name(channel), var, + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s] => [%s]\n", switch_channel_get_name(channel), var, val, expanded ? expanded : "UNDEF"); switch_channel_add_variable_var_check(channel, var, expanded, SWITCH_FALSE, stack); - - if (!strcasecmp(var, "effective_callee_id_number")) { - switch_channel_set_profile_var(channel, "callee_id_number", expanded); - } else if (!strcasecmp(var, "effective_callee_id_name")) { - switch_channel_set_profile_var(channel, "callee_id_name", expanded); - } else if (!strcasecmp(var, "effective_caller_id_number")) { - switch_channel_set_profile_var(channel, "caller_id_number", expanded); - } else if (!strcasecmp(var, "effective_caller_id_name")) { - switch_channel_set_profile_var(channel, "caller_id_name", expanded); - }; - - + kz_check_set_profile_var(channel, var, expanded); if (expanded && expanded != val) { switch_safe_free(expanded); } } } -static void base_export (switch_core_session_t *session, const char *data, switch_stack_t stack) { +static int kz_is_exported(switch_core_session_t *session, char *varname) +{ + char *array[256] = {0}; + int i, argc; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE); + char *arg = switch_core_session_strdup(session, exports); + argc = switch_split(arg, ',', array); + for(i=0; i < argc; i++) { + if(!strcasecmp(array[i], varname)) + return 1; + } + + return 0; +} + +static void base_export (switch_core_session_t *session, const char *data, int urldecode, switch_stack_t stack) +{ char *var, *val = NULL; if (zstr(data)) { @@ -121,21 +147,57 @@ static void base_export (switch_core_session_t *session, const char *data, switc } } - if (val) { - expanded = switch_channel_expand_variables(channel, val); - } + if (val) { + if(urldecode) { + switch_url_decode(val); + } + expanded = switch_channel_expand_variables(channel, val); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s EXPORT [%s]=[%s]\n", switch_channel_get_name(channel), var, - expanded ? expanded : "UNDEF"); - switch_channel_export_variable_var_check(channel, var, expanded, SWITCH_EXPORT_VARS_VARIABLE, SWITCH_FALSE); - - if (expanded && expanded != val) { - switch_safe_free(expanded); - } + if(!kz_is_exported(session, var)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s EXPORT [%s]=[%s]\n", switch_channel_get_name(channel), var, expanded ? expanded : "UNDEF"); + switch_channel_export_variable_var_check(channel, var, expanded, SWITCH_EXPORT_VARS_VARIABLE, SWITCH_FALSE); + } else { + if(strcmp(switch_str_nil(switch_channel_get_variable_dup(channel, var, SWITCH_FALSE, -1)), expanded)) { + switch_channel_set_variable(channel, var, expanded); + } + } + if (expanded && expanded != val) { + switch_safe_free(expanded); + } + } } } -SWITCH_STANDARD_APP(multiset_function) { +SWITCH_STANDARD_APP(prefix_unset_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_event_header_t *ei = NULL; + switch_event_t *clear; + char *arg = (char *) data; + + if(switch_event_create(&clear, SWITCH_EVENT_CLONE) != SWITCH_STATUS_SUCCESS) { + return; + } + + for (ei = switch_channel_variable_first(channel); ei; ei = ei->next) { + const char *name = ei->name; + char *value = ei->value; + if (!strncasecmp(name, arg, strlen(arg))) { + switch_event_add_header_string(clear, SWITCH_STACK_BOTTOM, name, value); + } + } + + switch_channel_variable_last(channel); + for (ei = clear->headers; ei; ei = ei->next) { + char *varname = ei->name; + switch_channel_set_variable(channel, varname, NULL); + } + + switch_event_destroy(&clear); +} + +void kz_multiset(switch_core_session_t *session, const char* data, int urldecode) +{ char delim = ' '; char *arg = (char *) data; switch_event_t *event; @@ -145,33 +207,107 @@ SWITCH_STANDARD_APP(multiset_function) { delim = *arg++; } - if (arg) { + if(delim != '\0') { switch_channel_t *channel = switch_core_session_get_channel(session); - char *array[256] = {0}; - int i, argc; + if (arg) { + char *array[256] = {0}; + int i, argc; - arg = switch_core_session_strdup(session, arg); - argc = switch_split(arg, delim, array); + arg = switch_core_session_strdup(session, arg); + argc = switch_split(arg, delim, array); - for(i = 0; i < argc; i++) { - base_set(session, array[i], SWITCH_STACK_BOTTOM); + for(i = 0; i < argc; i++) { + base_set(session, array[i], urldecode, SWITCH_STACK_BOTTOM); + } } - if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_fire(&event); } - } else { - base_set(session, data, SWITCH_STACK_BOTTOM); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiset with empty args\n"); } } -SWITCH_STANDARD_APP(set_function) { +SWITCH_STANDARD_APP(multiset_function) +{ + kz_multiset(session, data, 0); +} + +SWITCH_STANDARD_APP(multiset_encoded_function) +{ + kz_multiset(session, data, 1); +} + +void kz_uuid_multiset(switch_core_session_t *session, const char* data, int urldecode) +{ + char delim = ' '; + char *arg0 = (char *) data; + char *arg = strchr(arg0, ' '); + switch_event_t *event; + + + if(arg == NULL) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "uuid_multiset with invalid args\n"); + return; + } + *arg = '\0'; + arg++; + + if(zstr(arg0)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "uuid_multiset with invalid uuid\n"); + return; + } + + + if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') { + arg += 2; + delim = *arg++; + } + + if(delim != '\0') { + switch_core_session_t *uuid_session = NULL; + if ((uuid_session = switch_core_session_force_locate(arg0)) != NULL) { + switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session); + if (arg) { + char *array[256] = {0}; + int i, argc; + + arg = switch_core_session_strdup(session, arg); + argc = switch_split(arg, delim, array); + + for(i = 0; i < argc; i++) { + base_set(uuid_session, array[i], urldecode, SWITCH_STACK_BOTTOM); + } + } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(uuid_channel, event); + switch_event_fire(&event); + } + switch_core_session_rwunlock(uuid_session); + } else { + base_set(session, data, urldecode, SWITCH_STACK_BOTTOM); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiset with empty args\n"); + } +} + +SWITCH_STANDARD_APP(uuid_multiset_function) +{ + kz_uuid_multiset(session, data, 0); +} + +SWITCH_STANDARD_APP(uuid_multiset_encoded_function) +{ + kz_uuid_multiset(session, data, 1); +} + +void kz_set(switch_core_session_t *session, const char* data, int urldecode) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_t *event; - base_set(session, data, SWITCH_STACK_BOTTOM); + base_set(session, data, urldecode, SWITCH_STACK_BOTTOM); if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); @@ -179,6 +315,16 @@ SWITCH_STANDARD_APP(set_function) { } } +SWITCH_STANDARD_APP(set_function) +{ + kz_set(session, data, 0); +} + +SWITCH_STANDARD_APP(set_encoded_function) +{ + kz_set(session, data, 1); +} + SWITCH_STANDARD_APP(unset_function) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_t *event; @@ -205,55 +351,562 @@ SWITCH_STANDARD_APP(multiunset_function) { delim = *arg++; } - if (arg) { - char *array[256] = {0}; - int i, argc; + if(delim != '\0') { + if (arg) { + char *array[256] = {0}; + int i, argc; - arg = switch_core_session_strdup(session, arg); - argc = switch_split(arg, delim, array); + arg = switch_core_session_strdup(session, arg); + argc = switch_split(arg, delim, array); - for(i = 0; i < argc; i++) { - switch_channel_set_variable(switch_core_session_get_channel(session), array[i], NULL); + for(i = 0; i < argc; i++) { + switch_channel_set_variable(switch_core_session_get_channel(session), array[i], NULL); + } + + } else { + switch_channel_set_variable(switch_core_session_get_channel(session), arg, NULL); } - } else { - switch_channel_set_variable(switch_core_session_get_channel(session), arg, NULL); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "multiunset with empty args\n"); } } -SWITCH_STANDARD_APP(export_function) { - char delim = ' '; - char *arg = (char *) data; - if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') { - arg += 2; - delim = *arg++; - } +void kz_export(switch_core_session_t *session, const char* data, int urldecode) +{ + char delim = ' '; + char *arg = (char *) data; - if (arg) { - char *array[256] = {0}; - int i, argc; + if (!zstr(arg) && *arg == '^' && *(arg+1) == '^') { + arg += 2; + delim = *arg++; + } - arg = switch_core_session_strdup(session, arg); - argc = switch_split(arg, delim, array); + if(delim != '\0') { + if (arg) { + char *array[256] = {0}; + int i, argc; - for(i = 0; i < argc; i++) { - base_export(session, array[i], SWITCH_STACK_BOTTOM); - } - } else { - base_export(session, data, SWITCH_STACK_BOTTOM); - } + arg = switch_core_session_strdup(session, arg); + argc = switch_split(arg, delim, array); + + for(i = 0; i < argc; i++) { + base_export(session, array[i], urldecode, SWITCH_STACK_BOTTOM); + } + } else { + base_export(session, data, urldecode, SWITCH_STACK_BOTTOM); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "export with empty args\n"); + } +} + +SWITCH_STANDARD_APP(export_function) +{ + kz_export(session, data, 0); +} + +SWITCH_STANDARD_APP(export_encoded_function) +{ + kz_export(session, data, 1); +} + +// copied from mod_dptools with allow SWITCH_STATUS_BREAK +SWITCH_STANDARD_APP(kz_endless_playback_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_status_t status = SWITCH_STATUS_SUCCESS; + const char *file = data; + + while (switch_channel_ready(channel)) { + status = switch_ivr_play_file(session, NULL, file, NULL); + + if (status != SWITCH_STATUS_SUCCESS) { + break; + } + } + + switch (status) { + case SWITCH_STATUS_SUCCESS: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE PLAYED"); + break; + case SWITCH_STATUS_BREAK: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK_INTERRUPTED"); + break; + case SWITCH_STATUS_NOTFOUND: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "FILE NOT FOUND"); + break; + default: + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, "PLAYBACK ERROR"); + break; + } + +} + +SWITCH_STANDARD_APP(noop_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + const char *response = uuid_str; + + if (zstr(data)) { + switch_uuid_str(uuid_str, sizeof(uuid_str)); + } else { + response = data; + } + + switch_channel_set_variable(channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, response); +} + +SWITCH_STANDARD_APP(kz_restore_caller_id_function) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_caller_profile_t *cp = switch_channel_get_caller_profile(channel); + cp->caller_id_name = cp->orig_caller_id_name; + cp->caller_id_number = cp->orig_caller_id_number; +} + +SWITCH_STANDARD_APP(kz_audio_bridge_function) +{ + switch_channel_t *caller_channel = switch_core_session_get_channel(session); + switch_core_session_t *peer_session = NULL; + switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; + switch_status_t status = SWITCH_STATUS_FALSE; + + if (zstr(data)) { + return; + } + + status = switch_ivr_originate(session, &peer_session, &cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL); + + if (status != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "Originate Failed. Cause: %s\n", switch_channel_cause2str(cause)); + + switch_channel_set_variable(caller_channel, "originate_failed_cause", switch_channel_cause2str(cause)); + switch_channel_set_variable(caller_channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, switch_channel_cause2str(cause)); + switch_channel_handle_cause(caller_channel, cause); + + return; + } else { + const char* uuid = switch_core_session_get_uuid(session); + const char* peer_uuid = switch_core_session_get_uuid(peer_session); + + + switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session); + if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE)) || + switch_true(switch_channel_get_variable(peer_channel, SWITCH_BYPASS_MEDIA_AFTER_BRIDGE_VARIABLE))) { + switch_channel_set_flag(caller_channel, CF_BYPASS_MEDIA_AFTER_BRIDGE); + } + + while(1) { + const char *xfer_uuid; + switch_channel_state_t a_state , a_running_state; + switch_channel_state_t b_state , b_running_state; + status = switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "BRIDGE RESULT %i\n", status); + if(status != 0) { + break; + } + + a_state = switch_channel_get_state(caller_channel); + a_running_state = switch_channel_get_running_state(caller_channel); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A STATE %s %s => %s , %s\n", switch_channel_state_name(a_running_state), switch_channel_state_name(a_state), uuid, peer_uuid); + + if(a_state >= CS_HANGUP) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A HANGUP = %s , %s\n", uuid, peer_uuid); + break; + } + + b_state = switch_channel_get_state(peer_channel); + b_running_state = switch_channel_get_running_state(peer_channel); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B STATE %s %s => %s , %s\n", switch_channel_state_name(b_running_state), switch_channel_state_name(b_state), uuid, peer_uuid); + + if(b_state >= CS_HANGUP) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B HANGUP = %s , %s\n", uuid, peer_uuid); + switch_channel_set_variable(caller_channel, SWITCH_CURRENT_APPLICATION_RESPONSE_VARIABLE, switch_channel_cause2str(switch_channel_get_cause(peer_channel))); + break; + } + + if(!(xfer_uuid=switch_channel_get_variable(caller_channel, "att_xfer_peer_uuid"))) { + if(!(xfer_uuid=switch_channel_get_variable(peer_channel, "att_xfer_peer_uuid"))) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "XFER UUID NULL\n"); + break; + } + } + + switch_channel_set_variable(caller_channel, "att_xfer_peer_uuid", NULL); + switch_channel_set_variable(peer_channel, "att_xfer_peer_uuid", NULL); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "WAIT 1\n"); + + switch_channel_clear_flag(peer_channel, CF_UUID_BRIDGE_ORIGINATOR); + switch_channel_set_state(peer_channel, CS_RESET); + switch_channel_wait_for_state(peer_channel, NULL, CS_RESET); + switch_channel_clear_state_handler(peer_channel, NULL); + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "WAIT 3\n"); + + switch_channel_set_flag(caller_channel, CF_UUID_BRIDGE_ORIGINATOR); + switch_channel_clear_flag(caller_channel, CF_TRANSFER); + switch_channel_clear_flag(caller_channel, CF_REDIRECT); + switch_channel_set_flag(peer_channel, CF_UUID_BRIDGE_ORIGINATOR); + switch_channel_clear_flag(peer_channel, CF_TRANSFER); + switch_channel_clear_flag(peer_channel, CF_REDIRECT); + + if(!switch_channel_media_up(caller_channel)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "A MEDIA DOWN HANGUP = %s, %s , %s\n", xfer_uuid, uuid, peer_uuid); + } + if(!switch_channel_media_up(peer_channel)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "B MEDIA DOWN HANGUP = %s, %s , %s\n", xfer_uuid, uuid, peer_uuid); + } + switch_channel_set_state(caller_channel, CS_EXECUTE); + switch_channel_set_state(peer_channel, CS_EXECUTE); + + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "XFER LOOP %s %s , %s\n", xfer_uuid, uuid, peer_uuid); + + } + + if (peer_session) { + switch_core_session_rwunlock(peer_session); + } + } +} + +SWITCH_STANDARD_APP(kz_audio_bridge_uuid_function) +{ + switch_core_session_t *peer_session = NULL; + const char * peer_uuid = NULL; + + if (zstr(data)) { + return; + } + + peer_uuid = switch_core_session_strdup(session, data); + if (peer_uuid && (peer_session = switch_core_session_locate(peer_uuid))) { + switch_ivr_multi_threaded_bridge(session, peer_session, NULL, NULL, NULL); + } + + if (peer_session) { + switch_core_session_rwunlock(peer_session); + } +} + + +struct kz_att_keys { + const char *attxfer_cancel_key; + const char *attxfer_hangup_key; + const char *attxfer_conf_key; +}; + +static switch_status_t kz_att_xfer_on_dtmf(switch_core_session_t *session, void *input, switch_input_type_t itype, void *buf, unsigned int buflen) +{ + switch_core_session_t *peer_session = (switch_core_session_t *) buf; + if (!buf || !peer_session) { + return SWITCH_STATUS_SUCCESS; + } + + switch (itype) { + case SWITCH_INPUT_TYPE_DTMF: + { + switch_dtmf_t *dtmf = (switch_dtmf_t *) input; + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session); + struct kz_att_keys *keys = switch_channel_get_private(channel, "__kz_keys"); + + if (dtmf->digit == *keys->attxfer_hangup_key) { + switch_channel_hangup(channel, SWITCH_CAUSE_ATTENDED_TRANSFER); + return SWITCH_STATUS_FALSE; + } + + if (dtmf->digit == *keys->attxfer_cancel_key) { + switch_channel_hangup(peer_channel, SWITCH_CAUSE_NORMAL_CLEARING); + return SWITCH_STATUS_FALSE; + } + + if (dtmf->digit == *keys->attxfer_conf_key) { + switch_caller_extension_t *extension = NULL; + const char *app = "three_way"; + const char *app_arg = switch_core_session_get_uuid(session); + const char *holding = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); + switch_core_session_t *b_session; + + if (holding && (b_session = switch_core_session_locate(holding))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + if (!switch_channel_ready(b_channel)) { + app = "intercept"; + } + switch_core_session_rwunlock(b_session); + } + + if ((extension = switch_caller_extension_new(peer_session, app, app_arg)) == 0) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_CRIT, "Memory Error!\n"); + abort(); + } + + switch_caller_extension_add_application(peer_session, extension, app, app_arg); + switch_channel_set_caller_extension(peer_channel, extension); + switch_channel_set_state(peer_channel, CS_RESET); + switch_channel_wait_for_state(peer_channel, channel, CS_RESET); + switch_channel_set_state(peer_channel, CS_EXECUTE); + switch_channel_set_variable(channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE, NULL); + return SWITCH_STATUS_FALSE; + } + + } + break; + default: + break; + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t kz_att_xfer_tmp_hanguphook(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_state_t state = switch_channel_get_state(channel); + + if (state == CS_HANGUP || state == CS_ROUTING) { + const char *bond = switch_channel_get_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE); + + if (!zstr(bond)) { + switch_core_session_t *b_session; + + if ((b_session = switch_core_session_locate(bond))) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + if (switch_channel_up(b_channel)) { + switch_channel_set_flag(b_channel, CF_REDIRECT); + } + switch_core_session_rwunlock(b_session); + } + } + + switch_core_event_hook_remove_state_change(session, kz_att_xfer_tmp_hanguphook); + } + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t kz_att_xfer_hanguphook(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_state_t state = switch_channel_get_state(channel); + const char *id = NULL; + + if (state == CS_HANGUP || state == CS_ROUTING) { + if ((id = switch_channel_get_variable(channel, "xfer_uuids"))) { + switch_stream_handle_t stream = { 0 }; + SWITCH_STANDARD_STREAM(stream); + switch_api_execute("uuid_bridge", id, NULL, &stream); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "\nHangup Command uuid_bridge(%s):\n%s\n", id, + switch_str_nil((char *) stream.data)); + switch_safe_free(stream.data); + } + + switch_core_event_hook_remove_state_change(session, kz_att_xfer_hanguphook); + } + return SWITCH_STATUS_SUCCESS; +} + + +static void kz_att_xfer_set_result(switch_channel_t *channel, switch_status_t status) +{ + switch_channel_set_variable(channel, SWITCH_ATT_XFER_RESULT_VARIABLE, status == SWITCH_STATUS_SUCCESS ? "success" : "failure"); +} + +struct kz_att_obj { + switch_core_session_t *session; + const char *data; + int running; +}; + +void *SWITCH_THREAD_FUNC kz_att_thread_run(switch_thread_t *thread, void *obj) +{ + struct kz_att_obj *att = (struct kz_att_obj *) obj; + struct kz_att_keys *keys = NULL; + switch_core_session_t *session = att->session; + switch_core_session_t *peer_session = NULL; + const char *data = att->data; + switch_call_cause_t cause = SWITCH_CAUSE_NORMAL_CLEARING; + switch_channel_t *channel = switch_core_session_get_channel(session), *peer_channel = NULL; + const char *bond = NULL; + switch_core_session_t *b_session = NULL; + switch_bool_t follow_recording = switch_true(switch_channel_get_variable(channel, "recording_follow_attxfer")); + const char *attxfer_cancel_key = NULL, *attxfer_hangup_key = NULL, *attxfer_conf_key = NULL; + + att->running = 1; + + if (switch_core_session_read_lock(session) != SWITCH_STATUS_SUCCESS) { + return NULL; + } + + bond = switch_channel_get_partner_uuid(channel); + if ((b_session = switch_core_session_locate(bond)) == NULL) { + switch_core_session_rwunlock(peer_session); + return NULL; + } + + switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, bond); + switch_core_event_hook_add_state_change(session, kz_att_xfer_tmp_hanguphook); + + if (follow_recording && (b_session = switch_core_session_locate(bond))) { + switch_ivr_transfer_recordings(b_session, session); + switch_core_session_rwunlock(b_session); + } + + if (switch_ivr_originate(session, &peer_session, &cause, data, 0, NULL, NULL, NULL, NULL, NULL, SOF_NONE, NULL, NULL) + != SWITCH_STATUS_SUCCESS || !peer_session) { + switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond); + goto end; + } + + peer_channel = switch_core_session_get_channel(peer_session); + switch_channel_set_flag(peer_channel, CF_INNER_BRIDGE); + switch_channel_set_flag(channel, CF_INNER_BRIDGE); + + if (!(attxfer_cancel_key = switch_channel_get_variable(channel, "attxfer_cancel_key"))) { + if (!(attxfer_cancel_key = switch_channel_get_variable(peer_channel, "attxfer_cancel_key"))) { + attxfer_cancel_key = "#"; + } + } + + if (!(attxfer_hangup_key = switch_channel_get_variable(channel, "attxfer_hangup_key"))) { + if (!(attxfer_hangup_key = switch_channel_get_variable(peer_channel, "attxfer_hangup_key"))) { + attxfer_hangup_key = "*"; + } + } + + if (!(attxfer_conf_key = switch_channel_get_variable(channel, "attxfer_conf_key"))) { + if (!(attxfer_conf_key = switch_channel_get_variable(peer_channel, "attxfer_conf_key"))) { + attxfer_conf_key = "0"; + } + } + + keys = switch_core_session_alloc(session, sizeof(*keys)); + keys->attxfer_cancel_key = switch_core_session_strdup(session, attxfer_cancel_key); + keys->attxfer_hangup_key = switch_core_session_strdup(session, attxfer_hangup_key); + keys->attxfer_conf_key = switch_core_session_strdup(session, attxfer_conf_key); + switch_channel_set_private(channel, "__kz_keys", keys); + + switch_channel_set_variable(channel, "att_xfer_peer_uuid", switch_core_session_get_uuid(peer_session)); + + switch_ivr_multi_threaded_bridge(session, peer_session, kz_att_xfer_on_dtmf, peer_session, NULL); + + switch_channel_clear_flag(peer_channel, CF_INNER_BRIDGE); + switch_channel_clear_flag(channel, CF_INNER_BRIDGE); + + if (zstr(bond) && switch_channel_down(peer_channel)) { + switch_core_session_rwunlock(peer_session); + switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond); + goto end; + } + + if (bond) { + int br = 0; + + switch_channel_set_variable(channel, SWITCH_SIGNAL_BOND_VARIABLE, bond); + + if (!switch_channel_down(peer_channel)) { + /* + * we're emiting the transferee event so that callctl can update + */ + switch_event_t *event = NULL; + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, "sofia::transferee") == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(b_channel, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "att_xfer_replaced_call_id", switch_core_session_get_uuid(peer_session)); + switch_event_fire(&event); + } + if (!switch_channel_ready(channel)) { + switch_status_t status; + + if (follow_recording) { + switch_ivr_transfer_recordings(session, peer_session); + } + status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(peer_session), bond); + kz_att_xfer_set_result(peer_channel, status); + br++; + } else { + switch_channel_set_variable_printf(b_channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), switch_core_session_get_uuid(session)); + switch_channel_set_variable_printf(channel, "xfer_uuids", "%s %s", switch_core_session_get_uuid(peer_session), bond); + + switch_core_event_hook_add_state_change(session, kz_att_xfer_hanguphook); + switch_core_event_hook_add_state_change(b_session, kz_att_xfer_hanguphook); + } + } + +/* + * this was commented so that the existing bridge + * doesn't end + * + if (!br) { + switch_status_t status = switch_ivr_uuid_bridge(switch_core_session_get_uuid(session), bond); + att_xfer_set_result(channel, status); + } +*/ + + } + + switch_core_session_rwunlock(peer_session); + + end: + + switch_core_event_hook_remove_state_change(session, kz_att_xfer_tmp_hanguphook); + + switch_channel_set_variable(channel, SWITCH_SOFT_HOLDING_UUID_VARIABLE, NULL); + switch_channel_clear_flag(channel, CF_XFER_ZOMBIE); + + switch_core_session_rwunlock(b_session); + switch_core_session_rwunlock(session); + att->running = 0; + + return NULL; +} + +SWITCH_STANDARD_APP(kz_att_xfer_function) +{ + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + switch_memory_pool_t *pool = switch_core_session_get_pool(session); + struct kz_att_obj *att; + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_threadattr_create(&thd_attr, pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + switch_threadattr_detach_set(thd_attr, 1); + + att = switch_core_session_alloc(session, sizeof(*att)); + att->running = -1; + att->session = session; + att->data = switch_core_session_strdup(session, data); + switch_thread_create(&thread, thd_attr, kz_att_thread_run, att, pool); + + while(att->running && switch_channel_up(channel)) { + switch_yield(100000); + } } void add_kz_dptools(switch_loadable_module_interface_t **module_interface, switch_application_interface_t *app_interface) { - SWITCH_ADD_APP(app_interface, "kz_set", SET_SHORT_DESC, SET_LONG_DESC, set_function, SET_SYNTAX, - SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); - SWITCH_ADD_APP(app_interface, "kz_multiset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiset_function, MULTISET_SYNTAX, - SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); - SWITCH_ADD_APP(app_interface, "kz_unset", UNSET_SHORT_DESC, UNSET_LONG_DESC, unset_function, UNSET_SYNTAX, - SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); - SWITCH_ADD_APP(app_interface, "kz_multiunset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiunset_function, MULTIUNSET_SYNTAX, - SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); - SWITCH_ADD_APP(app_interface, "kz_export", EXPORT_SHORT_DESC, EXPORT_LONG_DESC, export_function, EXPORT_SYNTAX, - SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_set", SET_SHORT_DESC, SET_LONG_DESC, set_function, SET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_set_encoded", SET_SHORT_DESC, SET_LONG_DESC, set_encoded_function, SET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_multiset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiset_function, MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_multiset_encoded", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiset_encoded_function, MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_unset", UNSET_SHORT_DESC, UNSET_LONG_DESC, unset_function, UNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_multiunset", MULTISET_SHORT_DESC, MULTISET_LONG_DESC, multiunset_function, MULTIUNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_export", EXPORT_SHORT_DESC, EXPORT_LONG_DESC, export_function, EXPORT_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_export_encoded", EXPORT_SHORT_DESC, EXPORT_LONG_DESC, export_encoded_function, EXPORT_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_prefix_unset", PREFIX_UNSET_SHORT_DESC, PREFIX_UNSET_LONG_DESC, prefix_unset_function, PREFIX_UNSET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_uuid_multiset", UUID_MULTISET_SHORT_DESC, UUID_MULTISET_LONG_DESC, uuid_multiset_function, UUID_MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_uuid_multiset_encoded", UUID_MULTISET_SHORT_DESC, UUID_MULTISET_LONG_DESC, uuid_multiset_encoded_function, UUID_MULTISET_SYNTAX, SAF_SUPPORT_NOMEDIA | SAF_ROUTING_EXEC | SAF_ZOMBIE_EXEC); + SWITCH_ADD_APP(app_interface, "kz_endless_playback", KZ_ENDLESS_PLAYBACK_SHORT_DESC, KZ_ENDLESS_PLAYBACK_LONG_DESC, kz_endless_playback_function, KZ_ENDLESS_PLAYBACK_SYNTAX, SAF_NONE); + SWITCH_ADD_APP(app_interface, "kz_restore_caller_id", NOOP_SHORT_DESC, NOOP_LONG_DESC, kz_restore_caller_id_function, NOOP_SYNTAX, SAF_NONE); + SWITCH_ADD_APP(app_interface, "noop", NOOP_SHORT_DESC, NOOP_LONG_DESC, noop_function, NOOP_SYNTAX, SAF_NONE); + SWITCH_ADD_APP(app_interface, "kz_bridge", "Bridge Audio", "Bridge the audio between two sessions", kz_audio_bridge_function, "", SAF_SUPPORT_NOMEDIA|SAF_SUPPORT_TEXT_ONLY); + SWITCH_ADD_APP(app_interface, "kz_bridge_uuid", "Bridge Audio", "Bridge the audio between two sessions", kz_audio_bridge_uuid_function, "", SAF_SUPPORT_NOMEDIA|SAF_SUPPORT_TEXT_ONLY); + SWITCH_ADD_APP(app_interface, "kz_att_xfer", "Attended Transfer", "Attended Transfer", kz_att_xfer_function, "", SAF_NONE); } diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_ei.h b/src/mod/event_handlers/mod_kazoo/kazoo_ei.h new file mode 100644 index 0000000000..3d844655b7 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_ei.h @@ -0,0 +1,292 @@ +#ifndef KAZOO_EI_H +#define KAZOO_EI_H + +#include +#include + +#define MODNAME "mod_kazoo" +#define BUNDLE "community" +#define RELEASE "v1.5.0-1" +#define VERSION "mod_kazoo v1.5.0-1 community" + +#define KZ_MAX_SEPARATE_STRINGS 10 + +typedef enum {KAZOO_FETCH_PROFILE, KAZOO_EVENT_PROFILE} kazoo_profile_type; + +typedef enum {ERLANG_TUPLE, ERLANG_MAP} kazoo_json_term; + +typedef struct ei_xml_agent_s ei_xml_agent_t; +typedef ei_xml_agent_t *ei_xml_agent_ptr; + +typedef struct kazoo_event kazoo_event_t; +typedef kazoo_event_t *kazoo_event_ptr; + +typedef struct kazoo_event_profile kazoo_event_profile_t; +typedef kazoo_event_profile_t *kazoo_event_profile_ptr; + +typedef struct kazoo_fetch_profile kazoo_fetch_profile_t; +typedef kazoo_fetch_profile_t *kazoo_fetch_profile_ptr; + +typedef struct kazoo_config_t kazoo_config; +typedef kazoo_config *kazoo_config_ptr; + +#include "kazoo_fields.h" +#include "kazoo_config.h" + +struct ei_send_msg_s { + ei_x_buff buf; + erlang_pid pid; +}; +typedef struct ei_send_msg_s ei_send_msg_t; + +struct ei_received_msg_s { + ei_x_buff buf; + erlang_msg msg; +}; +typedef struct ei_received_msg_s ei_received_msg_t; + + +typedef struct ei_event_stream_s ei_event_stream_t; +typedef struct ei_node_s ei_node_t; + +struct ei_event_binding_s { + char id[SWITCH_UUID_FORMATTED_LENGTH + 1]; + switch_event_node_t *node; + switch_event_types_t type; + const char *subclass_name; + ei_event_stream_t* stream; + kazoo_event_ptr event; + + struct ei_event_binding_s *next; +}; +typedef struct ei_event_binding_s ei_event_binding_t; + +struct ei_event_stream_s { + switch_memory_pool_t *pool; + ei_event_binding_t *bindings; + switch_queue_t *queue; + switch_socket_t *acceptor; + switch_pollset_t *pollset; + switch_pollfd_t *pollfd; + switch_socket_t *socket; + switch_mutex_t *socket_mutex; + switch_bool_t connected; + char remote_ip[48]; + uint16_t remote_port; + char local_ip[48]; + uint16_t local_port; + erlang_pid pid; + uint32_t flags; + ei_node_t *node; + short event_stream_framing; + struct ei_event_stream_s *next; +}; + +struct ei_node_s { + int nodefd; + switch_atomic_t pending_bgapi; + switch_atomic_t receive_handlers; + switch_memory_pool_t *pool; + ei_event_stream_t *event_streams; + switch_mutex_t *event_streams_mutex; + switch_queue_t *send_msgs; + switch_queue_t *received_msgs; + char *peer_nodename; + switch_time_t created_time; + switch_socket_t *socket; + char remote_ip[48]; + uint16_t remote_port; + char local_ip[48]; + uint16_t local_port; + uint32_t flags; + int legacy; + short event_stream_framing; + struct ei_node_s *next; +}; + + +struct xml_fetch_reply_s { + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + char *xml_str; + struct xml_fetch_reply_s *next; +}; +typedef struct xml_fetch_reply_s xml_fetch_reply_t; + +struct fetch_handler_s { + erlang_pid pid; + struct fetch_handler_s *next; +}; +typedef struct fetch_handler_s fetch_handler_t; + +struct ei_xml_client_s { + ei_node_t *ei_node; + fetch_handler_t *fetch_handlers; + struct ei_xml_client_s *next; +}; +typedef struct ei_xml_client_s ei_xml_client_t; + +struct ei_xml_agent_s { + switch_memory_pool_t *pool; + switch_xml_section_t section; + switch_thread_rwlock_t *lock; + ei_xml_client_t *clients; + switch_mutex_t *current_client_mutex; + ei_xml_client_t *current_client; + switch_mutex_t *replies_mutex; + switch_thread_cond_t *new_reply; + xml_fetch_reply_t *replies; + kazoo_fetch_profile_ptr profile; + +}; + +typedef enum { + KZ_TWEAK_INTERACTION_ID, + KZ_TWEAK_EXPORT_VARS, + KZ_TWEAK_SWITCH_URI, + KZ_TWEAK_REPLACES_CALL_ID, + KZ_TWEAK_LOOPBACK_VARS, + KZ_TWEAK_CALLER_ID, + KZ_TWEAK_TRANSFERS, + KZ_TWEAK_BRIDGE, + KZ_TWEAK_BRIDGE_REPLACES_ALEG, + KZ_TWEAK_BRIDGE_REPLACES_CALL_ID, + KZ_TWEAK_BRIDGE_VARIABLES, + KZ_TWEAK_RESTORE_CALLER_ID_ON_BLIND_XFER, + + /* No new flags below this line */ + KZ_TWEAK_MAX +} kz_tweak_t; + +struct globals_s { + switch_memory_pool_t *pool; + switch_atomic_t threads; + switch_socket_t *acceptor; + struct ei_cnode_s ei_cnode; + switch_thread_rwlock_t *ei_nodes_lock; + ei_node_t *ei_nodes; + + switch_xml_binding_t *config_fetch_binding; + switch_xml_binding_t *directory_fetch_binding; + switch_xml_binding_t *dialplan_fetch_binding; + switch_xml_binding_t *channels_fetch_binding; + switch_xml_binding_t *languages_fetch_binding; + switch_xml_binding_t *chatplan_fetch_binding; + + switch_hash_t *event_filter; + int epmdfd; + int num_worker_threads; + switch_bool_t nat_map; + switch_bool_t ei_shortname; + int ei_compat_rel; + char *ip; + char *hostname; + char *ei_cookie; + char *ei_nodename; + uint32_t flags; + int send_all_headers; + int send_all_private_headers; + int connection_timeout; + int receive_timeout; + int receive_msg_preallocate; + int event_stream_preallocate; + int send_msg_batch; + short event_stream_framing; + switch_port_t port; + int config_fetched; + int io_fault_tolerance; + kazoo_event_profile_ptr events; + kazoo_config_ptr definitions; + kazoo_config_ptr event_handlers; + kazoo_config_ptr fetch_handlers; + kazoo_json_term json_encoding; + + char **profile_vars_prefixes; + char **kazoo_var_prefixes; + + int legacy_events; + uint8_t tweaks[KZ_TWEAK_MAX]; + + +}; +typedef struct globals_s globals_t; +extern globals_t kazoo_globals; + +/* kazoo_event_stream.c */ +ei_event_stream_t *find_event_stream(ei_event_stream_t *event_streams, const erlang_pid *from); + +//ei_event_stream_t *new_event_stream(ei_event_stream_t **event_streams, const erlang_pid *from); +ei_event_stream_t *new_event_stream(ei_node_t *ei_node, const erlang_pid *from); + + +switch_status_t remove_event_stream(ei_event_stream_t **event_streams, const erlang_pid *from); +switch_status_t remove_event_streams(ei_event_stream_t **event_streams); +unsigned long get_stream_port(const ei_event_stream_t *event_stream); +switch_status_t add_event_binding(ei_event_stream_t *event_stream, const char *event_name); +//switch_status_t add_event_binding(ei_event_stream_t *event_stream, const switch_event_types_t event_type, const char *subclass_name); +switch_status_t remove_event_binding(ei_event_stream_t *event_stream, const switch_event_types_t event_type, const char *subclass_name); +switch_status_t remove_event_bindings(ei_event_stream_t *event_stream); + +/* kazoo_node.c */ +switch_status_t new_kazoo_node(int nodefd, ErlConnect *conn); + +/* kazoo_ei_utils.c */ +void close_socket(switch_socket_t **sock); +void close_socketfd(int *sockfd); +switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port); +switch_socket_t *create_socket(switch_memory_pool_t *pool); +switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode); +switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2); +void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event); +void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int decode); +void ei_encode_json(ei_x_buff *ebuf, cJSON *JObj); +void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to); +void ei_encode_switch_event(ei_x_buff * ebuf, switch_event_t *event); +int ei_helper_send(ei_node_t *ei_node, erlang_pid* to, ei_x_buff *buf); +int ei_decode_atom_safe(char *buf, int *index, char *dst); +int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst); +int ei_decode_string_or_binary(char *buf, int *index, char **dst); +switch_status_t create_acceptor(); +switch_hash_t *create_default_filter(); + +void fetch_config(); + +switch_status_t kazoo_load_config(); +void kazoo_destroy_config(); + + +#define _ei_x_encode_string(buf, string) { ei_x_encode_binary(buf, string, strlen(string)); } + +/* kazoo_fetch_agent.c */ +switch_status_t bind_fetch_agents(); +switch_status_t unbind_fetch_agents(); +switch_status_t remove_xml_clients(ei_node_t *ei_node); +switch_status_t add_fetch_handler(ei_node_t *ei_node, erlang_pid *from, switch_xml_binding_t *binding); +switch_status_t remove_fetch_handlers(ei_node_t *ei_node, erlang_pid *from); +switch_status_t fetch_reply(char *uuid_str, char *xml_str, switch_xml_binding_t *binding); +switch_status_t handle_api_command_streams(ei_node_t *ei_node, switch_stream_handle_t *stream); + +void bind_event_profiles(kazoo_event_ptr event); +void rebind_fetch_profiles(kazoo_config_ptr fetch_handlers); +switch_status_t kazoo_config_handlers(switch_xml_t cfg); + +/* runtime */ +SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime); + + + +#define kz_test_tweak(flag) (kazoo_globals.tweaks[flag] ? 1 : 0) +#define kz_set_tweak(flag) kazoo_globals.tweaks[flag] = 1 +#define kz_clear_tweak(flag) kazoo_globals.tweaks[flag] = 0 + +#endif /* KAZOO_EI_H */ + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_ei_config.c b/src/mod/event_handlers/mod_kazoo/kazoo_ei_config.c new file mode 100644 index 0000000000..9357211afb --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_ei_config.c @@ -0,0 +1,635 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#include "mod_kazoo.h" + +#define KZ_DEFAULT_STREAM_PRE_ALLOCATE 8192 + +#define KAZOO_DECLARE_GLOBAL_STRING_FUNC(fname, vname) static void __attribute__((__unused__)) fname(const char *string) { if (!string) return;\ + if (vname) {free(vname); vname = NULL;}vname = strdup(string);} static void fname(const char *string) + +KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, kazoo_globals.ip); +KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_cookie, kazoo_globals.ei_cookie); +KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_nodename, kazoo_globals.ei_nodename); +//KAZOO_DECLARE_GLOBAL_STRING_FUNC(set_pref_kazoo_var_prefix, kazoo_globals.kazoo_var_prefix); + +static int read_cookie_from_file(char *filename) { + int fd; + char cookie[MAXATOMLEN + 1]; + char *end; + struct stat buf; + ssize_t res; + + if (!stat(filename, &buf)) { + if ((buf.st_mode & S_IRWXG) || (buf.st_mode & S_IRWXO)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s must only be accessible by owner only.\n", filename); + return 2; + } + if (buf.st_size > MAXATOMLEN) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s contains a cookie larger than the maximum atom size of %d.\n", filename, MAXATOMLEN); + return 2; + } + fd = open(filename, O_RDONLY); + if (fd < 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open cookie file %s : %d.\n", filename, errno); + return 2; + } + + if ((res = read(fd, cookie, MAXATOMLEN)) < 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie file %s : %d.\n", filename, errno); + } + + cookie[MAXATOMLEN] = '\0'; + + /* replace any end of line characters with a null */ + if ((end = strchr(cookie, '\n'))) { + *end = '\0'; + } + + if ((end = strchr(cookie, '\r'))) { + *end = '\0'; + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie from file %s: %s\n", filename, cookie); + + set_pref_ei_cookie(cookie); + return 0; + } else { + /* don't error here, because we might be blindly trying to read $HOME/.erlang.cookie, and that can fail silently */ + return 1; + } +} + + +switch_status_t kazoo_ei_config(switch_xml_t cfg) { + switch_xml_t child, param; + char* kazoo_var_prefix = NULL; + char* profile_vars_prefix = NULL; + char* sep_array[KZ_MAX_SEPARATE_STRINGS]; + int array_len, i; + kazoo_globals.send_all_headers = 0; + kazoo_globals.send_all_private_headers = 1; + kazoo_globals.connection_timeout = 500; + kazoo_globals.receive_timeout = 200; + kazoo_globals.receive_msg_preallocate = 2000; + kazoo_globals.event_stream_preallocate = KZ_DEFAULT_STREAM_PRE_ALLOCATE; + kazoo_globals.send_msg_batch = 10; + kazoo_globals.event_stream_framing = 2; + kazoo_globals.port = 0; + kazoo_globals.io_fault_tolerance = 10; + kazoo_globals.json_encoding = ERLANG_TUPLE; + + kazoo_globals.legacy_events = SWITCH_FALSE; + + kz_set_tweak(KZ_TWEAK_INTERACTION_ID); + kz_set_tweak(KZ_TWEAK_EXPORT_VARS); + kz_set_tweak(KZ_TWEAK_SWITCH_URI); + kz_set_tweak(KZ_TWEAK_REPLACES_CALL_ID); + kz_set_tweak(KZ_TWEAK_LOOPBACK_VARS); + kz_set_tweak(KZ_TWEAK_CALLER_ID); + kz_set_tweak(KZ_TWEAK_TRANSFERS); + kz_set_tweak(KZ_TWEAK_BRIDGE); + kz_set_tweak(KZ_TWEAK_BRIDGE_REPLACES_ALEG); + kz_set_tweak(KZ_TWEAK_BRIDGE_REPLACES_CALL_ID); + kz_set_tweak(KZ_TWEAK_BRIDGE_VARIABLES); + kz_set_tweak(KZ_TWEAK_RESTORE_CALLER_ID_ON_BLIND_XFER); + + + + if ((child = switch_xml_child(cfg, "settings"))) { + for (param = switch_xml_child(child, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!strcmp(var, "listen-ip")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind ip address: %s\n", val); + set_pref_ip(val); + } else if (!strcmp(var, "listen-port")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind port: %s\n", val); + kazoo_globals.port = atoi(val); + } else if (!strcmp(var, "cookie")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie: %s\n", val); + set_pref_ei_cookie(val); + } else if (!strcmp(var, "cookie-file")) { + if (read_cookie_from_file(val) == 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie from %s\n", val); + } + } else if (!strcmp(var, "nodename")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set node name: %s\n", val); + set_pref_ei_nodename(val); + } else if (!strcmp(var, "shortname")) { + kazoo_globals.ei_shortname = switch_true(val); + } else if (!strcmp(var, "kazoo-var-prefix")) { + kazoo_var_prefix = switch_core_strdup(kazoo_globals.pool, val); + } else if (!strcmp(var, "set-profile-vars-prefix")) { + profile_vars_prefix = switch_core_strdup(kazoo_globals.pool, val); + } else if (!strcmp(var, "compat-rel")) { + if (atoi(val) >= 7) + kazoo_globals.ei_compat_rel = atoi(val); + else + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid compatibility release '%s' specified\n", val); + } else if (!strcmp(var, "nat-map")) { + kazoo_globals.nat_map = switch_true(val); + } else if (!strcmp(var, "send-all-headers")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-headers: %s\n", val); + kazoo_globals.send_all_headers = switch_true(val); + } else if (!strcmp(var, "send-all-private-headers")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-private-headers: %s\n", val); + kazoo_globals.send_all_private_headers = switch_true(val); + } else if (!strcmp(var, "connection-timeout")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set connection-timeout: %s\n", val); + kazoo_globals.connection_timeout = atoi(val); + } else if (!strcmp(var, "receive-timeout")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-timeout: %s\n", val); + kazoo_globals.receive_timeout = atoi(val); + } else if (!strcmp(var, "receive-msg-preallocate")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-msg-preallocate: %s\n", val); + kazoo_globals.receive_msg_preallocate = atoi(val); + } else if (!strcmp(var, "event-stream-preallocate")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-preallocate: %s\n", val); + kazoo_globals.event_stream_preallocate = atoi(val); + } else if (!strcmp(var, "send-msg-batch-size")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-msg-batch-size: %s\n", val); + kazoo_globals.send_msg_batch = atoi(val); + } else if (!strcmp(var, "event-stream-framing")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-framing: %s\n", val); + kazoo_globals.event_stream_framing = atoi(val); + } else if (!strcmp(var, "io-fault-tolerance")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set io-fault-tolerance: %s\n", val); + kazoo_globals.io_fault_tolerance = atoi(val); + } else if (!strcmp(var, "num-worker-threads")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set num-worker-threads: %s\n", val); + kazoo_globals.num_worker_threads = atoi(val); + } else if (!strcmp(var, "json-term-encoding")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set json-term-encoding: %s\n", val); + if(!strcmp(val, "map")) { + kazoo_globals.json_encoding = ERLANG_MAP; + } + } else if (!strcmp(var, "legacy-events")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set legacy-events: %s\n", val); + kazoo_globals.legacy_events = switch_true(val); + } + } + } + + if ((child = switch_xml_child(cfg, "tweaks"))) { + for (param = switch_xml_child(child, "tweak"); param; param = param->next) { + kz_tweak_t tweak = KZ_TWEAK_MAX; + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if(var && val && kz_name_tweak(var, &tweak) == SWITCH_STATUS_SUCCESS) { + if(switch_true(val)) { + kz_set_tweak(tweak); + } else { + kz_clear_tweak(tweak); + } + } + } + } + + if ((child = switch_xml_child(cfg, "variables"))) { + for (param = switch_xml_child(child, "variable"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if(var && val) { + switch_core_set_variable(var, val); + } + } + } + + if ((child = switch_xml_child(cfg, "event-filter"))) { + switch_hash_t *filter; + + switch_core_hash_init(&filter); + for (param = switch_xml_child(child, "header"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + switch_core_hash_insert(filter, var, "1"); + } + kazoo_globals.event_filter = filter; + } + + if (kazoo_globals.receive_msg_preallocate < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid receive message preallocate value, disabled\n"); + kazoo_globals.receive_msg_preallocate = 0; + } + + if (kazoo_globals.event_stream_preallocate < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream preallocate value, disabled\n"); + kazoo_globals.event_stream_preallocate = 0; + } + + if (kazoo_globals.send_msg_batch < 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid send message batch size, reverting to default\n"); + kazoo_globals.send_msg_batch = 10; + } + + if (kazoo_globals.io_fault_tolerance < 1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid I/O fault tolerance, reverting to default\n"); + kazoo_globals.io_fault_tolerance = 10; + } + + if (!kazoo_globals.event_filter) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Event filter not found in configuration, using default\n"); + kazoo_globals.event_filter = create_default_filter(); + } + + if (kazoo_globals.event_stream_framing < 1 || kazoo_globals.event_stream_framing > 4) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream framing value, using default\n"); + kazoo_globals.event_stream_framing = 2; + } + + if (zstr(kazoo_var_prefix)) { + kazoo_var_prefix = switch_core_strdup(kazoo_globals.pool, "ecallmgr_;cav_"); + } + + if (zstr(profile_vars_prefix)) { + profile_vars_prefix = switch_core_strdup(kazoo_globals.pool, "effective_;origination_"); + } + + kazoo_globals.kazoo_var_prefixes = switch_core_alloc(kazoo_globals.pool, sizeof(char*) * KZ_MAX_SEPARATE_STRINGS); + array_len = switch_separate_string(kazoo_var_prefix, ';', sep_array, KZ_MAX_SEPARATE_STRINGS - 1); + for(i=0; i < array_len; i++) { + char var[100]; + sprintf(var, "variable_%s", sep_array[i]); + kazoo_globals.kazoo_var_prefixes[i] = switch_core_strdup(kazoo_globals.pool, var); + } + + kazoo_globals.profile_vars_prefixes = switch_core_alloc(kazoo_globals.pool, sizeof(char*) * KZ_MAX_SEPARATE_STRINGS); + array_len = switch_separate_string(profile_vars_prefix, ';', sep_array, KZ_MAX_SEPARATE_STRINGS - 1); + for(i=0; i < array_len; i++) { + kazoo_globals.profile_vars_prefixes[i] = switch_core_strdup(kazoo_globals.pool, sep_array[i]); + } + + if (!kazoo_globals.num_worker_threads) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Number of worker threads not found in configuration, using default\n"); + kazoo_globals.num_worker_threads = 10; + } + + if (zstr(kazoo_globals.ip)) { + set_pref_ip("0.0.0.0"); + } + + if (zstr(kazoo_globals.ei_cookie)) { + int res; + char *home_dir = getenv("HOME"); + char path_buf[1024]; + + if (!zstr(home_dir)) { + /* $HOME/.erlang.cookie */ + switch_snprintf(path_buf, sizeof (path_buf), "%s%s%s", home_dir, SWITCH_PATH_SEPARATOR, ".erlang.cookie"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for cookie at path: %s\n", path_buf); + + res = read_cookie_from_file(path_buf); + if (res) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No cookie or valid cookie file specified, using default cookie\n"); + set_pref_ei_cookie("ClueCon"); + } + } + } + + if (!kazoo_globals.ei_nodename) { + set_pref_ei_nodename("freeswitch"); + } + + if (!kazoo_globals.nat_map) { + kazoo_globals.nat_map = 0; + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t kazoo_config_handlers(switch_xml_t cfg) +{ + switch_xml_t def = NULL; + switch_xml_t child, param; + char* xml = NULL; + kazoo_config_ptr definitions = NULL, fetch_handlers = NULL, event_handlers = NULL; + kazoo_event_profile_ptr events = NULL; + + xml = strndup(kz_default_config, kz_default_config_size); + def = switch_xml_parse_str_dup(xml); + + kz_xml_process(def); + kz_xml_process(cfg); + + if ((child = switch_xml_child(cfg, "variables"))) { + for (param = switch_xml_child(child, "variable"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if(var && val) { + switch_core_set_variable(var, val); + } + } + } else if ((child = switch_xml_child(def, "variables"))) { + for (param = switch_xml_child(child, "variable"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + if(var && val) { + switch_core_set_variable(var, val); + } + } + } + + definitions = kazoo_config_definitions(cfg); + if(definitions == NULL) { + if(kazoo_globals.definitions == NULL) { + definitions = kazoo_config_definitions(def); + } else { + definitions = kazoo_globals.definitions; + } + } + + fetch_handlers = kazoo_config_fetch_handlers(definitions, cfg); + if(fetch_handlers == NULL) { + if(kazoo_globals.fetch_handlers == NULL) { + fetch_handlers = kazoo_config_fetch_handlers(definitions, def); + } else { + fetch_handlers = kazoo_globals.fetch_handlers; + } + } + + event_handlers = kazoo_config_event_handlers(definitions, cfg); + if(event_handlers == NULL) { + if(kazoo_globals.event_handlers == NULL) { + event_handlers = kazoo_config_event_handlers(definitions, def); + } else { + event_handlers = kazoo_globals.event_handlers; + } + } + + if(event_handlers != NULL) { + events = (kazoo_event_profile_ptr) switch_core_hash_find(event_handlers->hash, "default"); + } + + if(events == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to get default handler for events\n"); + if(kazoo_globals.event_handlers != event_handlers) destroy_config(&event_handlers); + if(kazoo_globals.fetch_handlers != fetch_handlers) destroy_config(&fetch_handlers); + if(kazoo_globals.definitions != definitions) destroy_config(&definitions); + switch_xml_free(def); + switch_safe_free(xml); + return SWITCH_STATUS_GENERR; + } + + if(kazoo_globals.events != events) { + bind_event_profiles(events->events); + kazoo_globals.events = events; + } + + if(kazoo_globals.event_handlers != event_handlers) { + kazoo_config_ptr tmp = kazoo_globals.event_handlers; + kazoo_globals.event_handlers = event_handlers; + destroy_config(&tmp); + } + + if(kazoo_globals.fetch_handlers != fetch_handlers) { + kazoo_config_ptr tmp = kazoo_globals.fetch_handlers; + kazoo_globals.fetch_handlers = fetch_handlers; + rebind_fetch_profiles(fetch_handlers); + destroy_config(&tmp); + } + + if(kazoo_globals.definitions != definitions) { + kazoo_config_ptr tmp = kazoo_globals.definitions; + kazoo_globals.definitions = definitions; + destroy_config(&tmp); + } + + + switch_xml_free(def); + switch_safe_free(xml); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t kazoo_load_config() +{ + char *cf = "kazoo.conf"; + switch_xml_t cfg, xml; + if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf); + return SWITCH_STATUS_FALSE; + } else { + kazoo_ei_config(cfg); + kazoo_config_handlers(cfg); + switch_xml_free(xml); + } + + return SWITCH_STATUS_SUCCESS; +} + +void kazoo_destroy_config() +{ + destroy_config(&kazoo_globals.event_handlers); + destroy_config(&kazoo_globals.fetch_handlers); + destroy_config(&kazoo_globals.definitions); +} + +switch_status_t kazoo_config_events(kazoo_config_ptr definitions, switch_memory_pool_t *pool, switch_xml_t cfg, kazoo_event_profile_ptr profile) +{ + switch_xml_t events, event; + kazoo_event_ptr prv = NULL, cur = NULL; + + + if ((events = switch_xml_child(cfg, "events")) != NULL) { + for (event = switch_xml_child(events, "event"); event; event = event->next) { + const char *var = switch_xml_attr(event, "name"); + cur = (kazoo_event_ptr) switch_core_alloc(pool, sizeof(kazoo_event_t)); + memset(cur, 0, sizeof(kazoo_event_t)); + if(prv == NULL) { + profile->events = prv = cur; + } else { + prv->next = cur; + prv = cur; + } + cur->profile = profile; + cur->name = switch_core_strdup(pool, var); + kazoo_config_filters(pool, event, &cur->filter); + kazoo_config_fields(definitions, pool, event, &cur->fields); + + } + + } + + return SWITCH_STATUS_SUCCESS; + +} + + +switch_status_t kazoo_config_fetch_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_fetch_profile_ptr *ptr) +{ + kazoo_fetch_profile_ptr profile = NULL; + switch_xml_t params, param; + switch_xml_section_t fetch_section; + int fetch_timeout = 2000000; + switch_memory_pool_t *pool = NULL; + + char *name = (char *) switch_xml_attr_soft(cfg, "name"); + if (zstr(name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing name in profile\n"); + return SWITCH_STATUS_GENERR; + } + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocation pool for new profile : %s\n", name); + return SWITCH_STATUS_GENERR; + } + + profile = switch_core_alloc(pool, sizeof(kazoo_fetch_profile_t)); + profile->pool = pool; + profile->root = root; + profile->name = switch_core_strdup(profile->pool, name); + + fetch_section = switch_xml_parse_section_string(name); + + if ((params = switch_xml_child(cfg, "params")) != NULL) { + for (param = switch_xml_child(params, "param"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + char *val = (char *) switch_xml_attr_soft(param, "value"); + + if (!var) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile[%s] param missing 'name' attribute\n", name); + continue; + } + + if (!val) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Profile[%s] param[%s] missing 'value' attribute\n", name, var); + continue; + } + + if (!strncmp(var, "fetch-timeout", 13)) { + fetch_timeout = atoi(val); + } else if (!strncmp(var, "fetch-section", 13)) { + fetch_section = switch_xml_parse_section_string(val); + } + } + } + + if (fetch_section == SWITCH_XML_SECTION_RESULT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Fetch Profile[%s] invalid fetch-section: %s\n", name, switch_xml_toxml(cfg, SWITCH_FALSE)); + goto err; + } + + + profile->fetch_timeout = fetch_timeout; + profile->section = fetch_section; + kazoo_config_fields(definitions, pool, cfg, &profile->fields); + kazoo_config_loglevels(pool, cfg, &profile->logging); + + if(root) { + if ( switch_core_hash_insert(root->hash, name, (void *) profile) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "failed to insert new fetch profile [%s] into kazoo profile hash\n", name); + goto err; + } + } + + if(ptr) + *ptr = profile; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "fetch handler profile %s successfully configured\n", name); + return SWITCH_STATUS_SUCCESS; + + err: + /* Cleanup */ + if(pool) { + switch_core_destroy_memory_pool(&pool); + } + return SWITCH_STATUS_GENERR; + +} + +switch_status_t kazoo_config_event_handler(kazoo_config_ptr definitions, kazoo_config_ptr root, switch_xml_t cfg, kazoo_event_profile_ptr *ptr) +{ + kazoo_event_profile_ptr profile = NULL; + switch_memory_pool_t *pool = NULL; + + char *name = (char *) switch_xml_attr_soft(cfg, "name"); + if (zstr(name)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "missing name in profile\n"); + return SWITCH_STATUS_GENERR; + } + + if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocation pool for new profile : %s\n", name); + return SWITCH_STATUS_GENERR; + } + + profile = switch_core_alloc(pool, sizeof(kazoo_event_profile_t)); + profile->pool = pool; + profile->root = root; + profile->name = switch_core_strdup(profile->pool, name); + + kazoo_config_filters(pool, cfg, &profile->filter); + kazoo_config_fields(definitions, pool, cfg, &profile->fields); + kazoo_config_events(definitions, pool, cfg, profile); + kazoo_config_loglevels(pool, cfg, &profile->logging); + + if(root) { + if ( switch_core_hash_insert(root->hash, name, (void *) profile) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to insert new profile [%s] into kazoo profile hash\n", name); + goto err; + } + } + + if(ptr) + *ptr = profile; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "event handler profile %s successfully configured\n", name); + return SWITCH_STATUS_SUCCESS; + + err: + /* Cleanup */ + if(pool) { + switch_core_destroy_memory_pool(&pool); + } + return SWITCH_STATUS_GENERR; + +} + + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_ei_utils.c b/src/mod/event_handlers/mod_kazoo/kazoo_ei_utils.c new file mode 100644 index 0000000000..7a2e62c925 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_ei_utils.c @@ -0,0 +1,1001 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Anthony Minessale II + * Andrew Thompson + * Rob Charlton + * Karl Anderson + * + * Original from mod_erlang_event. + * ei_helpers.c -- helper functions for ei + * + */ +#include "mod_kazoo.h" + +/* Stolen from code added to ei in R12B-5. + * Since not everyone has this version yet; + * provide our own version. + * */ + +#define put8(s,n) do { \ + (s)[0] = (char)((n) & 0xff); \ + (s) += 1; \ + } while (0) + +#define put32be(s,n) do { \ + (s)[0] = ((n) >> 24) & 0xff; \ + (s)[1] = ((n) >> 16) & 0xff; \ + (s)[2] = ((n) >> 8) & 0xff; \ + (s)[3] = (n) & 0xff; \ + (s) += 4; \ + } while (0) + +#ifdef EI_DEBUG +static void ei_x_print_reg_msg(ei_x_buff *buf, char *dest, int send) { + char *mbuf = NULL; + int i = 1; + + ei_s_print_term(&mbuf, buf->buff, &i); + + if (send) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoded term %s to '%s'\n", mbuf, dest); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Decoded term %s for '%s'\n", mbuf, dest); + } + + free(mbuf); +} + +static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) { + char *pbuf = NULL; + int i = 0; + ei_x_buff pidbuf; + + ei_x_new(&pidbuf); + ei_x_encode_pid(&pidbuf, pid); + + ei_s_print_term(&pbuf, pidbuf.buff, &i); + + ei_x_print_reg_msg(buf, pbuf, send); + free(pbuf); +} +#endif + +void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event) { + ei_encode_switch_event_headers_2(ebuf, event, 1); +} + +void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode) { + switch_event_header_t *hp; + char *uuid = switch_event_get_header(event, "unique-id"); + int i; + + for (i = 0, hp = event->headers; hp; hp = hp->next, i++); + + if (event->body) + i++; + + ei_x_encode_list_header(ebuf, i + 1); + + if (uuid) { + char *unique_id = switch_event_get_header(event, "unique-id"); + ei_x_encode_binary(ebuf, unique_id, strlen(unique_id)); + } else { + ei_x_encode_atom(ebuf, "undefined"); + } + + for (hp = event->headers; hp; hp = hp->next) { + ei_x_encode_tuple_header(ebuf, 2); + ei_x_encode_binary(ebuf, hp->name, strlen(hp->name)); + if(encode) { + switch_url_decode(hp->value); + } + ei_x_encode_binary(ebuf, hp->value, strlen(hp->value)); + } + + if (event->body) { + ei_x_encode_tuple_header(ebuf, 2); + ei_x_encode_binary(ebuf, "body", strlen("body")); + ei_x_encode_binary(ebuf, event->body, strlen(event->body)); + } + + ei_x_encode_empty_list(ebuf); +} + +int ei_json_child_count(cJSON *JObj) +{ + int mask = cJSON_False + | cJSON_True + | cJSON_NULL + | cJSON_Number + | cJSON_String + | cJSON_Array + | cJSON_Object + | cJSON_Raw; + + cJSON *item = JObj->child; + int i = 0; + while(item) { + if(item->type & mask) + i++; + item = item->next; + } + return i; + +} + +void ei_encode_json_array(ei_x_buff *ebuf, cJSON *JObj) { + cJSON *item; + int count = ei_json_child_count(JObj); + + ei_x_encode_list_header(ebuf, count); + if(count == 0) + return; + + item = JObj->child; + while(item) { + switch(item->type) { + case cJSON_String: + ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring)); + break; + + case cJSON_Number: + ei_x_encode_double(ebuf, item->valuedouble); + break; + + case cJSON_True: + ei_x_encode_boolean(ebuf, 1); + break; + + case cJSON_False: + ei_x_encode_boolean(ebuf, 0); + break; + + case cJSON_Object: + ei_encode_json(ebuf, item); + break; + + case cJSON_Array: + ei_encode_json_array(ebuf, item); + break; + + case cJSON_Raw: + { + cJSON *Decoded = cJSON_Parse(item->valuestring); + if(!Decoded) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring); + ei_x_encode_tuple_header(ebuf, 0); + } else { + ei_encode_json(ebuf, Decoded); + cJSON_Delete(Decoded); + } + break; + } + + case cJSON_NULL: + ei_x_encode_atom(ebuf, "null"); + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type); + break; + + } + item = item->next; + } + + ei_x_encode_empty_list(ebuf); + +} + +void ei_encode_json(ei_x_buff *ebuf, cJSON *JObj) { + cJSON *item; + int count = ei_json_child_count(JObj); + + if(kazoo_globals.json_encoding == ERLANG_TUPLE) { + ei_x_encode_tuple_header(ebuf, 1); + ei_x_encode_list_header(ebuf, count); + } else { + ei_x_encode_map_header(ebuf, count); + } + + if(count == 0) + return; + + item = JObj->child; + while(item) { + if(kazoo_globals.json_encoding == ERLANG_TUPLE) { + ei_x_encode_tuple_header(ebuf, 2); + } + ei_x_encode_binary(ebuf, item->string, strlen(item->string)); + + switch(item->type) { + case cJSON_String: + ei_x_encode_binary(ebuf, item->valuestring, strlen(item->valuestring)); + break; + + case cJSON_Number: + if ((fabs(((double)item->valueint) - item->valuedouble) <= DBL_EPSILON) + && (item->valuedouble <= INT_MAX) + && (item->valuedouble >= INT_MIN)) { + ei_x_encode_longlong(ebuf, item->valueint); + } else { + ei_x_encode_double(ebuf, item->valuedouble); + } + break; + + case cJSON_True: + ei_x_encode_boolean(ebuf, 1); + break; + + case cJSON_False: + ei_x_encode_boolean(ebuf, 0); + break; + + case cJSON_Object: + ei_encode_json(ebuf, item); + break; + + case cJSON_Array: + ei_encode_json_array(ebuf, item); + break; + + case cJSON_Raw: + { + cJSON *Decoded = cJSON_Parse(item->valuestring); + if(!Decoded) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "ERROR DECODING RAW JSON %s\n", item->valuestring); + ei_x_encode_tuple_header(ebuf, 0); + } else { + ei_encode_json(ebuf, Decoded); + cJSON_Delete(Decoded); + } + break; + } + + case cJSON_NULL: + ei_x_encode_atom(ebuf, "null"); + break; + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "NOT ENCODED %i\n", item->type); + break; + + } + item = item->next; + } + + if(kazoo_globals.json_encoding == ERLANG_TUPLE) { + ei_x_encode_empty_list(ebuf); + } + +} + +void close_socket(switch_socket_t ** sock) { + if (*sock) { + switch_socket_shutdown(*sock, SWITCH_SHUTDOWN_READWRITE); + switch_socket_close(*sock); + *sock = NULL; + } +} + +void close_socketfd(int *sockfd) { + if (*sockfd) { + shutdown(*sockfd, SHUT_RDWR); + close(*sockfd); + } +} + +switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port) { + switch_sockaddr_t *sa; + switch_socket_t *socket; + + if(switch_sockaddr_info_get(&sa, kazoo_globals.ip, SWITCH_UNSPEC, port, 0, pool)) { + return NULL; + } + + if (switch_socket_create(&socket, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, pool)) { + return NULL; + } + + if (switch_socket_opt_set(socket, SWITCH_SO_REUSEADDR, 1)) { + return NULL; + } + + if (switch_socket_bind(socket, sa)) { + return NULL; + } + + if (switch_socket_listen(socket, 5)){ + return NULL; + } + + switch_getnameinfo(&kazoo_globals.hostname, sa, 0); + + if (kazoo_globals.nat_map && switch_nat_get_type()) { + switch_nat_add_mapping(port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE); + } + + return socket; +} + +switch_socket_t *create_socket(switch_memory_pool_t *pool) { + return create_socket_with_port(pool, 0); + +} + +switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode) { + char hostname[EI_MAXHOSTNAMELEN + 1] = ""; + char nodename[MAXNODELEN + 1]; + char cnodename[EI_MAXALIVELEN + 1]; + //EI_MAX_COOKIE_SIZE+1 + char *atsign; + + /* copy the erlang interface nodename into something we can modify */ + strncpy(cnodename, name, EI_MAXALIVELEN); + + if ((atsign = strchr(cnodename, '@'))) { + /* we got a qualified node name, don't guess the host/domain */ + snprintf(nodename, MAXNODELEN + 1, "%s", kazoo_globals.ei_nodename); + /* truncate the alivename at the @ */ + *atsign = '\0'; + } else { + if (zstr(kazoo_globals.hostname) || !strncasecmp(kazoo_globals.ip, "0.0.0.0", 7) || !strncasecmp(kazoo_globals.ip, "::", 2)) { + memcpy(hostname, switch_core_get_hostname(), EI_MAXHOSTNAMELEN); + } else { + memcpy(hostname, kazoo_globals.hostname, EI_MAXHOSTNAMELEN); + } + + snprintf(nodename, MAXNODELEN + 1, "%s@%s", kazoo_globals.ei_nodename, hostname); + } + + if (kazoo_globals.ei_shortname) { + char *off; + if ((off = strchr(nodename, '.'))) { + *off = '\0'; + } + } + + /* init the ec stuff */ + if (ei_connect_xinit(ei_cnode, hostname, cnodename, nodename, (Erl_IpAddr) ip_addr, kazoo_globals.ei_cookie, 0) < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the erlang interface connection structure\n"); + return SWITCH_STATUS_FALSE; + } + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2) { + if ((!strcmp(pid1->node, pid2->node)) + && pid1->creation == pid2->creation + && pid1->num == pid2->num + && pid1->serial == pid2->serial) { + return SWITCH_STATUS_SUCCESS; + } else { + return SWITCH_STATUS_FALSE; + } +} + +void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to) { + char msgbuf[2048]; + char *s; + int index = 0; + + index = 5; /* max sizes: */ + ei_encode_version(msgbuf, &index); /* 1 */ + ei_encode_tuple_header(msgbuf, &index, 3); + ei_encode_long(msgbuf, &index, ERL_LINK); + ei_encode_pid(msgbuf, &index, from); /* 268 */ + ei_encode_pid(msgbuf, &index, to); /* 268 */ + + /* 5 byte header missing */ + s = msgbuf; + put32be(s, index - 4); /* 4 */ + put8(s, ERL_PASS_THROUGH); /* 1 */ + /* sum: 542 */ + + if (write(ei_node->nodefd, msgbuf, index) == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to link to process on %s\n", ei_node->peer_nodename); + } +} + +void ei_encode_switch_event(ei_x_buff *ebuf, switch_event_t *event) { + ei_x_encode_tuple_header(ebuf, 2); + ei_x_encode_atom(ebuf, "event"); + ei_encode_switch_event_headers(ebuf, event); +} + +int ei_helper_send(ei_node_t *ei_node, erlang_pid *to, ei_x_buff *buf) { + int ret = 0; + + if (ei_node->nodefd) { +#ifdef EI_DEBUG + ei_x_print_msg(buf, to, 1); +#endif + ret = ei_send(ei_node->nodefd, to, buf->buff, buf->index); + } + + return ret; +} + +int ei_decode_atom_safe(char *buf, int *index, char *dst) { + int type, size; + + ei_get_type(buf, index, &type, &size); + + if (type != ERL_ATOM_EXT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size); + return -1; + } else if (size > MAXATOMLEN) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN); + return -1; + } else { + return ei_decode_atom(buf, index, dst); + } +} + +int ei_decode_string_or_binary(char *buf, int *index, char **dst) { + int type, size, res; + long len; + + ei_get_type(buf, index, &type, &size); + + if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size); + return -1; + } + + *dst = malloc(size + 1); + + if (type == ERL_NIL_EXT) { + res = 0; + **dst = '\0'; + } else if (type == ERL_BINARY_EXT) { + res = ei_decode_binary(buf, index, *dst, &len); + (*dst)[len] = '\0'; + } else { + res = ei_decode_string(buf, index, *dst); + } + + return res; +} + +int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst) { + int type, size, res; + long len; + + ei_get_type(buf, index, &type, &size); + + if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_LIST_EXT && type != ERL_NIL_EXT) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size); + return -1; + } + + if (size > maxsize) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of %s with size %d into a buffer of size %d\n", + type == ERL_BINARY_EXT ? "binary" : "string", size, maxsize); + return -1; + } + + if (type == ERL_NIL_EXT) { + res = 0; + *dst = '\0'; + } else if (type == ERL_BINARY_EXT) { + res = ei_decode_binary(buf, index, dst, &len); + dst[len] = '\0'; /* binaries aren't null terminated */ + } else { + res = ei_decode_string(buf, index, dst); + } + + return res; +} + + +switch_status_t create_acceptor() { + switch_sockaddr_t *sa; + uint16_t port; + char ipbuf[48]; + const char *ip_addr; + +#if ERLANG_MAJOR >= 10 + ei_init(); +#endif + + /* if the config has specified an erlang release compatibility then pass that along to the erlang interface */ + if (kazoo_globals.ei_compat_rel) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Compatability with OTP R%d requested\n", kazoo_globals.ei_compat_rel); + ei_set_compat_rel(kazoo_globals.ei_compat_rel); + } + + if (!(kazoo_globals.acceptor = create_socket_with_port(kazoo_globals.pool, kazoo_globals.port))) { + return SWITCH_STATUS_SOCKERR; + } + + switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor); + + port = switch_sockaddr_get_port(sa); + ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor listening on %s:%u\n", ip_addr, port); + + /* try to initialize the erlang interface */ + if (create_ei_cnode(ip_addr, kazoo_globals.ei_nodename, &kazoo_globals.ei_cnode) != SWITCH_STATUS_SUCCESS) { + return SWITCH_STATUS_SOCKERR; + } + + /* tell the erlang port manager where we can be reached. this returns a file descriptor pointing to epmd or -1 */ + if ((kazoo_globals.epmdfd = ei_publish(&kazoo_globals.ei_cnode, port)) == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to publish port to epmd, trying to start epmd via system()\n"); + if (system("fs_epmd -daemon")) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, + "Failed to start epmd manually! Is epmd in $PATH? If not, start it yourself or run an erl shell with -sname or -name\n"); + return SWITCH_STATUS_SOCKERR; + } + switch_yield(100000); + if ((kazoo_globals.epmdfd = ei_publish(&kazoo_globals.ei_cnode, port)) == -1) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to publish port to epmd AGAIN\n"); + return SWITCH_STATUS_SOCKERR; + } + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to epmd and published erlang cnode name %s at port %d\n", kazoo_globals.ei_cnode.thisnodename, port); + + return SWITCH_STATUS_SUCCESS; +} + +switch_hash_t *create_default_filter() { + switch_hash_t *filter; + + switch_core_hash_init(&filter); + + switch_core_hash_insert(filter, "Acquired-UUID", "1"); + switch_core_hash_insert(filter, "action", "1"); + switch_core_hash_insert(filter, "Action", "1"); + switch_core_hash_insert(filter, "alt_event_type", "1"); + switch_core_hash_insert(filter, "Answer-State", "1"); + switch_core_hash_insert(filter, "Application", "1"); + switch_core_hash_insert(filter, "Application-Data", "1"); + switch_core_hash_insert(filter, "Application-Name", "1"); + switch_core_hash_insert(filter, "Application-Response", "1"); + switch_core_hash_insert(filter, "att_xfer_replaced_by", "1"); + switch_core_hash_insert(filter, "Auth-Method", "1"); + switch_core_hash_insert(filter, "Auth-Realm", "1"); + switch_core_hash_insert(filter, "Auth-User", "1"); + switch_core_hash_insert(filter, "Bridge-A-Unique-ID", "1"); + switch_core_hash_insert(filter, "Bridge-B-Unique-ID", "1"); + switch_core_hash_insert(filter, "Call-Direction", "1"); + switch_core_hash_insert(filter, "Caller-Callee-ID-Name", "1"); + switch_core_hash_insert(filter, "Caller-Callee-ID-Number", "1"); + switch_core_hash_insert(filter, "Caller-Caller-ID-Name", "1"); + switch_core_hash_insert(filter, "Caller-Caller-ID-Number", "1"); + switch_core_hash_insert(filter, "Caller-Screen-Bit", "1"); + switch_core_hash_insert(filter, "Caller-Privacy-Hide-Name", "1"); + switch_core_hash_insert(filter, "Caller-Privacy-Hide-Number", "1"); + switch_core_hash_insert(filter, "Caller-Context", "1"); + switch_core_hash_insert(filter, "Caller-Controls", "1"); + switch_core_hash_insert(filter, "Caller-Destination-Number", "1"); + switch_core_hash_insert(filter, "Caller-Dialplan", "1"); + switch_core_hash_insert(filter, "Caller-Network-Addr", "1"); + switch_core_hash_insert(filter, "Caller-Unique-ID", "1"); + switch_core_hash_insert(filter, "Call-ID", "1"); + switch_core_hash_insert(filter, "Channel-Call-State", "1"); + switch_core_hash_insert(filter, "Channel-Call-UUID", "1"); + switch_core_hash_insert(filter, "Channel-Presence-ID", "1"); + switch_core_hash_insert(filter, "Channel-State", "1"); + switch_core_hash_insert(filter, "Chat-Permissions", "1"); + switch_core_hash_insert(filter, "Conference-Name", "1"); + switch_core_hash_insert(filter, "Conference-Profile-Name", "1"); + switch_core_hash_insert(filter, "Conference-Unique-ID", "1"); + switch_core_hash_insert(filter, "contact", "1"); + switch_core_hash_insert(filter, "Detected-Tone", "1"); + switch_core_hash_insert(filter, "dialog_state", "1"); + switch_core_hash_insert(filter, "direction", "1"); + switch_core_hash_insert(filter, "Distributed-From", "1"); + switch_core_hash_insert(filter, "DTMF-Digit", "1"); + switch_core_hash_insert(filter, "DTMF-Duration", "1"); + switch_core_hash_insert(filter, "Event-Date-Timestamp", "1"); + switch_core_hash_insert(filter, "Event-Name", "1"); + switch_core_hash_insert(filter, "Event-Subclass", "1"); + switch_core_hash_insert(filter, "expires", "1"); + switch_core_hash_insert(filter, "Expires", "1"); + switch_core_hash_insert(filter, "Ext-SIP-IP", "1"); + switch_core_hash_insert(filter, "File", "1"); + switch_core_hash_insert(filter, "FreeSWITCH-Hostname", "1"); + switch_core_hash_insert(filter, "from", "1"); + switch_core_hash_insert(filter, "Hunt-Destination-Number", "1"); + switch_core_hash_insert(filter, "ip", "1"); + switch_core_hash_insert(filter, "Message-Account", "1"); + switch_core_hash_insert(filter, "metadata", "1"); + switch_core_hash_insert(filter, "old_node_channel_uuid", "1"); + switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Name", "1"); + switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Number", "1"); + switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Name", "1"); + switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Number", "1"); + switch_core_hash_insert(filter, "Other-Leg-Destination-Number", "1"); + switch_core_hash_insert(filter, "Other-Leg-Direction", "1"); + switch_core_hash_insert(filter, "Other-Leg-Unique-ID", "1"); + switch_core_hash_insert(filter, "Other-Leg-Channel-Name", "1"); + switch_core_hash_insert(filter, "Participant-Type", "1"); + switch_core_hash_insert(filter, "Path", "1"); + switch_core_hash_insert(filter, "profile_name", "1"); + switch_core_hash_insert(filter, "Profiles", "1"); + switch_core_hash_insert(filter, "proto-specific-event-name", "1"); + switch_core_hash_insert(filter, "Raw-Application-Data", "1"); + switch_core_hash_insert(filter, "realm", "1"); + switch_core_hash_insert(filter, "Resigning-UUID", "1"); + switch_core_hash_insert(filter, "set", "1"); + switch_core_hash_insert(filter, "sip_auto_answer", "1"); + switch_core_hash_insert(filter, "sip_auth_method", "1"); + switch_core_hash_insert(filter, "sip_from_host", "1"); + switch_core_hash_insert(filter, "sip_from_user", "1"); + switch_core_hash_insert(filter, "sip_to_host", "1"); + switch_core_hash_insert(filter, "sip_to_user", "1"); + switch_core_hash_insert(filter, "sub-call-id", "1"); + switch_core_hash_insert(filter, "technology", "1"); + switch_core_hash_insert(filter, "to", "1"); + switch_core_hash_insert(filter, "Unique-ID", "1"); + switch_core_hash_insert(filter, "URL", "1"); + switch_core_hash_insert(filter, "username", "1"); + switch_core_hash_insert(filter, "variable_channel_is_moving", "1"); + switch_core_hash_insert(filter, "variable_collected_digits", "1"); + switch_core_hash_insert(filter, "variable_current_application", "1"); + switch_core_hash_insert(filter, "variable_current_application_data", "1"); + switch_core_hash_insert(filter, "variable_domain_name", "1"); + switch_core_hash_insert(filter, "variable_effective_caller_id_name", "1"); + switch_core_hash_insert(filter, "variable_effective_caller_id_number", "1"); + switch_core_hash_insert(filter, "variable_holding_uuid", "1"); + switch_core_hash_insert(filter, "variable_hold_music", "1"); + switch_core_hash_insert(filter, "variable_media_group_id", "1"); + switch_core_hash_insert(filter, "variable_originate_disposition", "1"); + switch_core_hash_insert(filter, "variable_origination_uuid", "1"); + switch_core_hash_insert(filter, "variable_playback_terminator_used", "1"); + switch_core_hash_insert(filter, "variable_presence_id", "1"); + switch_core_hash_insert(filter, "variable_record_ms", "1"); + switch_core_hash_insert(filter, "variable_recovered", "1"); + switch_core_hash_insert(filter, "variable_silence_hits_exhausted", "1"); + switch_core_hash_insert(filter, "variable_sip_auth_realm", "1"); + switch_core_hash_insert(filter, "variable_sip_from_host", "1"); + switch_core_hash_insert(filter, "variable_sip_from_user", "1"); + switch_core_hash_insert(filter, "variable_sip_from_tag", "1"); + switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-IP", "1"); + switch_core_hash_insert(filter, "variable_sip_received_ip", "1"); + switch_core_hash_insert(filter, "variable_sip_to_host", "1"); + switch_core_hash_insert(filter, "variable_sip_to_user", "1"); + switch_core_hash_insert(filter, "variable_sip_to_tag", "1"); + switch_core_hash_insert(filter, "variable_sofia_profile_name", "1"); + switch_core_hash_insert(filter, "variable_transfer_history", "1"); + switch_core_hash_insert(filter, "variable_user_name", "1"); + switch_core_hash_insert(filter, "variable_endpoint_disposition", "1"); + switch_core_hash_insert(filter, "variable_originate_disposition", "1"); + switch_core_hash_insert(filter, "variable_bridge_hangup_cause", "1"); + switch_core_hash_insert(filter, "variable_hangup_cause", "1"); + switch_core_hash_insert(filter, "variable_last_bridge_proto_specific_hangup_cause", "1"); + switch_core_hash_insert(filter, "variable_proto_specific_hangup_cause", "1"); + switch_core_hash_insert(filter, "VM-Call-ID", "1"); + switch_core_hash_insert(filter, "VM-sub-call-id", "1"); + switch_core_hash_insert(filter, "whistle_application_name", "1"); + switch_core_hash_insert(filter, "whistle_application_response", "1"); + switch_core_hash_insert(filter, "whistle_event_name", "1"); + switch_core_hash_insert(filter, "kazoo_application_name", "1"); + switch_core_hash_insert(filter, "kazoo_application_response", "1"); + switch_core_hash_insert(filter, "kazoo_event_name", "1"); + switch_core_hash_insert(filter, "sip_auto_answer_notify", "1"); + switch_core_hash_insert(filter, "eavesdrop_group", "1"); + switch_core_hash_insert(filter, "origination_caller_id_name", "1"); + switch_core_hash_insert(filter, "origination_caller_id_number", "1"); + switch_core_hash_insert(filter, "origination_callee_id_name", "1"); + switch_core_hash_insert(filter, "origination_callee_id_number", "1"); + switch_core_hash_insert(filter, "sip_auth_username", "1"); + switch_core_hash_insert(filter, "sip_auth_password", "1"); + switch_core_hash_insert(filter, "effective_caller_id_name", "1"); + switch_core_hash_insert(filter, "effective_caller_id_number", "1"); + switch_core_hash_insert(filter, "effective_callee_id_name", "1"); + switch_core_hash_insert(filter, "effective_callee_id_number", "1"); + switch_core_hash_insert(filter, "variable_destination_number", "1"); + switch_core_hash_insert(filter, "variable_effective_callee_id_name", "1"); + switch_core_hash_insert(filter, "variable_effective_callee_id_number", "1"); + switch_core_hash_insert(filter, "variable_record_silence_hits", "1"); + switch_core_hash_insert(filter, "variable_refer_uuid", "1"); + switch_core_hash_insert(filter, "variable_sip_call_id", "1"); + switch_core_hash_insert(filter, "variable_sip_h_Referred-By", "1"); + switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-PORT", "1"); + switch_core_hash_insert(filter, "variable_sip_loopback_req_uri", "1"); + switch_core_hash_insert(filter, "variable_sip_received_port", "1"); + switch_core_hash_insert(filter, "variable_sip_refer_to", "1"); + switch_core_hash_insert(filter, "variable_sip_req_host", "1"); + switch_core_hash_insert(filter, "variable_sip_req_uri", "1"); + switch_core_hash_insert(filter, "variable_transfer_source", "1"); + switch_core_hash_insert(filter, "variable_uuid", "1"); + + /* Registration headers */ + switch_core_hash_insert(filter, "call-id", "1"); + switch_core_hash_insert(filter, "profile-name", "1"); + switch_core_hash_insert(filter, "from-user", "1"); + switch_core_hash_insert(filter, "from-host", "1"); + switch_core_hash_insert(filter, "presence-hosts", "1"); + switch_core_hash_insert(filter, "contact", "1"); + switch_core_hash_insert(filter, "rpid", "1"); + switch_core_hash_insert(filter, "status", "1"); + switch_core_hash_insert(filter, "expires", "1"); + switch_core_hash_insert(filter, "to-user", "1"); + switch_core_hash_insert(filter, "to-host", "1"); + switch_core_hash_insert(filter, "network-ip", "1"); + switch_core_hash_insert(filter, "network-port", "1"); + switch_core_hash_insert(filter, "username", "1"); + switch_core_hash_insert(filter, "realm", "1"); + switch_core_hash_insert(filter, "user-agent", "1"); + + switch_core_hash_insert(filter, "Hangup-Cause", "1"); + switch_core_hash_insert(filter, "Unique-ID", "1"); + switch_core_hash_insert(filter, "variable_switch_r_sdp", "1"); + switch_core_hash_insert(filter, "variable_rtp_local_sdp_str", "1"); + switch_core_hash_insert(filter, "variable_sip_to_uri", "1"); + switch_core_hash_insert(filter, "variable_sip_from_uri", "1"); + switch_core_hash_insert(filter, "variable_sip_user_agent", "1"); + switch_core_hash_insert(filter, "variable_duration", "1"); + switch_core_hash_insert(filter, "variable_billsec", "1"); + switch_core_hash_insert(filter, "variable_billmsec", "1"); + switch_core_hash_insert(filter, "variable_progresssec", "1"); + switch_core_hash_insert(filter, "variable_progress_uepoch", "1"); + switch_core_hash_insert(filter, "variable_progress_media_uepoch", "1"); + switch_core_hash_insert(filter, "variable_start_uepoch", "1"); + switch_core_hash_insert(filter, "variable_digits_dialed", "1"); + switch_core_hash_insert(filter, "Member-ID", "1"); + switch_core_hash_insert(filter, "Floor", "1"); + switch_core_hash_insert(filter, "Video", "1"); + switch_core_hash_insert(filter, "Hear", "1"); + switch_core_hash_insert(filter, "Speak", "1"); + switch_core_hash_insert(filter, "Talking", "1"); + switch_core_hash_insert(filter, "Current-Energy", "1"); + switch_core_hash_insert(filter, "Energy-Level", "1"); + switch_core_hash_insert(filter, "Mute-Detect", "1"); + + /* RTMP headers */ + switch_core_hash_insert(filter, "RTMP-Session-ID", "1"); + switch_core_hash_insert(filter, "RTMP-Profile", "1"); + switch_core_hash_insert(filter, "RTMP-Flash-Version", "1"); + switch_core_hash_insert(filter, "RTMP-SWF-URL", "1"); + switch_core_hash_insert(filter, "RTMP-TC-URL", "1"); + switch_core_hash_insert(filter, "RTMP-Page-URL", "1"); + switch_core_hash_insert(filter, "User", "1"); + switch_core_hash_insert(filter, "Domain", "1"); + + /* Fax headers */ + switch_core_hash_insert(filter, "variable_fax_bad_rows", "1"); + switch_core_hash_insert(filter, "variable_fax_document_total_pages", "1"); + switch_core_hash_insert(filter, "variable_fax_document_transferred_pages", "1"); + switch_core_hash_insert(filter, "variable_fax_ecm_used", "1"); + switch_core_hash_insert(filter, "variable_fax_result_code", "1"); + switch_core_hash_insert(filter, "variable_fax_result_text", "1"); + switch_core_hash_insert(filter, "variable_fax_success", "1"); + switch_core_hash_insert(filter, "variable_fax_transfer_rate", "1"); + switch_core_hash_insert(filter, "variable_fax_local_station_id", "1"); + switch_core_hash_insert(filter, "variable_fax_remote_station_id", "1"); + switch_core_hash_insert(filter, "variable_fax_remote_country", "1"); + switch_core_hash_insert(filter, "variable_fax_remote_vendor", "1"); + switch_core_hash_insert(filter, "variable_fax_remote_model", "1"); + switch_core_hash_insert(filter, "variable_fax_image_resolution", "1"); + switch_core_hash_insert(filter, "variable_fax_file_image_resolution", "1"); + switch_core_hash_insert(filter, "variable_fax_image_size", "1"); + switch_core_hash_insert(filter, "variable_fax_image_pixel_size", "1"); + switch_core_hash_insert(filter, "variable_fax_file_image_pixel_size", "1"); + switch_core_hash_insert(filter, "variable_fax_longest_bad_row_run", "1"); + switch_core_hash_insert(filter, "variable_fax_encoding", "1"); + switch_core_hash_insert(filter, "variable_fax_encoding_name", "1"); + switch_core_hash_insert(filter, "variable_fax_header", "1"); + switch_core_hash_insert(filter, "variable_fax_ident", "1"); + switch_core_hash_insert(filter, "variable_fax_timezone", "1"); + switch_core_hash_insert(filter, "variable_fax_doc_id", "1"); + switch_core_hash_insert(filter, "variable_fax_doc_database", "1"); + switch_core_hash_insert(filter, "variable_has_t38", "1"); + + /* Secure headers */ + switch_core_hash_insert(filter, "variable_sdp_secure_savp_only", "1"); + switch_core_hash_insert(filter, "variable_rtp_has_crypto", "1"); + switch_core_hash_insert(filter, "variable_rtp_secure_media", "1"); + switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed", "1"); + switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_audio", "1"); + switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_video", "1"); + switch_core_hash_insert(filter, "variable_zrtp_secure_media", "1"); + switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed", "1"); + switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_audio", "1"); + switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_video", "1"); + switch_core_hash_insert(filter, "sdp_secure_savp_only", "1"); + switch_core_hash_insert(filter, "rtp_has_crypto", "1"); + switch_core_hash_insert(filter, "rtp_secure_media", "1"); + switch_core_hash_insert(filter, "rtp_secure_media_confirmed", "1"); + switch_core_hash_insert(filter, "rtp_secure_media_confirmed_audio", "1"); + switch_core_hash_insert(filter, "rtp_secure_media_confirmed_video", "1"); + switch_core_hash_insert(filter, "zrtp_secure_media", "1"); + switch_core_hash_insert(filter, "zrtp_secure_media_confirmed", "1"); + switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_audio", "1"); + switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_video", "1"); + + /* Device Redirect headers */ + switch_core_hash_insert(filter, "variable_last_bridge_hangup_cause", "1"); + switch_core_hash_insert(filter, "variable_sip_redirected_by", "1"); + switch_core_hash_insert(filter, "intercepted_by", "1"); + switch_core_hash_insert(filter, "variable_bridge_uuid", "1"); + switch_core_hash_insert(filter, "Record-File-Path", "1"); + + /* Loopback headers */ + switch_core_hash_insert(filter, "variable_loopback_bowout_on_execute", "1"); + switch_core_hash_insert(filter, "variable_loopback_bowout", "1"); + switch_core_hash_insert(filter, "variable_other_loopback_leg_uuid", "1"); + switch_core_hash_insert(filter, "variable_loopback_leg", "1"); + switch_core_hash_insert(filter, "variable_is_loopback", "1"); + + // SMS + switch_core_hash_insert(filter, "Message-ID", "1"); + switch_core_hash_insert(filter, "Delivery-Failure", "1"); + switch_core_hash_insert(filter, "Delivery-Result-Code", "1"); + + return filter; +} + +static void fetch_config_filters(switch_memory_pool_t *pool) +{ + char *cf = "kazoo.conf"; + switch_xml_t cfg, xml, child, param; + switch_event_t *params; + + switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-filter"); + + if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf); + } else if ((child = switch_xml_child(cfg, "event-filter"))) { + switch_hash_t *filter; + switch_hash_t *old_filter; + + switch_core_hash_init(&filter); + for (param = switch_xml_child(child, "header"); param; param = param->next) { + char *var = (char *) switch_xml_attr_soft(param, "name"); + switch_core_hash_insert(filter, var, "1"); + } + + old_filter = kazoo_globals.event_filter; + kazoo_globals.event_filter = filter; + if (old_filter) { + switch_core_hash_destroy(&old_filter); + } + + kazoo_globals.config_fetched = 1; + switch_xml_free(xml); + } + +} + +static void fetch_config_handlers(switch_memory_pool_t *pool) +{ + char *cf = "kazoo.conf"; + switch_xml_t cfg, xml; + switch_event_t *params; + + switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-handlers"); + + if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf); + } else { + kazoo_config_handlers(cfg); + kazoo_globals.config_fetched = 1; + switch_xml_free(xml); + } + +} + +static void *SWITCH_THREAD_FUNC fetch_config_exec(switch_thread_t *thread, void *obj) +{ + switch_memory_pool_t *pool = (switch_memory_pool_t *)obj; + fetch_config_filters(pool); + fetch_config_handlers(pool); + + kazoo_globals.config_fetched = 1; + + return NULL; +} + +void fetch_config() { + switch_memory_pool_t *pool; + switch_thread_t *thread; + switch_threadattr_t *thd_attr = NULL; + switch_uuid_t uuid; + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "fetching kazoo config\n"); + + switch_core_new_memory_pool(&pool); + + switch_threadattr_create(&thd_attr, pool); + switch_threadattr_detach_set(thd_attr, 1); + switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); + + switch_uuid_get(&uuid); + switch_thread_create(&thread, thd_attr, fetch_config_exec, pool, pool); + +} + + +SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime) { + switch_os_socket_t os_socket; + + if(create_acceptor() != SWITCH_STATUS_SUCCESS) { + // TODO: what would we need to clean up here + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to create erlang connection acceptor!\n"); + close_socket(&kazoo_globals.acceptor); + return SWITCH_STATUS_TERM; + } + + switch_atomic_inc(&kazoo_globals.threads); + switch_os_sock_get(&os_socket, kazoo_globals.acceptor); + + while (switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { + int nodefd; + ErlConnect conn; + + /* zero out errno because ei_accept doesn't differentiate between a */ + /* failed authentication or a socket failure, or a client version */ + /* mismatch or a godzilla attack (and a godzilla attack is highly likely) */ + errno = 0; + + /* wait here for an erlang node to connect, timming out to check if our module is still running every now-and-again */ + if ((nodefd = ei_accept_tmo(&kazoo_globals.ei_cnode, (int) os_socket, &conn, kazoo_globals.connection_timeout)) == ERL_ERROR) { + if (erl_errno == ETIMEDOUT) { + continue; + } else if (errno) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Erlang connection acceptor socket error %d %d\n", erl_errno, errno); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "Erlang node connection failed - ensure your cookie matches '%s' and you are using a good nodename\n", kazoo_globals.ei_cookie); + } + continue; + } + + if (!switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { + break; + } + + /* NEW ERLANG NODE CONNECTION! Hello friend! */ + new_kazoo_node(nodefd, &conn); + } + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor shut down\n"); + + switch_atomic_dec(&kazoo_globals.threads); + + return SWITCH_STATUS_TERM; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_endpoints.c b/src/mod/event_handlers/mod_kazoo/kazoo_endpoints.c new file mode 100644 index 0000000000..fba1adddb1 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_endpoints.c @@ -0,0 +1,284 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Karl Anderson + * Darren Schreiber + * + * + * kazoo_dptools.c -- clones of mod_dptools commands slightly modified for kazoo + * + */ +#include "mod_kazoo.h" + +/* kazoo endpoint */ +switch_endpoint_interface_t *kz_endpoint_interface; +static switch_call_cause_t kz_endpoint_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause); +switch_io_routines_t kz_endpoint_io_routines = { + /*.outgoing_channel */ kz_endpoint_outgoing_channel +}; + +static switch_call_cause_t kz_endpoint_outgoing_channel(switch_core_session_t *session, + switch_event_t *var_event, + switch_caller_profile_t *outbound_profile, + switch_core_session_t **new_session, switch_memory_pool_t **pool, switch_originate_flag_t flags, + switch_call_cause_t *cancel_cause) +{ + switch_xml_t x_user = NULL, x_param, x_params; + char *user = NULL, *domain = NULL, *dup_domain = NULL, *dialed_user = NULL; + const char *dest = NULL; + switch_call_cause_t cause = SWITCH_CAUSE_NONE; + unsigned int timelimit = SWITCH_DEFAULT_TIMEOUT; + switch_channel_t *new_channel = NULL; + switch_event_t *params = NULL, *var_event_orig = var_event; + char stupid[128] = ""; + const char *skip = NULL, *var = NULL; + + if (zstr(outbound_profile->destination_number)) { + goto done; + } + + user = strdup(outbound_profile->destination_number); + + if (!user) + goto done; + + if ((domain = strchr(user, '@'))) { + *domain++ = '\0'; + } else { + domain = switch_core_get_domain(SWITCH_TRUE); + dup_domain = domain; + } + + if (!domain) { + goto done; + } + + + switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); + switch_assert(params); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "as_channel", "true"); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "action", "user_call"); + + if (var_event) { + switch_event_merge(params, var_event); + } + + if (var_event && (skip = switch_event_get_header(var_event, "user_recurse_variables")) && switch_false(skip)) { + if ((var = switch_event_get_header(var_event, SWITCH_CALL_TIMEOUT_VARIABLE)) || (var = switch_event_get_header(var_event, "leg_timeout"))) { + timelimit = atoi(var); + } + var_event = NULL; + } + + if (switch_xml_locate_user_merged("id", user, domain, NULL, &x_user, params) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Can't find user [%s@%s]\n", user, domain); + cause = SWITCH_CAUSE_SUBSCRIBER_ABSENT; + goto done; + } + + if ((x_params = switch_xml_child(x_user, "params"))) { + for (x_param = switch_xml_child(x_params, "param"); x_param; x_param = x_param->next) { + const char *pvar = switch_xml_attr_soft(x_param, "name"); + const char *val = switch_xml_attr(x_param, "value"); + + if (!strcasecmp(pvar, "dial-string")) { + dest = val; + } else if (!strncasecmp(pvar, "dial-var-", 9)) { + if (!var_event) { + switch_event_create(&var_event, SWITCH_EVENT_GENERAL); + } else { + switch_event_del_header(var_event, pvar + 9); + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "adding variable to var_event => %s = %s\n", pvar + 9, val); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, pvar + 9, val); + } + } + } + + dialed_user = (char *)switch_xml_attr(x_user, "id"); + + if (var_event) { + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_user", dialed_user); + switch_event_add_header_string(var_event, SWITCH_STACK_BOTTOM, "dialed_domain", domain); + if (!zstr(dest) && !strstr(dest, "presence_id=")) { + switch_event_add_header(var_event, SWITCH_STACK_BOTTOM, "presence_id", "%s@%s", dialed_user, domain); + } + } + + if (!dest) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No dial-string available, please check your user directory.\n"); + cause = SWITCH_CAUSE_MANDATORY_IE_MISSING; + } else { + const char *varval; + char *d_dest = NULL; + switch_channel_t *channel; + switch_originate_flag_t myflags = SOF_NONE; + char *cid_name_override = NULL; + char *cid_num_override = NULL; + + if (var_event) { + cid_name_override = switch_event_get_header(var_event, "origination_caller_id_name"); + cid_num_override = switch_event_get_header(var_event, "origination_caller_id_number"); + } + + if (session) { + switch_event_t *event = NULL; + switch_event_create(&event, SWITCH_EVENT_GENERAL); + channel = switch_core_session_get_channel(session); + if ((varval = switch_channel_get_variable(channel, SWITCH_CALL_TIMEOUT_VARIABLE)) + || (var_event && (varval = switch_event_get_header(var_event, "leg_timeout")))) { + timelimit = atoi(varval); + } + switch_channel_event_set_data(channel, event); + if(var_event) { + switch_event_merge(event, var_event); + } + + switch_channel_set_variable(channel, "dialed_user", dialed_user); + switch_channel_set_variable(channel, "dialed_domain", domain); + + d_dest = switch_event_expand_headers(event, dest); + + switch_event_destroy(&event); + + } else { + switch_event_t *event = NULL; + + if (var_event) { + switch_event_dup(&event, var_event); + switch_event_del_header(event, "dialed_user"); + switch_event_del_header(event, "dialed_domain"); + if ((varval = switch_event_get_header(var_event, SWITCH_CALL_TIMEOUT_VARIABLE)) || + (varval = switch_event_get_header(var_event, "leg_timeout"))) { + timelimit = atoi(varval); + } + } else { + switch_event_create(&event, SWITCH_EVENT_REQUEST_PARAMS); + switch_assert(event); + } + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "dialed_user", dialed_user); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "dialed_domain", domain); + d_dest = switch_event_expand_headers(event, dest); + switch_event_destroy(&event); + } + + if ((flags & SOF_NO_LIMITS)) { + myflags |= SOF_NO_LIMITS; + } + + if ((flags & SOF_FORKED_DIAL)) { + myflags |= SOF_NOBLOCK; + } + + switch_snprintf(stupid, sizeof(stupid), "kz/%s", dialed_user); + if (switch_stristr(stupid, d_dest)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Waddya Daft? You almost called '%s' in an infinate loop!\n", + stupid); + cause = SWITCH_CAUSE_INVALID_IE_CONTENTS; + } else if (switch_ivr_originate(session, new_session, &cause, d_dest, timelimit, NULL, + cid_name_override, cid_num_override, outbound_profile, var_event, myflags, + cancel_cause, NULL) == SWITCH_STATUS_SUCCESS) { + const char *context; + switch_caller_profile_t *cp; + + if (var_event) { + switch_event_del_header(var_event, "origination_uuid"); + } + + new_channel = switch_core_session_get_channel(*new_session); + + if ((context = switch_channel_get_variable(new_channel, "user_context"))) { + if ((cp = switch_channel_get_caller_profile(new_channel))) { + cp->context = switch_core_strdup(cp->pool, context); + } + } + + if ((x_params = switch_xml_child(x_user, "variables"))) { + for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) { + const char *pvar = switch_xml_attr(x_param, "name"); + const char *val = switch_xml_attr(x_param, "value"); + switch_channel_set_variable(new_channel, pvar, val); + } + } + + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_DEBUG1, "CHECKING CALLER-ID\n"); + if ((x_params = switch_xml_child(x_user, "profile-variables"))) { + switch_caller_profile_t *cp = NULL; + const char* val = NULL; + for (x_param = switch_xml_child(x_params, "variable"); x_param; x_param = x_param->next) { + const char *pvar = switch_xml_attr(x_param, "name"); + const char *val = switch_xml_attr(x_param, "value"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(*new_session), SWITCH_LOG_DEBUG1, "setting profile var %s = %s\n", pvar, val); + switch_channel_set_profile_var(new_channel, pvar, val); + } + cp = switch_channel_get_caller_profile(new_channel); + if((val=switch_caller_get_field_by_name(cp, "Endpoint-Caller-ID-Name"))) { + cp->callee_id_name = val; + cp->orig_caller_id_name = val; + } + if((val=switch_caller_get_field_by_name(cp, "Endpoint-Caller-ID-Number"))) { + cp->callee_id_number = val; + cp->orig_caller_id_number = val; + } + } + switch_core_session_rwunlock(*new_session); + } + + if (d_dest != dest) { + switch_safe_free(d_dest); + } + } + + done: + + if (x_user) { + switch_xml_free(x_user); + } + + if (params) { + switch_event_destroy(¶ms); + } + + if (var_event && var_event_orig != var_event) { + switch_event_destroy(&var_event); + } + + switch_safe_free(user); + switch_safe_free(dup_domain); + + return cause; +} + + +void add_kz_endpoints(switch_loadable_module_interface_t **module_interface) { + kz_endpoint_interface = (switch_endpoint_interface_t *) switch_loadable_module_create_interface(*module_interface, SWITCH_ENDPOINT_INTERFACE); + kz_endpoint_interface->interface_name = "kz"; + kz_endpoint_interface->io_routines = &kz_endpoint_io_routines; +} diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_event_stream.c b/src/mod/event_handlers/mod_kazoo/kazoo_event_stream.c index 3ca0e3acc7..5e5fb8dff4 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_event_stream.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_event_stream.c @@ -32,6 +32,8 @@ */ #include "mod_kazoo.h" +#define MAX_FRAMING 4 + /* Blatantly repurposed from switch_eventc */ static char *my_dup(const char *s) { size_t len = strlen(s) + 1; @@ -48,7 +50,8 @@ static char *my_dup(const char *s) { static const char* private_headers[] = {"variable_sip_h_", "sip_h_", "P-", "X-"}; static int is_private_header(const char *name) { - for(int i=0; i < 4; i++) { + int i; + for(i=0; i < 4; i++) { if(!strncmp(name, private_headers[i], strlen(private_headers[i]))) { return 1; } @@ -56,6 +59,20 @@ static int is_private_header(const char *name) { return 0; } +static int is_kazoo_var(char* header) +{ + int idx = 0; + while(kazoo_globals.kazoo_var_prefixes[idx] != NULL) { + char *prefix = kazoo_globals.kazoo_var_prefixes[idx]; + if(!strncasecmp(header, prefix, strlen(prefix))) { + return 1; + } + idx++; + } + + return 0; +} + static switch_status_t kazoo_event_dup(switch_event_t **clone, switch_event_t *event, switch_hash_t *filter) { switch_event_header_t *header; @@ -73,7 +90,7 @@ static switch_status_t kazoo_event_dup(switch_event_t **clone, switch_event_t *e continue; } - if (strncmp(header->name, kazoo_globals.kazoo_var_prefix, kazoo_globals.var_prefix_length) + if (!is_kazoo_var(header->name) && filter && !switch_core_hash_find(filter, header->name) && (!kazoo_globals.send_all_headers) @@ -102,51 +119,115 @@ static switch_status_t kazoo_event_dup(switch_event_t **clone, switch_event_t *e return SWITCH_STATUS_SUCCESS; } -static void event_handler(switch_event_t *event) { +static int encode_event_old(switch_event_t *event, ei_x_buff *ebuf) { switch_event_t *clone = NULL; - ei_event_stream_t *event_stream = (ei_event_stream_t *) event->bind_user_data; + + if (kazoo_event_dup(&clone, event, kazoo_globals.event_filter) != SWITCH_STATUS_SUCCESS) { + return 0; + } + + ei_encode_switch_event(ebuf, clone); + + switch_event_destroy(&clone); + + return 1; +} + +static int encode_event_new(switch_event_t *event, ei_x_buff *ebuf) { + kazoo_message_ptr msg = NULL; + ei_event_binding_t *event_binding = (ei_event_binding_t *) event->bind_user_data; + + msg = kazoo_message_create_event(event, event_binding->event, kazoo_globals.events); + + if(msg == NULL) { + return 0; + } + + ei_x_encode_tuple_header(ebuf, 3); + ei_x_encode_atom(ebuf, "event"); + if(kazoo_globals.json_encoding == ERLANG_TUPLE) { + ei_x_encode_atom(ebuf, "json"); + } else { + ei_x_encode_atom(ebuf, "map"); + } + ei_encode_json(ebuf, msg->JObj); + + kazoo_message_destroy(&msg); + + return 1; +} + +/* + * event_handler is duplicated when there are 2+ nodes connected + * with the same bindings + * we should maintain a list of event_streams in event_binding struct + * and build a ref count in the message + * + */ +static void event_handler(switch_event_t *event) { + ei_event_binding_t *event_binding = (ei_event_binding_t *) event->bind_user_data; + ei_event_stream_t *event_stream = event_binding->stream; + ei_x_buff *ebuf = NULL; + int res = 0; /* if mod_kazoo or the event stream isn't running dont push a new event */ if (!switch_test_flag(event_stream, LFLAG_RUNNING) || !switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { return; } - if (event->event_id == SWITCH_EVENT_CUSTOM) { - ei_event_binding_t *event_binding = event_stream->bindings; - unsigned short int found = 0; + kz_event_decode(event); - if (!event->subclass_name) { - return; - } - - while(event_binding != NULL) { - if (event_binding->type == SWITCH_EVENT_CUSTOM) { - if(event_binding->subclass_name - && !strcmp(event->subclass_name, event_binding->subclass_name)) { - found = 1; - break; - } - } - event_binding = event_binding->next; - } - - if (!found) { - return; - } + switch_malloc(ebuf, sizeof(*ebuf)); + if(ebuf == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not allocate erlang buffer for mod_kazoo message\n"); + return; } + memset(ebuf, 0, sizeof(*ebuf)); - /* try to clone the event and push it to the event stream thread */ - /* TODO: someday maybe the filter comes from the event_stream (set during init only) - * and is per-binding so we only send headers that a process requests */ - if (kazoo_event_dup(&clone, event, kazoo_globals.event_filter) == SWITCH_STATUS_SUCCESS) { - if (switch_queue_trypush(event_stream->queue, clone) != SWITCH_STATUS_SUCCESS) { - /* if we couldn't place the cloned event into the listeners */ - /* event queue make sure we destroy it, real good like */ - switch_event_destroy(&clone); + if(kazoo_globals.event_stream_preallocate > 0) { + ebuf->buff = malloc(kazoo_globals.event_stream_preallocate); + ebuf->buffsz = kazoo_globals.event_stream_preallocate; + ebuf->index = 0; + if(ebuf->buff == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not pre-allocate memory for mod_kazoo message\n"); + switch_safe_free(ebuf); + return; } } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory error: Have a good trip? See you next fall!\n"); + ei_x_new(ebuf); } + + ebuf->index = MAX_FRAMING; + + ei_x_encode_version(ebuf); + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Target-Node", event_binding->stream->node->peer_nodename); + + if(event_stream->node->legacy) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename); + res = encode_event_old(event, ebuf); + } else { + res = encode_event_new(event, ebuf); + } + + if(!res) { + ei_x_free(ebuf); + switch_safe_free(ebuf); + return; + } + + if (kazoo_globals.event_stream_preallocate > 0 && ebuf->buffsz > kazoo_globals.event_stream_preallocate) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "increased event stream buffer size to %d\n", ebuf->buffsz); + } + + if (switch_queue_trypush(event_stream->queue, ebuf) != SWITCH_STATUS_SUCCESS) { + /* if we couldn't place the cloned event into the listeners */ + /* event queue make sure we destroy it, real good like */ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error placing the event in the listeners queue\n"); + ei_x_free(ebuf); + switch_safe_free(ebuf); + } + } static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void *obj) { @@ -157,12 +238,15 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void char ipbuf[48]; const char *ip_addr; void *pop; - short event_stream_framing = kazoo_globals.event_stream_framing; + short event_stream_framing; + short ok = 1; switch_atomic_inc(&kazoo_globals.threads); switch_assert(event_stream != NULL); + event_stream_framing = event_stream->event_stream_framing; + /* figure out what socket we just opened */ switch_socket_addr_get(&sa, SWITCH_FALSE, event_stream->acceptor); port = switch_sockaddr_get_port(sa); @@ -172,13 +256,14 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void ,(void *)event_stream, ip_addr, port, event_stream->pid.node, event_stream->pid.creation ,event_stream->pid.num, event_stream->pid.serial); - while (switch_test_flag(event_stream, LFLAG_RUNNING) && switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { + while (switch_test_flag(event_stream, LFLAG_RUNNING) && switch_test_flag(&kazoo_globals, LFLAG_RUNNING) && ok) { const switch_pollfd_t *fds; int32_t numfds; /* check if a new connection is pending */ if (switch_pollset_poll(event_stream->pollset, 0, &numfds, &fds) == SWITCH_STATUS_SUCCESS) { - for (int32_t i = 0; i < numfds; i++) { + int32_t i; + for (i = 0; i < numfds; i++) { switch_socket_t *newsocket; /* accept the new client connection */ @@ -201,11 +286,11 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void event_stream->socket = newsocket; switch_socket_addr_get(&sa, SWITCH_TRUE, newsocket); - event_stream->local_port = switch_sockaddr_get_port(sa); + event_stream->remote_port = switch_sockaddr_get_port(sa); switch_get_addr(event_stream->remote_ip, sizeof (event_stream->remote_ip), sa); switch_socket_addr_get(&sa, SWITCH_FALSE, newsocket); - event_stream->remote_port = switch_sockaddr_get_port(sa); + event_stream->local_port = switch_sockaddr_get_port(sa); switch_get_addr(event_stream->local_ip, sizeof (event_stream->local_ip), sa); event_stream->connected = SWITCH_TRUE; @@ -217,46 +302,38 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void } /* if there was an event waiting in our queue send it to the client */ - if (switch_queue_pop_timeout(event_stream->queue, &pop, 500000) == SWITCH_STATUS_SUCCESS) { - switch_event_t *event = (switch_event_t *) pop; + if (switch_queue_pop_timeout(event_stream->queue, &pop, 200000) == SWITCH_STATUS_SUCCESS) { + ei_x_buff *ebuf = (ei_x_buff *) pop; if (event_stream->socket) { - ei_x_buff ebuf; - char byte; - short i = event_stream_framing; - switch_size_t size = 1; + switch_size_t size = 1, expected = 0; + switch_status_t status = SWITCH_STATUS_SUCCESS; - if(kazoo_globals.event_stream_preallocate > 0) { - ebuf.buff = malloc(kazoo_globals.event_stream_preallocate); - ebuf.buffsz = kazoo_globals.event_stream_preallocate; - ebuf.index = 0; - if(ebuf.buff == NULL) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Could not pre-allocate memory for mod_kazoo message\n"); - break; - } - ei_x_encode_version(&ebuf); + if(ebuf->index >= pow(2, 8 * event_stream_framing)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "sending frame size %d with insufficient frame capacity, change event_stream_framing here and tcp_packet_type in ecallmgr\n", ebuf->index); } else { - ei_x_new_with_version(&ebuf); + if(event_stream_framing) { + int index = ebuf->index - MAX_FRAMING; + char byte; + short i = event_stream_framing; + while (i) { + byte = index >> (8 * --i); + ebuf->buff[MAX_FRAMING - i - 1] = byte; + } + } + expected = size = (switch_size_t)ebuf->index - MAX_FRAMING + event_stream_framing; + if((status = switch_socket_send(event_stream->socket, ebuf->buff + (MAX_FRAMING - event_stream_framing), &size)) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error %d sending event stream\n", status); + ok = 0; + } else if(expected != size) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error sending event stream, sent bytes is different of expected\n"); + ok = 0; + } } - - ei_encode_switch_event(&ebuf, event); - - if (kazoo_globals.event_stream_preallocate > 0 && ebuf.buffsz > kazoo_globals.event_stream_preallocate) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "increased event stream buffer size to %d\n", ebuf.buffsz); - } - - while (i) { - byte = ebuf.index >> (8 * --i); - switch_socket_send(event_stream->socket, &byte, &size); - } - - size = (switch_size_t)ebuf.index; - switch_socket_send(event_stream->socket, ebuf.buff, &size); - - ei_x_free(&ebuf); } - switch_event_destroy(&event); + ei_x_free(ebuf); + switch_safe_free(ebuf); } } @@ -272,8 +349,9 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void /* clear and destroy any remaining queued events */ while (switch_queue_trypop(event_stream->queue, &pop) == SWITCH_STATUS_SUCCESS) { - switch_event_t *event = (switch_event_t *) pop; - switch_event_destroy(&event); + ei_x_buff *ebuf = (ei_x_buff *) pop; + ei_x_free(ebuf); + switch_safe_free(ebuf); } /* remove the acceptor pollset */ @@ -297,11 +375,12 @@ static void *SWITCH_THREAD_FUNC event_stream_loop(switch_thread_t *thread, void return NULL; } -ei_event_stream_t *new_event_stream(ei_event_stream_t **event_streams, const erlang_pid *from) { +ei_event_stream_t *new_event_stream(ei_node_t *ei_node, const erlang_pid *from) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; switch_memory_pool_t *pool = NULL; ei_event_stream_t *event_stream; + ei_event_stream_t **event_streams = &ei_node->event_streams; /* create memory pool for this event stream */ if (switch_core_new_memory_pool(&pool) != SWITCH_STATUS_SUCCESS) { @@ -320,6 +399,8 @@ ei_event_stream_t *new_event_stream(ei_event_stream_t **event_streams, const erl event_stream->bindings = NULL; event_stream->pool = pool; event_stream->connected = SWITCH_FALSE; + event_stream->node = ei_node; + event_stream->event_stream_framing = ei_node->event_stream_framing; memcpy(&event_stream->pid, from, sizeof(erlang_pid)); switch_queue_create(&event_stream->queue, MAX_QUEUE_LEN, pool); @@ -443,17 +524,68 @@ switch_status_t remove_event_streams(ei_event_stream_t **event_streams) { return SWITCH_STATUS_SUCCESS; } -switch_status_t add_event_binding(ei_event_stream_t *event_stream, const switch_event_types_t event_type, const char *subclass_name) { +void bind_event_profile(ei_event_binding_t *event_binding, kazoo_event_ptr event) +{ + switch_event_types_t event_type; + while(event != NULL) { + if (switch_name_event(event->name, &event_type) != SWITCH_STATUS_SUCCESS) { + event_type = SWITCH_EVENT_CUSTOM; + } + if(event_binding->type != SWITCH_EVENT_CUSTOM + && event_binding->type == event_type) { + break; + } + if (event_binding->type == SWITCH_EVENT_CUSTOM + && event_binding->type == event_type + && !strcasecmp(event_binding->subclass_name, event->name)) { + break; + } + event = event->next; + } + event_binding->event = event; + if(event == NULL && (!event_binding->stream->node->legacy)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "event binding to an event without profile in non legacy mode => %s - %s\n",switch_event_name(event_binding->type), event_binding->subclass_name); + } +} + +void bind_event_profiles(kazoo_event_ptr event) +{ + ei_node_t *ei_node = kazoo_globals.ei_nodes; + while(ei_node) { + ei_event_stream_t *event_streams = ei_node->event_streams; + while(event_streams) { + ei_event_binding_t *bindings = event_streams->bindings; + while(bindings) { + bind_event_profile(bindings, event); + bindings = bindings->next; + } + event_streams = event_streams->next; + } + ei_node = ei_node->next; + } +} + +switch_status_t add_event_binding(ei_event_stream_t *event_stream, const char *event_name) { ei_event_binding_t *event_binding = event_stream->bindings; + switch_event_types_t event_type; + + if(!strcasecmp(event_name, "CUSTOM")) { + return SWITCH_STATUS_SUCCESS; + } + + if (switch_name_event(event_name, &event_type) != SWITCH_STATUS_SUCCESS) { + event_type = SWITCH_EVENT_CUSTOM; + } /* check if the event binding already exists, ignore if so */ while(event_binding != NULL) { if (event_binding->type == SWITCH_EVENT_CUSTOM) { - if(subclass_name - && event_binding->subclass_name - && !strcmp(subclass_name, event_binding->subclass_name)) { - return SWITCH_STATUS_SUCCESS; - } + if(event_type == SWITCH_EVENT_CUSTOM + && event_name + && event_binding->subclass_name + && !strcasecmp(event_name, event_binding->subclass_name)) { + return SWITCH_STATUS_SUCCESS; + } } else if (event_binding->type == event_type) { return SWITCH_STATUS_SUCCESS; } @@ -467,18 +599,21 @@ switch_status_t add_event_binding(ei_event_stream_t *event_stream, const switch_ } /* prepare the event binding struct */ + event_binding->stream = event_stream; event_binding->type = event_type; - if (!subclass_name || zstr(subclass_name)) { - event_binding->subclass_name = NULL; + if(event_binding->type == SWITCH_EVENT_CUSTOM) { + event_binding->subclass_name = switch_core_strdup(event_stream->pool, event_name); } else { - /* TODO: free strdup? */ - event_binding->subclass_name = strdup(subclass_name); + event_binding->subclass_name = SWITCH_EVENT_SUBCLASS_ANY; } event_binding->next = NULL; + bind_event_profile(event_binding, kazoo_globals.events->events); + + /* bind to the event with a unique ID and capture the event_node pointer */ switch_uuid_str(event_binding->id, sizeof(event_binding->id)); - if (switch_event_bind_removable(event_binding->id, event_type, subclass_name, event_handler, event_stream, &event_binding->node) != SWITCH_STATUS_SUCCESS) { + if (switch_event_bind_removable(event_binding->id, event_type, event_binding->subclass_name, event_handler, event_binding, &event_binding->node) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to bind to event %s %s!\n" ,switch_event_name(event_binding->type), event_binding->subclass_name ? event_binding->subclass_name : ""); return SWITCH_STATUS_GENERR; diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c b/src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c index 006ffe32f0..24d4358b7e 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_fetch_agent.c @@ -32,38 +32,12 @@ */ #include "mod_kazoo.h" -struct xml_fetch_reply_s { - char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; - char *xml_str; - struct xml_fetch_reply_s *next; +static const char *fetch_uuid_sources[] = { + "Fetch-Call-UUID", + "refer-from-channel-id", + "sip_call_id", + NULL }; -typedef struct xml_fetch_reply_s xml_fetch_reply_t; - -struct fetch_handler_s { - erlang_pid pid; - struct fetch_handler_s *next; -}; -typedef struct fetch_handler_s fetch_handler_t; - -struct ei_xml_client_s { - ei_node_t *ei_node; - fetch_handler_t *fetch_handlers; - struct ei_xml_client_s *next; -}; -typedef struct ei_xml_client_s ei_xml_client_t; - -struct ei_xml_agent_s { - switch_memory_pool_t *pool; - switch_xml_section_t section; - switch_thread_rwlock_t *lock; - ei_xml_client_t *clients; - switch_mutex_t *current_client_mutex; - ei_xml_client_t *current_client; - switch_mutex_t *replies_mutex; - switch_thread_cond_t *new_reply; - xml_fetch_reply_t *replies; -}; -typedef struct ei_xml_agent_s ei_xml_agent_t; static char *xml_section_to_string(switch_xml_section_t section) { switch(section) { @@ -77,6 +51,8 @@ static char *xml_section_to_string(switch_xml_section_t section) { return "chatplan"; case SWITCH_XML_SECTION_CHANNELS: return "channels"; + case SWITCH_XML_SECTION_LANGUAGES: + return "languages"; default: return "unknown"; } @@ -105,8 +81,10 @@ static char *expand_vars(char *xml_str) { *e++ = '\0'; rp = e; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "trying to expand %s \n", var); if ((val = switch_core_get_variable_dup(var))) { char *p; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "expanded %s to %s\n", var, val); for (p = val; p && *p && wp <= ep; p++) { *wp++ = *p; } @@ -133,6 +111,11 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con ei_xml_client_t *client; fetch_handler_t *fetch_handler; xml_fetch_reply_t reply, *pending, *prev = NULL; + switch_event_t *event = params; + kazoo_fetch_profile_ptr profile = agent->profile; + const char *fetch_call_id; + ei_send_msg_t *send_msg = NULL; + int sent = 0; now = switch_micro_time_now(); @@ -164,12 +147,71 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con return xml; } + if(event == NULL) { + if (switch_event_create(&event, SWITCH_EVENT_GENERAL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error creating event for fetch handler\n"); + return xml; + } + } + /* prepare the reply collector */ switch_uuid_get(&uuid); switch_uuid_format(reply.uuid_str, &uuid); reply.next = NULL; reply.xml_str = NULL; + if(switch_event_get_header(event, "Unique-ID") == NULL) { + int i; + for(i = 0; fetch_uuid_sources[i] != NULL; i++) { + if((fetch_call_id = switch_event_get_header(event, fetch_uuid_sources[i])) != NULL) { + switch_core_session_t *session = NULL; + if((session = switch_core_session_force_locate(fetch_call_id)) != NULL) { + switch_channel_t *channel = switch_core_session_get_channel(session); + uint32_t verbose = switch_channel_test_flag(channel, CF_VERBOSE_EVENTS); + switch_channel_set_flag(channel, CF_VERBOSE_EVENTS); + switch_channel_event_set_data(channel, event); + switch_channel_set_flag_value(channel, CF_VERBOSE_EVENTS, verbose); + switch_core_session_rwunlock(session); + break; + } + } + } + } + + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-UUID", reply.uuid_str); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Section", section); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Tag", tag_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Key-Name", key_name); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Fetch-Key-Value", key_value); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Fetch-Timeout", "%u", profile->fetch_timeout); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Fetch-Timestamp-Micro", "%" SWITCH_UINT64_T_FMT, (uint64_t)now); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Version", VERSION); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Bundle", BUNDLE); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Kazoo-Release", RELEASE); + + kz_event_decode(event); + + switch_malloc(send_msg, sizeof(*send_msg)); + + if(client->ei_node->legacy) { + ei_x_new_with_version(&send_msg->buf); + ei_x_encode_tuple_header(&send_msg->buf, 7); + ei_x_encode_atom(&send_msg->buf, "fetch"); + ei_x_encode_atom(&send_msg->buf, section); + _ei_x_encode_string(&send_msg->buf, tag_name ? tag_name : "undefined"); + _ei_x_encode_string(&send_msg->buf, key_name ? key_name : "undefined"); + _ei_x_encode_string(&send_msg->buf, key_value ? key_value : "undefined"); + _ei_x_encode_string(&send_msg->buf, reply.uuid_str); + ei_encode_switch_event_headers(&send_msg->buf, event); + } else { + kazoo_message_ptr msg = kazoo_message_create_fetch(event, profile); + ei_x_new_with_version(&send_msg->buf); + ei_x_encode_tuple_header(&send_msg->buf, 2); + ei_x_encode_atom(&send_msg->buf, "fetch"); + ei_encode_json(&send_msg->buf, msg->JObj); + kazoo_message_destroy(&msg); + } + /* add our reply placeholder to the replies list */ switch_mutex_lock(agent->replies_mutex); if (!agent->replies) { @@ -181,28 +223,8 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con switch_mutex_unlock(agent->replies_mutex); fetch_handler = client->fetch_handlers; - while (fetch_handler != NULL) { - ei_send_msg_t *send_msg; - - switch_malloc(send_msg, sizeof(*send_msg)); + while (fetch_handler != NULL && sent == 0) { memcpy(&send_msg->pid, &fetch_handler->pid, sizeof(erlang_pid)); - - ei_x_new_with_version(&send_msg->buf); - - ei_x_encode_tuple_header(&send_msg->buf, 7); - ei_x_encode_atom(&send_msg->buf, "fetch"); - ei_x_encode_atom(&send_msg->buf, section); - _ei_x_encode_string(&send_msg->buf, tag_name ? tag_name : "undefined"); - _ei_x_encode_string(&send_msg->buf, key_name ? key_name : "undefined"); - _ei_x_encode_string(&send_msg->buf, key_value ? key_value : "undefined"); - _ei_x_encode_string(&send_msg->buf, reply.uuid_str); - - if (params) { - ei_encode_switch_event_headers(&send_msg->buf, params); - } else { - ei_x_encode_empty_list(&send_msg->buf); - } - if (switch_queue_trypush(client->ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send %s XML request to %s <%d.%d.%d>\n" ,section @@ -210,8 +232,6 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con ,fetch_handler->pid.creation ,fetch_handler->pid.num ,fetch_handler->pid.serial); - ei_x_free(&send_msg->buf); - switch_safe_free(send_msg); } else { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sending %s XML request (%s) to %s <%d.%d.%d>\n" ,section @@ -220,11 +240,19 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con ,fetch_handler->pid.creation ,fetch_handler->pid.num ,fetch_handler->pid.serial); + sent = 1; } - fetch_handler = fetch_handler->next; } + if(!sent) { + ei_x_free(&send_msg->buf); + switch_safe_free(send_msg); + } + + if(params == NULL) + switch_event_destroy(&event); + /* wait for a reply (if there isnt already one...amazingly improbable but lets not take shortcuts */ switch_mutex_lock(agent->replies_mutex); @@ -292,6 +320,42 @@ static switch_xml_t fetch_handler(const char *section, const char *tag_name, con return xml; } +void bind_fetch_profile(ei_xml_agent_t *agent, kazoo_config_ptr fetch_handlers) +{ + switch_hash_index_t *hi; + kazoo_fetch_profile_ptr val = NULL, ptr = NULL; + + for (hi = switch_core_hash_first(fetch_handlers->hash); hi; hi = switch_core_hash_next(&hi)) { + switch_core_hash_this(hi, NULL, NULL, (void**) &val); + if (val && val->section == agent->section) { + ptr = val; + break; + } + } + agent->profile = ptr; +} + +void rebind_fetch_profiles(kazoo_config_ptr fetch_handlers) +{ + if(kazoo_globals.config_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.config_fetch_binding), fetch_handlers); + + if(kazoo_globals.directory_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.directory_fetch_binding), fetch_handlers); + + if(kazoo_globals.dialplan_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.dialplan_fetch_binding), fetch_handlers); + + if(kazoo_globals.channels_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.channels_fetch_binding), fetch_handlers); + + if(kazoo_globals.languages_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.languages_fetch_binding), fetch_handlers); + + if(kazoo_globals.chatplan_fetch_binding != NULL) + bind_fetch_profile((ei_xml_agent_t *) switch_xml_get_binding_user_data(kazoo_globals.chatplan_fetch_binding), fetch_handlers); +} + static switch_status_t bind_fetch_agent(switch_xml_section_t section, switch_xml_binding_t **binding) { switch_memory_pool_t *pool = NULL; ei_xml_agent_t *agent; @@ -326,6 +390,8 @@ static switch_status_t bind_fetch_agent(switch_xml_section_t section, switch_xml switch_thread_cond_create(&agent->new_reply, pool); agent->replies = NULL; + bind_fetch_profile(agent, kazoo_globals.fetch_handlers); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Bound to %s XML requests\n" ,xml_section_to_string(section)); @@ -336,6 +402,9 @@ static switch_status_t unbind_fetch_agent(switch_xml_binding_t **binding) { ei_xml_agent_t *agent; ei_xml_client_t *client; + if(*binding == NULL) + return SWITCH_STATUS_GENERR; + /* get a pointer to our user_data */ agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(*binding); @@ -399,6 +468,9 @@ static switch_status_t remove_xml_client(ei_node_t *ei_node, switch_xml_binding_ ei_xml_client_t *client, *prev = NULL; int found = 0; + if(binding == NULL) + return SWITCH_STATUS_GENERR; + agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding); /* write-lock the agent */ @@ -575,8 +647,9 @@ switch_status_t bind_fetch_agents() { bind_fetch_agent(SWITCH_XML_SECTION_CONFIG, &kazoo_globals.config_fetch_binding); bind_fetch_agent(SWITCH_XML_SECTION_DIRECTORY, &kazoo_globals.directory_fetch_binding); bind_fetch_agent(SWITCH_XML_SECTION_DIALPLAN, &kazoo_globals.dialplan_fetch_binding); - bind_fetch_agent(SWITCH_XML_SECTION_CHATPLAN, &kazoo_globals.chatplan_fetch_binding); bind_fetch_agent(SWITCH_XML_SECTION_CHANNELS, &kazoo_globals.channels_fetch_binding); + bind_fetch_agent(SWITCH_XML_SECTION_LANGUAGES, &kazoo_globals.languages_fetch_binding); + bind_fetch_agent(SWITCH_XML_SECTION_CHATPLAN, &kazoo_globals.chatplan_fetch_binding); return SWITCH_STATUS_SUCCESS; } @@ -585,8 +658,9 @@ switch_status_t unbind_fetch_agents() { unbind_fetch_agent(&kazoo_globals.config_fetch_binding); unbind_fetch_agent(&kazoo_globals.directory_fetch_binding); unbind_fetch_agent(&kazoo_globals.dialplan_fetch_binding); - unbind_fetch_agent(&kazoo_globals.chatplan_fetch_binding); unbind_fetch_agent(&kazoo_globals.channels_fetch_binding); + unbind_fetch_agent(&kazoo_globals.languages_fetch_binding); + unbind_fetch_agent(&kazoo_globals.chatplan_fetch_binding); return SWITCH_STATUS_SUCCESS; } @@ -595,8 +669,9 @@ switch_status_t remove_xml_clients(ei_node_t *ei_node) { remove_xml_client(ei_node, kazoo_globals.config_fetch_binding); remove_xml_client(ei_node, kazoo_globals.directory_fetch_binding); remove_xml_client(ei_node, kazoo_globals.dialplan_fetch_binding); - remove_xml_client(ei_node, kazoo_globals.chatplan_fetch_binding); remove_xml_client(ei_node, kazoo_globals.channels_fetch_binding); + remove_xml_client(ei_node, kazoo_globals.languages_fetch_binding); + remove_xml_client(ei_node, kazoo_globals.chatplan_fetch_binding); return SWITCH_STATUS_SUCCESS; } @@ -606,6 +681,9 @@ switch_status_t add_fetch_handler(ei_node_t *ei_node, erlang_pid *from, switch_x ei_xml_client_t *client; fetch_handler_t *fetch_handler; + if(binding == NULL) + return SWITCH_STATUS_GENERR; + agent = (ei_xml_agent_t *)switch_xml_get_binding_user_data(binding); /* write-lock the agent */ @@ -653,8 +731,9 @@ switch_status_t remove_fetch_handlers(ei_node_t *ei_node, erlang_pid *from) { remove_fetch_handler(ei_node, from, kazoo_globals.config_fetch_binding); remove_fetch_handler(ei_node, from, kazoo_globals.directory_fetch_binding); remove_fetch_handler(ei_node, from, kazoo_globals.dialplan_fetch_binding); - remove_fetch_handler(ei_node, from, kazoo_globals.chatplan_fetch_binding); remove_fetch_handler(ei_node, from, kazoo_globals.channels_fetch_binding); + remove_fetch_handler(ei_node, from, kazoo_globals.languages_fetch_binding); + remove_fetch_handler(ei_node, from, kazoo_globals.chatplan_fetch_binding); return SWITCH_STATUS_SUCCESS; } @@ -689,8 +768,9 @@ switch_status_t handle_api_command_streams(ei_node_t *ei_node, switch_stream_han handle_api_command_stream(ei_node, stream, kazoo_globals.config_fetch_binding); handle_api_command_stream(ei_node, stream, kazoo_globals.directory_fetch_binding); handle_api_command_stream(ei_node, stream, kazoo_globals.dialplan_fetch_binding); - handle_api_command_stream(ei_node, stream, kazoo_globals.chatplan_fetch_binding); handle_api_command_stream(ei_node, stream, kazoo_globals.channels_fetch_binding); + handle_api_command_stream(ei_node, stream, kazoo_globals.languages_fetch_binding); + handle_api_command_stream(ei_node, stream, kazoo_globals.chatplan_fetch_binding); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_fields.h b/src/mod/event_handlers/mod_kazoo/kazoo_fields.h new file mode 100644 index 0000000000..6c8111bfe4 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_fields.h @@ -0,0 +1,197 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#ifndef KAZOO_FIELDS_H +#define KAZOO_FIELDS_H + +#include + +#define MAX_LIST_FIELDS 25 + +typedef struct kazoo_log_levels kazoo_loglevels_t; +typedef kazoo_loglevels_t *kazoo_loglevels_ptr; + +struct kazoo_log_levels +{ + switch_log_level_t success_log_level; + switch_log_level_t failed_log_level; + switch_log_level_t warn_log_level; + switch_log_level_t info_log_level; + switch_log_level_t time_log_level; + switch_log_level_t filtered_event_log_level; + switch_log_level_t filtered_field_log_level; + +}; + +typedef struct kazoo_logging kazoo_logging_t; +typedef kazoo_logging_t *kazoo_logging_ptr; + +struct kazoo_logging +{ + kazoo_loglevels_ptr levels; + const char *profile_name; + const char *event_name; +}; + +typedef struct kazoo_list_s { + char *value[MAX_LIST_FIELDS]; + int size; +} kazoo_list_t; + +typedef enum { + FILTER_COMPARE_REGEX, + FILTER_COMPARE_LIST, + FILTER_COMPARE_VALUE, + FILTER_COMPARE_PREFIX, + FILTER_COMPARE_EXISTS, + FILTER_COMPARE_FIELD + +} kazoo_filter_compare_type; + +typedef enum { + FILTER_EXCLUDE, + FILTER_INCLUDE, + FILTER_ENSURE +} kazoo_filter_type; + +typedef struct kazoo_filter_t { + kazoo_filter_type type; + kazoo_filter_compare_type compare; + char* name; + char* value; + kazoo_list_t list; + struct kazoo_filter_t* next; +} kazoo_filter, *kazoo_filter_ptr; + + +typedef enum { + JSON_NONE, + JSON_STRING, + JSON_NUMBER, + JSON_BOOLEAN, + JSON_OBJECT, + JSON_RAW +} kazoo_json_field_type; + +typedef enum { + FIELD_NONE, + FIELD_COPY, + FIELD_STATIC, + FIELD_FIRST_OF, + FIELD_EXPAND, + FIELD_PREFIX, + FIELD_OBJECT, + FIELD_GROUP, + FIELD_REFERENCE + +} kazoo_field_type; + +typedef struct kazoo_field_t kazoo_field; +typedef kazoo_field *kazoo_field_ptr; + +typedef struct kazoo_fields_t kazoo_fields; +typedef kazoo_fields *kazoo_fields_ptr; + +typedef struct kazoo_definition_t kazoo_definition; +typedef kazoo_definition *kazoo_definition_ptr; + +struct kazoo_field_t { + char* name; + char* value; + char* as; + kazoo_list_t list; + switch_bool_t exclude_prefix; + kazoo_field_type in_type; + kazoo_json_field_type out_type; + kazoo_filter_ptr filter; + + kazoo_definition_ptr ref; + kazoo_field_ptr next; + kazoo_fields_ptr children; +}; + +struct kazoo_fields_t { + kazoo_field_ptr head; + int verbose; +}; + + +struct kazoo_definition_t { + char* name; + kazoo_field_ptr head; + kazoo_filter_ptr filter; +}; + +struct kazoo_event { + kazoo_event_profile_ptr profile; + char *name; + kazoo_fields_ptr fields; + kazoo_filter_ptr filter; + + kazoo_event_t* next; +}; + +struct kazoo_event_profile { + char *name; + kazoo_config_ptr root; + switch_bool_t running; + switch_memory_pool_t *pool; + kazoo_filter_ptr filter; + kazoo_fields_ptr fields; + kazoo_event_ptr events; + + kazoo_loglevels_ptr logging; +}; + +struct kazoo_fetch_profile { + char *name; + kazoo_config_ptr root; + switch_bool_t running; + switch_memory_pool_t *pool; + kazoo_fields_ptr fields; + int fetch_timeout; + switch_mutex_t *fetch_reply_mutex; + switch_hash_t *fetch_reply_hash; + switch_xml_binding_t *fetch_binding; + switch_xml_section_t section; + + kazoo_loglevels_ptr logging; +}; + +#endif /* KAZOO_FIELDS_H */ + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_message.c b/src/mod/event_handlers/mod_kazoo/kazoo_message.c new file mode 100644 index 0000000000..74ddff6647 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_message.c @@ -0,0 +1,436 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#include "mod_kazoo.h" + +/* deletes then add */ +void kazoo_cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item) +{ + cJSON_DeleteItemFromObject(object, string); + cJSON_AddItemToObject(object, string, item); +} + +static int inline filter_compare(switch_event_t* evt, kazoo_filter_ptr filter) +{ + switch_event_header_t *header; + int hasValue = 0, n; + char *value = NULL, *expr = NULL; + + switch(filter->compare) { + + case FILTER_COMPARE_EXISTS: + hasValue = switch_event_get_header(evt, filter->name) != NULL ? 1 : 0; + break; + + case FILTER_COMPARE_VALUE: + if (*filter->name == '$') { + value = expr = kz_event_expand_headers(evt, filter->name); + } else { + value = switch_event_get_header(evt, filter->name); + } + hasValue = value ? !strcmp(value, filter->value) : 0; + break; + + case FILTER_COMPARE_FIELD: + if (*filter->name == '$') { + value = expr = kz_event_expand_headers(evt, filter->name); + } else { + value = switch_event_get_header(evt, filter->name); + } + hasValue = value ? !strcmp(value, switch_event_get_header_nil(evt, filter->value)) : 0; + break; + + case FILTER_COMPARE_PREFIX: + for (header = evt->headers; header; header = header->next) { + if(!strncmp(header->name, filter->value, strlen(filter->value))) { + hasValue = 1; + break; + } + } + break; + + case FILTER_COMPARE_LIST: + if (*filter->name == '$') { + value = expr = kz_event_expand_headers(evt, filter->name); + } else { + value = switch_event_get_header(evt, filter->name); + } + if(value) { + for(n = 0; n < filter->list.size; n++) { + if(!strncmp(value, filter->list.value[n], strlen(filter->list.value[n]))) { + hasValue = 1; + break; + } + } + } + break; + + case FILTER_COMPARE_REGEX: + break; + + default: + break; + } + + switch_safe_free(expr); + + return hasValue; +} + +static kazoo_filter_ptr inline filter_event(switch_event_t* evt, kazoo_filter_ptr filter) +{ + while(filter) { + int hasValue = filter_compare(evt, filter); + if(filter->type == FILTER_EXCLUDE) { + if(hasValue) + break; + } else if(filter->type == FILTER_INCLUDE) { + if(!hasValue) + break; + } + filter = filter->next; + } + return filter; +} + +static void kazoo_event_init_json_fields(switch_event_t *event, cJSON *json) +{ + switch_event_header_t *hp; + for (hp = event->headers; hp; hp = hp->next) { + if (hp->idx) { + cJSON *a = cJSON_CreateArray(); + int i; + + for(i = 0; i < hp->idx; i++) { + cJSON_AddItemToArray(a, cJSON_CreateString(hp->array[i])); + } + + cJSON_AddItemToObject(json, hp->name, a); + + } else { + cJSON_AddItemToObject(json, hp->name, cJSON_CreateString(hp->value)); + } + } +} + +static switch_status_t kazoo_event_init_json(kazoo_fields_ptr fields1, kazoo_fields_ptr fields2, switch_event_t* evt, cJSON** clone) +{ + switch_status_t status; + if( (fields2 && fields2->verbose) + || (fields1 && fields1->verbose) + || ( (!fields2) && (!fields1)) ) { + status = switch_event_serialize_json_obj(evt, clone); + } else { + status = SWITCH_STATUS_SUCCESS; + *clone = cJSON_CreateObject(); + if((*clone) == NULL) { + status = SWITCH_STATUS_GENERR; + } + } + return status; +} + +static cJSON * kazoo_event_json_value(kazoo_json_field_type type, const char *value) { + cJSON *item = NULL; + switch(type) { + case JSON_STRING: + item = cJSON_CreateString(value); + break; + + case JSON_NUMBER: + item = cJSON_CreateNumber(strtod(value, NULL)); + break; + + case JSON_BOOLEAN: + item = cJSON_CreateBool(switch_true(value)); + break; + + case JSON_OBJECT: + item = cJSON_CreateObject(); + break; + + case JSON_RAW: + item = cJSON_CreateRaw(value); + break; + + default: + break; + }; + + return item; +} + +static cJSON * kazoo_event_add_json_value(cJSON *dst, kazoo_field_ptr field, const char *as, const char *value) { + cJSON *item = NULL; + if(value || field->out_type == JSON_OBJECT) { + if((item = kazoo_event_json_value(field->out_type, value)) != NULL) { + kazoo_cJSON_AddItemToObject(dst, as, item); + } + } + return item; +} + + +cJSON * kazoo_event_add_field_to_json(cJSON *dst, switch_event_t *src, kazoo_field_ptr field) +{ + switch_event_header_t *header; + char *expanded; + uint i, n; + cJSON *item = NULL; + + switch(field->in_type) { + case FIELD_COPY: + if((header = switch_event_get_header_ptr(src, field->name)) != NULL) { + if (header->idx) { + item = cJSON_CreateArray(); + for(i = 0; i < header->idx; i++) { + cJSON_AddItemToArray(item, kazoo_event_json_value(field->out_type, header->array[i])); + } + kazoo_cJSON_AddItemToObject(dst, field->as ? field->as : field->name, item); + } else { + item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, header->value); + } + } + break; + + case FIELD_EXPAND: + expanded = kz_event_expand_headers(src, field->value); + if(expanded != NULL && !zstr(expanded)) { + item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, expanded); + free(expanded); + } + break; + + case FIELD_FIRST_OF: + for(n = 0; n < field->list.size; n++) { + if(*field->list.value[n] == '#') { + item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, ++field->list.value[n]); + break; + } else { + header = switch_event_get_header_ptr(src, field->list.value[n]); + if(header) { + if (header->idx) { + item = cJSON_CreateArray(); + for(i = 0; i < header->idx; i++) { + cJSON_AddItemToArray(item, kazoo_event_json_value(field->out_type, header->array[i])); + } + kazoo_cJSON_AddItemToObject(dst, field->as ? field->as : field->name, item); + } else { + item = kazoo_event_add_json_value(dst, field, field->as ? field->as : field->name, header->value); + } + break; + } + } + } + break; + + case FIELD_PREFIX: + for (header = src->headers; header; header = header->next) { + if(!strncmp(header->name, field->name, strlen(field->name))) { + if (header->idx) { + cJSON *array = cJSON_CreateArray(); + for(i = 0; i < header->idx; i++) { + cJSON_AddItemToArray(array, kazoo_event_json_value(field->out_type, header->array[i])); + } + kazoo_cJSON_AddItemToObject(dst, field->exclude_prefix ? header->name+strlen(field->name) : header->name, array); + } else { + kazoo_event_add_json_value(dst, field, field->exclude_prefix ? header->name+strlen(field->name) : header->name, header->value); + } + } + } + break; + + case FIELD_STATIC: + item = kazoo_event_add_json_value(dst, field, field->name, field->value); + break; + + case FIELD_GROUP: + item = dst; + break; + + default: + break; + } + + return item; +} + +static switch_status_t kazoo_event_add_fields_to_json(kazoo_logging_ptr logging, cJSON *dst, switch_event_t *src, kazoo_field_ptr field) { + + kazoo_filter_ptr filter; + cJSON *item = NULL; + while(field) { + if(field->in_type == FIELD_REFERENCE) { + if(field->ref) { + if((filter = filter_event(src, field->ref->filter)) != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->filtered_field_log_level, "profile[%s] event %s, referenced field %s filtered by settings %s : %s\n", logging->profile_name, logging->event_name, field->ref->name, filter->name, filter->value); + } else { + kazoo_event_add_fields_to_json(logging, dst, src, field->ref->head); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "profile[%s] event %s, referenced field %s not found\n", logging->profile_name, logging->event_name, field->name); + } + } else { + if((filter = filter_event(src, field->filter)) != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, logging->levels->filtered_field_log_level, "profile[%s] event %s, field %s filtered by settings %s : %s\n", logging->profile_name, logging->event_name, field->name, filter->name, filter->value); + } else { + item = kazoo_event_add_field_to_json(dst, src, field); + if(field->children && item != NULL) { + if(field->children->verbose && field->out_type == JSON_OBJECT) { + kazoo_event_init_json_fields(src, item); + } + kazoo_event_add_fields_to_json(logging, field->out_type == JSON_OBJECT ? item : dst, src, field->children->head); + } + } + } + + field = field->next; + } + + return SWITCH_STATUS_SUCCESS; +} + + +kazoo_message_ptr kazoo_message_create_event(switch_event_t* evt, kazoo_event_ptr event, kazoo_event_profile_ptr profile) +{ + kazoo_message_ptr message; + cJSON *JObj = NULL; + kazoo_filter_ptr filtered; + kazoo_logging_t logging; + + logging.levels = profile->logging; + logging.event_name = switch_event_get_header_nil(evt, "Event-Name"); + logging.profile_name = profile->name; + + switch_event_add_header_string(evt, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename); + + + message = malloc(sizeof(kazoo_message_t)); + if(message == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocating memory for serializing event to json\n"); + return NULL; + } + memset(message, 0, sizeof(kazoo_message_t)); + + if(profile->filter) { + // filtering + if((filtered = filter_event(evt, profile->filter)) != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, logging.levels->filtered_event_log_level, "profile[%s] event %s filtered by profile settings %s : %s\n", logging.profile_name, logging.event_name, filtered->name, filtered->value); + kazoo_message_destroy(&message); + return NULL; + } + } + + if(event && event->filter) { + if((filtered = filter_event(evt, event->filter)) != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, logging.levels->filtered_event_log_level, "profile[%s] event %s filtered by event settings %s : %s\n", logging.profile_name, logging.event_name, filtered->name, filtered->value); + kazoo_message_destroy(&message); + return NULL; + } + } + + kazoo_event_init_json(profile->fields, event ? event->fields : NULL, evt, &JObj); + + if(profile->fields) + kazoo_event_add_fields_to_json(&logging, JObj, evt, profile->fields->head); + + if(event && event->fields) + kazoo_event_add_fields_to_json(&logging, JObj, evt, event->fields->head); + + message->JObj = JObj; + + + return message; + + +} + +kazoo_message_ptr kazoo_message_create_fetch(switch_event_t* evt, kazoo_fetch_profile_ptr profile) +{ + kazoo_message_ptr message; + cJSON *JObj = NULL; + kazoo_logging_t logging; + + logging.levels = profile->logging; + logging.event_name = switch_event_get_header_nil(evt, "Event-Name"); + logging.profile_name = profile->name; + + switch_event_add_header_string(evt, SWITCH_STACK_BOTTOM, "Switch-Nodename", kazoo_globals.ei_cnode.thisnodename); + + message = malloc(sizeof(kazoo_message_t)); + if(message == NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "error allocating memory for serializing event to json\n"); + return NULL; + } + memset(message, 0, sizeof(kazoo_message_t)); + + + kazoo_event_init_json(profile->fields, NULL, evt, &JObj); + + if(profile->fields) + kazoo_event_add_fields_to_json(&logging, JObj, evt, profile->fields->head); + + message->JObj = JObj; + + + return message; + + +} + + +void kazoo_message_destroy(kazoo_message_ptr *msg) +{ + if (!msg || !*msg) return; + if((*msg)->JObj != NULL) + cJSON_Delete((*msg)->JObj); + switch_safe_free(*msg); + +} + + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 + */ diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_message.h b/src/mod/event_handlers/mod_kazoo/kazoo_message.h new file mode 100644 index 0000000000..eade6c4e7b --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_message.h @@ -0,0 +1,66 @@ +/* +* FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* Copyright (C) 2005-2012, Anthony Minessale II +* +* Version: MPL 1.1 +* +* The contents of this file are subject to the Mozilla Public License Version +* 1.1 (the "License"); you may not use this file except in compliance with +* the License. You may obtain a copy of the License at +* http://www.mozilla.org/MPL/ +* +* Software distributed under the License is distributed on an "AS IS" basis, +* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License +* for the specific language governing rights and limitations under the +* License. +* +* The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application +* +* The Initial Developer of the Original Code is +* Anthony Minessale II +* Portions created by the Initial Developer are Copyright (C) +* the Initial Developer. All Rights Reserved. +* +* Based on mod_skel by +* Anthony Minessale II +* +* Contributor(s): +* +* Daniel Bryars +* Tim Brown +* Anthony Minessale II +* William King +* Mike Jerris +* +* kazoo.c -- Sends FreeSWITCH events to an AMQP broker +* +*/ + +#ifndef KAZOO_MESSAGE_H +#define KAZOO_MESSAGE_H + +#include + +typedef struct { + uint64_t timestamp; + uint64_t start; + uint64_t filter; + uint64_t serialize; + uint64_t print; + uint64_t rk; +} kazoo_message_times_t, *kazoo_message_times_ptr; + +typedef struct { + cJSON *JObj; +} kazoo_message_t, *kazoo_message_ptr; + +void kazoo_cJSON_AddItemToObject(cJSON *object, const char *string, cJSON *item); +cJSON * kazoo_event_add_field_to_json(cJSON *dst, switch_event_t *src, kazoo_field_ptr field); +kazoo_message_ptr kazoo_message_create_event(switch_event_t* evt, kazoo_event_ptr event, kazoo_event_profile_ptr profile); +kazoo_message_ptr kazoo_message_create_fetch(switch_event_t* evt, kazoo_fetch_profile_ptr profile); + +void kazoo_message_destroy(kazoo_message_ptr *msg); + + +#endif /* KAZOO_MESSAGE_H */ + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_node.c b/src/mod/event_handlers/mod_kazoo/kazoo_node.c index 17da6dc582..a92fe49aa2 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_node.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_node.c @@ -53,6 +53,8 @@ static char *REQUEST_ATOMS[] = { "nixevent", "sendevent", "sendmsg", + "commands", + "command", "bind", "getpid", "version", @@ -62,7 +64,8 @@ static char *REQUEST_ATOMS[] = { "fetch_reply", "config", "bgapi4", - "api4" + "api4", + "json_api" }; typedef enum { @@ -72,6 +75,8 @@ typedef enum { REQUEST_NIXEVENT, REQUEST_SENDEVENT, REQUEST_SENDMSG, + REQUEST_COMMANDS, + REQUEST_COMMAND, REQUEST_BIND, REQUEST_GETPID, REQUEST_VERSION, @@ -82,11 +87,13 @@ typedef enum { REQUEST_CONFIG, REQUEST_BGAPI4, REQUEST_API4, + REQUEST_JSON_API, REQUEST_MAX } request_atoms_t; static switch_status_t find_request(char *atom, int *request) { - for (int i = 0; i < REQUEST_MAX; i++) { + int i; + for (i = 0; i < REQUEST_MAX; i++) { if(!strncmp(atom, REQUEST_ATOMS[i], MAXATOMLEN)) { *request = i; return SWITCH_STATUS_SUCCESS; @@ -200,14 +207,21 @@ SWITCH_DECLARE(switch_status_t) kazoo_api_execute(const char *cmd, const char *a char *arg_used; char *cmd_used; int fire_event = 0; + char *arg_expanded; + switch_event_t* evt; switch_assert(stream != NULL); switch_assert(stream->data != NULL); switch_assert(stream->write_function != NULL); - cmd_used = (char *) cmd; - arg_used = (char *) arg; + arg_expanded = (char *) arg; + switch_event_create(&evt, SWITCH_EVENT_GENERAL); + arg_expanded = switch_event_expand_headers(evt, arg); + switch_event_destroy(&evt); + + cmd_used = (char *) cmd; + arg_used = arg_expanded; if (!stream->param_event) { switch_event_create(&stream->param_event, SWITCH_EVENT_API); @@ -221,6 +235,9 @@ SWITCH_DECLARE(switch_status_t) kazoo_api_execute(const char *cmd, const char *a if (arg_used && *arg_used) { switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument", arg_used); } + if (arg_expanded && *arg_expanded) { + switch_event_add_header_string(stream->param_event, SWITCH_STACK_BOTTOM, "API-Command-Argument-Expanded", arg_expanded); + } } @@ -247,10 +264,14 @@ SWITCH_DECLARE(switch_status_t) kazoo_api_execute(const char *cmd, const char *a switch_safe_free(cmd_used); } - if (arg_used != arg) { + if (arg_used != arg_expanded) { switch_safe_free(arg_used); } + if (arg_expanded != arg) { + switch_safe_free(arg_expanded); + } + return status; } @@ -267,7 +288,7 @@ static switch_status_t api_exec_stream(char *cmd, char *arg, switch_stream_handl } } else if (!stream->data || !strlen(stream->data)) { *reply = switch_mprintf("%s: Command returned no output", cmd); - status = SWITCH_STATUS_FALSE; + status = SWITCH_STATUS_SUCCESS; } else { *reply = strdup(stream->data); status = SWITCH_STATUS_SUCCESS; @@ -357,14 +378,13 @@ static void *SWITCH_THREAD_FUNC bgapi4_exec(switch_thread_t *thread, void *obj) return NULL; } - SWITCH_STANDARD_STREAM(stream); + SWITCH_STANDARD_STREAM(stream); switch_event_create(&stream.param_event, SWITCH_EVENT_API); - switch_malloc(send_msg, sizeof(*send_msg)); - memcpy(&send_msg->pid, &acs->pid, sizeof(erlang_pid)); + switch_malloc(send_msg, sizeof(*send_msg)); + memcpy(&send_msg->pid, &acs->pid, sizeof(erlang_pid)); ei_x_new_with_version(&send_msg->buf); - ei_x_encode_tuple_header(&send_msg->buf, (stream.param_event ? 4 : 3)); if (api_exec_stream(cmd, arg, &stream, &reply) == SWITCH_STATUS_SUCCESS) { @@ -376,9 +396,9 @@ static void *SWITCH_THREAD_FUNC bgapi4_exec(switch_thread_t *thread, void *obj) _ei_x_encode_string(&send_msg->buf, acs->uuid_str); _ei_x_encode_string(&send_msg->buf, reply); - if (stream.param_event) { + if (stream.param_event) { ei_encode_switch_event_headers_2(&send_msg->buf, stream.param_event, 0); - } + } if (switch_queue_trypush(ei_node->send_msgs, send_msg) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to send bgapi response %s to %s <%d.%d.%d>\n" @@ -393,9 +413,9 @@ static void *SWITCH_THREAD_FUNC bgapi4_exec(switch_thread_t *thread, void *obj) switch_atomic_dec(&ei_node->pending_bgapi); - if (stream.param_event) { - switch_event_fire(&stream.param_event); - } + if (stream.param_event) { + switch_event_fire(&stream.param_event); + } switch_safe_free(reply); switch_safe_free(acs->arg); @@ -412,11 +432,10 @@ static void log_sendmsg_request(char *uuid, switch_event_t *event) switch_ssize_t hlen = -1; unsigned long CMD_EXECUTE = switch_hashfunc_default("execute", &hlen); unsigned long CMD_XFEREXT = switch_hashfunc_default("xferext", &hlen); - // unsigned long CMD_HANGUP = switch_hashfunc_default("hangup", &hlen); - // unsigned long CMD_NOMEDIA = switch_hashfunc_default("nomedia", &hlen); - // unsigned long CMD_UNICAST = switch_hashfunc_default("unicast", &hlen); if (zstr(cmd)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "log|%s|invalid \n", uuid); + DUMP_EVENT(event); return; } @@ -453,6 +472,7 @@ static void log_sendmsg_request(char *uuid, switch_event_t *event) static switch_status_t build_event(switch_event_t *event, ei_x_buff * buf) { int propslist_length, arity; + int n=0; if(!event) { return SWITCH_STATUS_FALSE; @@ -462,7 +482,7 @@ static switch_status_t build_event(switch_event_t *event, ei_x_buff * buf) { return SWITCH_STATUS_FALSE; } - while (!ei_decode_tuple_header(buf->buff, &buf->index, &arity)) { + while (!ei_decode_tuple_header(buf->buff, &buf->index, &arity) && n < propslist_length) { char key[1024]; char *value; @@ -482,9 +502,21 @@ static switch_status_t build_event(switch_event_t *event, ei_x_buff * buf) { switch_safe_free(event->body); event->body = value; } else { + if(!strcasecmp(key, "Call-ID")) { + switch_core_session_t *session = NULL; + if(!zstr(value)) { + if ((session = switch_core_session_force_locate(value)) != NULL) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_event_set_data(channel, event); + switch_core_session_rwunlock(session); + } + } + } switch_event_add_header_string(event, SWITCH_STACK_BOTTOM | SWITCH_STACK_NODUP, key, value); } + n++; } + ei_skip_term(buf->buff, &buf->index); return SWITCH_STATUS_SUCCESS; } @@ -525,6 +557,16 @@ static switch_status_t erlang_response_ok(ei_x_buff *rbuf) { return SWITCH_STATUS_SUCCESS; } +static switch_status_t erlang_response_ok_uuid(ei_x_buff *rbuf, const char * uuid) { + if (rbuf) { + ei_x_encode_tuple_header(rbuf, 2); + ei_x_encode_atom(rbuf, "ok"); + ei_x_encode_binary(rbuf, uuid, strlen(uuid)); + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t handle_request_noevents(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { ei_event_stream_t *event_stream; @@ -554,6 +596,7 @@ static switch_status_t handle_request_nixevent(ei_node_t *ei_node, erlang_pid *p switch_event_types_t event_type; ei_event_stream_t *event_stream; int custom = 0, length = 0; + int i; if (ei_decode_list_header(buf->buff, &buf->index, &length) || length == 0) { @@ -566,7 +609,7 @@ static switch_status_t handle_request_nixevent(ei_node_t *ei_node, erlang_pid *p return erlang_response_ok(rbuf); } - for (int i = 1; i <= length; i++) { + for (i = 1; i <= length; i++) { if (ei_decode_atom_safe(buf->buff, &buf->index, event_name)) { switch_mutex_unlock(ei_node->event_streams_mutex); return erlang_response_badarg(rbuf); @@ -576,16 +619,22 @@ static switch_status_t handle_request_nixevent(ei_node_t *ei_node, erlang_pid *p remove_event_binding(event_stream, SWITCH_EVENT_CUSTOM, event_name); } else if (switch_name_event(event_name, &event_type) == SWITCH_STATUS_SUCCESS) { switch (event_type) { + case SWITCH_EVENT_CUSTOM: custom++; break; + case SWITCH_EVENT_ALL: - for (switch_event_types_t type = 0; type < SWITCH_EVENT_ALL; type++) { + { + switch_event_types_t type; + for (type = 0; type < SWITCH_EVENT_ALL; type++) { if(type != SWITCH_EVENT_CUSTOM) { remove_event_binding(event_stream, type, NULL); } } break; + } + default: remove_event_binding(event_stream, event_type, NULL); } @@ -632,6 +681,83 @@ static switch_status_t handle_request_sendevent(ei_node_t *ei_node, erlang_pid * return erlang_response_badarg(rbuf); } +static switch_status_t handle_request_command(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { + switch_core_session_t *session; + switch_event_t *event = NULL; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + switch_uuid_t cmd_uuid; + char cmd_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + + if (ei_decode_string_or_binary_limited(buf->buff, &buf->index, sizeof(uuid_str), uuid_str)) { + return erlang_response_badarg(rbuf); + } + + switch_uuid_get(&cmd_uuid); + switch_uuid_format(cmd_uuid_str, &cmd_uuid); + + switch_event_create(&event, SWITCH_EVENT_COMMAND); + if (build_event(event, buf) != SWITCH_STATUS_SUCCESS) { + return erlang_response_badarg(rbuf); + } + + log_sendmsg_request(uuid_str, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event-uuid", cmd_uuid_str); + + if (zstr_buf(uuid_str) || !(session = switch_core_session_locate(uuid_str))) { + return erlang_response_baduuid(rbuf); + } + switch_core_session_queue_private_event(session, &event, SWITCH_FALSE); + switch_core_session_rwunlock(session); + + return erlang_response_ok_uuid(rbuf, cmd_uuid_str); +} + +static switch_status_t handle_request_commands(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { + switch_core_session_t *session; + char uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + int propslist_length, n; + switch_uuid_t cmd_uuid; + char cmd_uuid_str[SWITCH_UUID_FORMATTED_LENGTH + 1]; + + if (ei_decode_string_or_binary_limited(buf->buff, &buf->index, sizeof(uuid_str), uuid_str)) { + return erlang_response_badarg(rbuf); + } + + if (zstr_buf(uuid_str) || !(session = switch_core_session_locate(uuid_str))) { + return erlang_response_baduuid(rbuf); + } + + switch_uuid_get(&cmd_uuid); + switch_uuid_format(cmd_uuid_str, &cmd_uuid); + + if (ei_decode_list_header(buf->buff, &buf->index, &propslist_length)) { + switch_core_session_rwunlock(session); + return SWITCH_STATUS_FALSE; + } + + for(n = 0; n < propslist_length; n++) { + switch_event_t *event = NULL; + switch_event_create(&event, SWITCH_EVENT_COMMAND); + if (build_event(event, buf) != SWITCH_STATUS_SUCCESS) { + switch_core_session_rwunlock(session); + return erlang_response_badarg(rbuf); + } + log_sendmsg_request(uuid_str, event); + if(n == (propslist_length - 1)) { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event-uuid", cmd_uuid_str); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "event-uuid", "null"); +// switch_event_del_header_val(event, "event-uuid-name", NULL); + } + switch_core_session_queue_private_event(session, &event, SWITCH_FALSE); + } + + switch_core_session_rwunlock(session); + + return erlang_response_ok_uuid(rbuf, cmd_uuid_str); + +} + static switch_status_t handle_request_sendmsg(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { switch_core_session_t *session; switch_event_t *event = NULL; @@ -659,8 +785,8 @@ static switch_status_t handle_request_sendmsg(ei_node_t *ei_node, erlang_pid *pi static switch_status_t handle_request_config(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { - fetch_config_filters(); - return erlang_response_ok(rbuf); + fetch_config(); + return erlang_response_ok(rbuf); } static switch_status_t handle_request_bind(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { @@ -675,8 +801,10 @@ static switch_status_t handle_request_bind(ei_node_t *ei_node, erlang_pid *pid, switch(section) { case SWITCH_XML_SECTION_CONFIG: add_fetch_handler(ei_node, pid, kazoo_globals.config_fetch_binding); - if(!kazoo_globals.config_filters_fetched) - fetch_config_filters(); + if(!kazoo_globals.config_fetched) { + kazoo_globals.config_fetched = 1; + fetch_config(); + } break; case SWITCH_XML_SECTION_DIRECTORY: add_fetch_handler(ei_node, pid, kazoo_globals.directory_fetch_binding); @@ -684,12 +812,15 @@ static switch_status_t handle_request_bind(ei_node_t *ei_node, erlang_pid *pid, case SWITCH_XML_SECTION_DIALPLAN: add_fetch_handler(ei_node, pid, kazoo_globals.dialplan_fetch_binding); break; - case SWITCH_XML_SECTION_CHATPLAN: - add_fetch_handler(ei_node, pid, kazoo_globals.chatplan_fetch_binding); - break; case SWITCH_XML_SECTION_CHANNELS: add_fetch_handler(ei_node, pid, kazoo_globals.channels_fetch_binding); break; + case SWITCH_XML_SECTION_LANGUAGES: + add_fetch_handler(ei_node, pid, kazoo_globals.languages_fetch_binding); + break; + case SWITCH_XML_SECTION_CHATPLAN: + add_fetch_handler(ei_node, pid, kazoo_globals.chatplan_fetch_binding); + break; default: return erlang_response_badarg(rbuf); } @@ -796,10 +927,10 @@ static switch_status_t handle_request_api4(ei_node_t *ei_node, erlang_pid *pid, status = api_exec_stream(cmd, arg, &stream, &reply); if (status == SWITCH_STATUS_SUCCESS) { - ei_x_encode_tuple_header(buf, 2); + ei_x_encode_tuple_header(rbuf, 2); ei_x_encode_atom(rbuf, "ok"); } else { - ei_x_encode_tuple_header(buf, (stream.param_event ? 3 : 2)); + ei_x_encode_tuple_header(rbuf, (stream.param_event ? 3 : 2)); ei_x_encode_atom(rbuf, "error"); } @@ -822,6 +953,61 @@ static switch_status_t handle_request_api4(ei_node_t *ei_node, erlang_pid *pid, return SWITCH_STATUS_SUCCESS; } +static switch_status_t handle_request_json_api(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) +{ + char *arg; + cJSON *jcmd = NULL; + switch_core_session_t *session = NULL; + const char *uuid = NULL; + char *response = NULL; + const char *parse_end = NULL; + switch_status_t status = SWITCH_STATUS_SUCCESS; + + if (ei_decode_string_or_binary(buf->buff, &buf->index, &arg)) { + return erlang_response_badarg(rbuf); + } + + jcmd = cJSON_ParseWithOpts(arg, &parse_end, 0); + + if (!jcmd) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "json api error: %s\n", parse_end); + ei_x_encode_tuple_header(rbuf, 2); + ei_x_encode_atom(rbuf, "error"); + ei_x_encode_tuple_header(rbuf, 2); + ei_x_encode_atom(rbuf, "parse_error"); + _ei_x_encode_string(rbuf, parse_end); + return status; + } + + if ((uuid = cJSON_GetObjectCstr(jcmd, "uuid"))) { + if (!(session = switch_core_session_locate(uuid))) { + return erlang_response_baduuid(rbuf); + } + } + + status = switch_json_api_execute(jcmd, session, NULL); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "json api (%i): %s\n", status , arg); + + response = cJSON_PrintUnformatted(jcmd); + ei_x_encode_tuple_header(rbuf, 2); + if (status == SWITCH_STATUS_SUCCESS) { + ei_x_encode_atom(rbuf, "ok"); + } else { + ei_x_encode_atom(rbuf, "error"); + } + _ei_x_encode_string(rbuf, response); + switch_safe_free(response); + + cJSON_Delete(jcmd); + switch_safe_free(arg); + + if (session) { + switch_core_session_rwunlock(session); + } + + return SWITCH_STATUS_SUCCESS; +} + static switch_status_t handle_request_api(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { char cmd[MAXATOMLEN + 1]; char *arg; @@ -834,7 +1020,7 @@ static switch_status_t handle_request_api(ei_node_t *ei_node, erlang_pid *pid, e return erlang_response_badarg(rbuf); } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "exec: %s(%s)\n", cmd, arg); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "exec: %s(%s)\n", cmd, arg); if (rbuf) { char *reply; @@ -858,9 +1044,9 @@ static switch_status_t handle_request_api(ei_node_t *ei_node, erlang_pid *pid, e static switch_status_t handle_request_event(ei_node_t *ei_node, erlang_pid *pid, ei_x_buff *buf, ei_x_buff *rbuf) { char event_name[MAXATOMLEN + 1]; - switch_event_types_t event_type; ei_event_stream_t *event_stream; - int custom = 0, length = 0; + int length = 0; + int i; if (ei_decode_list_header(buf->buff, &buf->index, &length) || !length) { return erlang_response_badarg(rbuf); @@ -868,38 +1054,18 @@ static switch_status_t handle_request_event(ei_node_t *ei_node, erlang_pid *pid, switch_mutex_lock(ei_node->event_streams_mutex); if (!(event_stream = find_event_stream(ei_node->event_streams, pid))) { - event_stream = new_event_stream(&ei_node->event_streams, pid); + event_stream = new_event_stream(ei_node, pid); /* ensure we are notified if the requesting processes dies so we can clean up */ ei_link(ei_node, ei_self(&kazoo_globals.ei_cnode), pid); } - for (int i = 1; i <= length; i++) { + for (i = 1; i <= length; i++) { + if (ei_decode_atom_safe(buf->buff, &buf->index, event_name)) { switch_mutex_unlock(ei_node->event_streams_mutex); return erlang_response_badarg(rbuf); } - - if (custom) { - add_event_binding(event_stream, SWITCH_EVENT_CUSTOM, event_name); - } else if (switch_name_event(event_name, &event_type) == SWITCH_STATUS_SUCCESS) { - switch (event_type) { - case SWITCH_EVENT_CUSTOM: - custom++; - break; - case SWITCH_EVENT_ALL: - for (switch_event_types_t type = 0; type < SWITCH_EVENT_ALL; type++) { - if(type != SWITCH_EVENT_CUSTOM) { - add_event_binding(event_stream, type, NULL); - } - } - break; - default: - add_event_binding(event_stream, event_type, NULL); - } - } else { - switch_mutex_unlock(ei_node->event_streams_mutex); - return erlang_response_badarg(rbuf); - } + add_event_binding(event_stream, event_name); } switch_mutex_unlock(ei_node->event_streams_mutex); @@ -935,13 +1101,13 @@ static switch_status_t handle_request_fetch_reply(ei_node_t *ei_node, erlang_pid } if (ei_decode_string_or_binary(buf->buff, &buf->index, &xml_str)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ignoring a fetch reply without XML\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ignoring a fetch reply without XML : %s \n", uuid_str); return erlang_response_badarg(rbuf); } if (zstr(xml_str)) { switch_safe_free(xml_str); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ignoring an empty fetch reply\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Ignoring an empty fetch reply : %s\n", uuid_str); return erlang_response_badarg(rbuf); } @@ -955,21 +1121,24 @@ static switch_status_t handle_request_fetch_reply(ei_node_t *ei_node, erlang_pid case SWITCH_XML_SECTION_DIALPLAN: result = fetch_reply(uuid_str, xml_str, kazoo_globals.dialplan_fetch_binding); break; - case SWITCH_XML_SECTION_CHATPLAN: - result = fetch_reply(uuid_str, xml_str, kazoo_globals.chatplan_fetch_binding); - break; case SWITCH_XML_SECTION_CHANNELS: result = fetch_reply(uuid_str, xml_str, kazoo_globals.channels_fetch_binding); break; + case SWITCH_XML_SECTION_LANGUAGES: + result = fetch_reply(uuid_str, xml_str, kazoo_globals.languages_fetch_binding); + break; + case SWITCH_XML_SECTION_CHATPLAN: + result = fetch_reply(uuid_str, xml_str, kazoo_globals.chatplan_fetch_binding); + break; default: - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved fetch reply for an unknown configuration section: %s\n", section_str); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received fetch reply %s for an unknown configuration section: %s : %s\n", uuid_str, section_str, xml_str); return erlang_response_badarg(rbuf); } if (result == SWITCH_STATUS_SUCCESS) { return erlang_response_ok(rbuf); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved fetch reply for an unknown/expired UUID: %s\n", uuid_str); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received fetch reply %s is unknown or has expired : %s\n", uuid_str, xml_str); return erlang_response_baduuid(rbuf); } } @@ -988,12 +1157,12 @@ static switch_status_t handle_kazoo_request(ei_node_t *ei_node, erlang_pid *pid, } if (ei_decode_atom_safe(buf->buff, &buf->index, atom)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved mod_kazoo message that did not contain a command (ensure you are using Kazoo v2.14+).\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received mod_kazoo message that did not contain a command (ensure you are using Kazoo v2.14+).\n"); return erlang_response_badarg(rbuf); } if (find_request(atom, &request) != SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved mod_kazoo message for unimplemented feature (ensure you are using Kazoo v2.14+): %s\n", atom); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received mod_kazoo message for unimplemented feature (ensure you are using Kazoo v2.14+): %s\n", atom); return erlang_response_badarg(rbuf); } @@ -1010,6 +1179,10 @@ static switch_status_t handle_kazoo_request(ei_node_t *ei_node, erlang_pid *pid, return handle_request_sendevent(ei_node, pid, buf, rbuf); case REQUEST_SENDMSG: return handle_request_sendmsg(ei_node, pid, buf, rbuf); + case REQUEST_COMMAND: + return handle_request_command(ei_node, pid, buf, rbuf); + case REQUEST_COMMANDS: + return handle_request_commands(ei_node, pid, buf, rbuf); case REQUEST_BIND: return handle_request_bind(ei_node, pid, buf, rbuf); case REQUEST_GETPID: @@ -1024,12 +1197,14 @@ static switch_status_t handle_kazoo_request(ei_node_t *ei_node, erlang_pid *pid, return handle_request_event(ei_node, pid, buf, rbuf); case REQUEST_FETCH_REPLY: return handle_request_fetch_reply(ei_node, pid, buf, rbuf); - case REQUEST_CONFIG: - return handle_request_config(ei_node, pid, buf, rbuf); - case REQUEST_BGAPI4: - return handle_request_bgapi4(ei_node, pid, buf, rbuf); + case REQUEST_CONFIG: + return handle_request_config(ei_node, pid, buf, rbuf); + case REQUEST_BGAPI4: + return handle_request_bgapi4(ei_node, pid, buf, rbuf); case REQUEST_API4: return handle_request_api4(ei_node, pid, buf, rbuf); + case REQUEST_JSON_API: + return handle_request_json_api(ei_node, pid, buf, rbuf); default: return erlang_response_notimplemented(rbuf); } @@ -1052,7 +1227,7 @@ static switch_status_t handle_mod_kazoo_request(ei_node_t *ei_node, erlang_msg * ei_decode_tuple_header(buf->buff, &buf->index, &arity); if (ei_decode_atom_safe(buf->buff, &buf->index, atom)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved erlang message tuple that did not start with an atom (ensure you are using Kazoo v2.14+).\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received erlang message tuple that did not start with an atom (ensure you are using Kazoo v2.14+).\n"); return SWITCH_STATUS_GENERR; } @@ -1108,7 +1283,7 @@ static switch_status_t handle_mod_kazoo_request(ei_node_t *ei_node, erlang_msg * return status; } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved inappropriate erlang message (ensure you are using Kazoo v2.14+)\n"); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received inappropriate erlang message (ensure you are using Kazoo v2.14+)\n"); return SWITCH_STATUS_GENERR; } } @@ -1214,7 +1389,7 @@ static switch_status_t handle_erl_send(ei_node_t *ei_node, erlang_msg *msg, ei_x } else if (!strncmp(msg->toname, "mod_kazoo", MAXATOMLEN)) { return handle_mod_kazoo_request(ei_node, msg, buf); } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Recieved erlang message to unknown process \"%s\" (ensure you are using Kazoo v2.14+).\n", msg->toname); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Received erlang message to unknown process \"%s\" (ensure you are using Kazoo v2.14+).\n", msg->toname); return SWITCH_STATUS_GENERR; } } @@ -1262,7 +1437,7 @@ static void *SWITCH_THREAD_FUNC receive_handler(switch_thread_t *thread, void *o while (switch_test_flag(ei_node, LFLAG_RUNNING) && switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { void *pop; - if (switch_queue_pop_timeout(ei_node->received_msgs, &pop, 500000) == SWITCH_STATUS_SUCCESS) { + if (switch_queue_pop_timeout(ei_node->received_msgs, &pop, 100000) == SWITCH_STATUS_SUCCESS) { ei_received_msg_t *received_msg = (ei_received_msg_t *) pop; handle_erl_msg(ei_node, &received_msg->msg, &received_msg->buf); ei_x_free(&received_msg->buf); @@ -1313,7 +1488,7 @@ static void *SWITCH_THREAD_FUNC handle_node(switch_thread_t *thread, void *obj) } while (++send_msg_count <= kazoo_globals.send_msg_batch - && switch_queue_trypop(ei_node->send_msgs, &pop) == SWITCH_STATUS_SUCCESS) { + && switch_queue_pop_timeout(ei_node->send_msgs, &pop, 20000) == SWITCH_STATUS_SUCCESS) { ei_send_msg_t *send_msg = (ei_send_msg_t *) pop; ei_helper_send(ei_node, &send_msg->pid, &send_msg->buf); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Sent erlang message to %s <%d.%d.%d>\n" @@ -1431,16 +1606,18 @@ switch_status_t new_kazoo_node(int nodefd, ErlConnect *conn) { ei_node->nodefd = nodefd; ei_node->peer_nodename = switch_core_strdup(ei_node->pool, conn->nodename); ei_node->created_time = switch_micro_time_now(); + ei_node->legacy = kazoo_globals.legacy_events; + ei_node->event_stream_framing = kazoo_globals.event_stream_framing; /* store the IP and node name we are talking with */ switch_os_sock_put(&ei_node->socket, (switch_os_socket_t *)&nodefd, pool); switch_socket_addr_get(&sa, SWITCH_TRUE, ei_node->socket); - ei_node->local_port = switch_sockaddr_get_port(sa); + ei_node->remote_port = switch_sockaddr_get_port(sa); switch_get_addr(ei_node->remote_ip, sizeof (ei_node->remote_ip), sa); switch_socket_addr_get(&sa, SWITCH_FALSE, ei_node->socket); - ei_node->remote_port = switch_sockaddr_get_port(sa); + ei_node->local_port = switch_sockaddr_get_port(sa); switch_get_addr(ei_node->local_ip, sizeof (ei_node->local_ip), sa); switch_queue_create(&ei_node->send_msgs, MAX_QUEUE_LEN, pool); @@ -1451,8 +1628,7 @@ switch_status_t new_kazoo_node(int nodefd, ErlConnect *conn) { /* when we start we are running */ switch_set_flag(ei_node, LFLAG_RUNNING); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "New erlang connection from node %s (%s:%d)\n", ei_node->peer_nodename, ei_node->remote_ip, ei_node->remote_port); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "New erlang connection to node %s (%s:%d)\n", ei_node->peer_nodename, ei_node->local_ip, ei_node->local_port); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "New erlang connection from node %s (%s:%d) -> (%s:%d)\n", ei_node->peer_nodename, ei_node->remote_ip, ei_node->remote_port, ei_node->local_ip, ei_node->local_port); for(i = 0; i < kazoo_globals.num_worker_threads; i++) { switch_threadattr_create(&thd_attr, ei_node->pool); diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_tweaks.c b/src/mod/event_handlers/mod_kazoo/kazoo_tweaks.c new file mode 100644 index 0000000000..67f4d37a99 --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kazoo_tweaks.c @@ -0,0 +1,741 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2012, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Luis Azedo + * + * mod_hacks.c -- hacks with state handlers + * + */ +#include "mod_kazoo.h" + +#define INTERACTION_VARIABLE "Call-Interaction-ID" +#define BRIDGE_INTERCEPT_VARIABLE "Bridge-Intercepted" + +static char *TWEAK_NAMES[] = { + "interaction-id", + "export-vars", + "switch-uri", + "replaces-call-id", + "loopback-vars", + "caller-id", + "transfers", + "bridge", + "bridge-replaces-aleg", + "bridge-replaces-call-id", + "bridge-variables", + "restore-caller-id-on-blind-xfer" +}; + +static const char *bridge_variables[] = { + "Call-Control-Queue", + "Call-Control-PID", + "Call-Control-Node", + INTERACTION_VARIABLE, + "ecallmgr_Ecallmgr-Node", + "sip_h_k-cid", + "Switch-URI", + "Switch-URL", + NULL +}; + +static switch_status_t kz_tweaks_signal_bridge_on_hangup(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_event_t *my_event; + + const char *peer_uuid = switch_channel_get_variable(channel, "Bridge-B-Unique-ID"); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak signal bridge on hangup: %s , %s\n", switch_core_session_get_uuid(session), peer_uuid); + + + if (switch_event_create(&my_event, SWITCH_EVENT_CHANNEL_UNBRIDGE) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(my_event, SWITCH_STACK_BOTTOM, "Bridge-A-Unique-ID", switch_core_session_get_uuid(session)); + switch_event_add_header_string(my_event, SWITCH_STACK_BOTTOM, "Bridge-B-Unique-ID", peer_uuid); + switch_channel_event_set_data(channel, my_event); + switch_event_fire(&my_event); + } + + return SWITCH_STATUS_SUCCESS; +} + +static const switch_state_handler_table_t kz_tweaks_signal_bridge_state_handlers = { + /*.on_init */ NULL, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ kz_tweaks_signal_bridge_on_hangup, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ NULL, + /*.on_destroy */ NULL +}; + +static void kz_tweaks_handle_bridge_variables(switch_event_t *event) +{ + switch_core_session_t *a_session = NULL, *b_session = NULL; + const char *a_leg = switch_event_get_header(event, "Bridge-A-Unique-ID"); + const char *b_leg = switch_event_get_header(event, "Bridge-B-Unique-ID"); + int i; + + if (!kz_test_tweak(KZ_TWEAK_BRIDGE_VARIABLES)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak bridge event handler: variables : %s , %s\n", a_leg, b_leg); + + + if (a_leg && (a_session = switch_core_session_force_locate(a_leg)) != NULL) { + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + if(switch_channel_get_variable_dup(a_channel, bridge_variables[0], SWITCH_FALSE, -1) == NULL) { + if(b_leg && (b_session = switch_core_session_force_locate(b_leg)) != NULL) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + for(i = 0; bridge_variables[i] != NULL; i++) { + const char *val = switch_channel_get_variable_dup(b_channel, bridge_variables[i], SWITCH_FALSE, -1); + switch_channel_set_variable(a_channel, bridge_variables[i], val); + } + switch_core_session_rwunlock(b_session); + } + } else { + if(b_leg && (b_session = switch_core_session_force_locate(b_leg)) != NULL) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + if(switch_channel_get_variable_dup(b_channel, bridge_variables[0], SWITCH_FALSE, -1) == NULL) { + for(i = 0; bridge_variables[i] != NULL; i++) { + const char *val = switch_channel_get_variable_dup(a_channel, bridge_variables[i], SWITCH_FALSE, -1); + switch_channel_set_variable(b_channel, bridge_variables[i], val); + } + } + switch_core_session_rwunlock(b_session); + } + } + switch_core_session_rwunlock(a_session); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "NOT FOUND : %s\n", a_leg); + } + +} + +static void kz_tweaks_handle_bridge_intercepted(switch_event_t *event) +{ + switch_event_t *my_event; + switch_core_session_t *a_session = NULL; + switch_core_session_t *b_session = NULL; + + const char *uuid = switch_event_get_header(event, "Unique-ID"); + const char *a_leg = switch_event_get_header(event, "Bridge-A-Unique-ID"); + const char *b_leg = switch_event_get_header(event, "Bridge-B-Unique-ID"); + const char *bridge_intercepted = NULL; + + if (!kz_test_tweak(KZ_TWEAK_BRIDGE_REPLACES_ALEG)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak bridge event handler: intercepted : %s , %s, %s\n", uuid, a_leg, b_leg); + + + if ((a_session = switch_core_session_locate(a_leg)) != NULL) { + switch_channel_t *a_channel = switch_core_session_get_channel(a_session); + bridge_intercepted = switch_channel_get_variable_dup(a_channel, BRIDGE_INTERCEPT_VARIABLE, SWITCH_TRUE, -1); + switch_channel_set_variable(a_channel, BRIDGE_INTERCEPT_VARIABLE, NULL); + if (bridge_intercepted && switch_true(bridge_intercepted)) { + switch_channel_set_variable(a_channel, "Bridge-B-Unique-ID", b_leg); + switch_channel_add_state_handler(a_channel, &kz_tweaks_signal_bridge_state_handlers); + + if ((b_session = switch_core_session_locate(b_leg)) != NULL) { + switch_channel_t *b_channel = switch_core_session_get_channel(b_session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "creating channel_bridge event A - %s , B - %s\n", switch_core_session_get_uuid(b_session), uuid); + if (switch_event_create(&my_event, SWITCH_EVENT_CHANNEL_BRIDGE) == SWITCH_STATUS_SUCCESS) { + switch_event_add_header_string(my_event, SWITCH_STACK_BOTTOM, "Bridge-A-Unique-ID", switch_core_session_get_uuid(b_session)); + switch_event_add_header_string(my_event, SWITCH_STACK_BOTTOM, "Bridge-B-Unique-ID", uuid); + switch_channel_event_set_data(b_channel, my_event); + switch_event_fire(&my_event); + } + switch_core_session_rwunlock(b_session); + } + } + switch_core_session_rwunlock(a_session); + } + switch_safe_strdup(bridge_intercepted); +} + +static void kz_tweaks_channel_bridge_event_handler(switch_event_t *event) +{ + const char *uuid = switch_event_get_header(event, "Unique-ID"); + + if (!kz_test_tweak(KZ_TWEAK_BRIDGE)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak bridge event handler: %s\n", uuid); + + kz_tweaks_handle_bridge_intercepted(event); + kz_tweaks_handle_bridge_variables(event); +} + +// TRANSFERS + +static void kz_tweaks_channel_replaced_event_handler(switch_event_t *event) +{ + const char *uuid = switch_event_get_header(event, "Unique-ID"); + const char *replaced_by = switch_event_get_header(event, "att_xfer_replaced_by"); + + if (!kz_test_tweak(KZ_TWEAK_TRANSFERS)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "REPLACED : %s , %s\n", uuid, replaced_by); +} + +static void kz_tweaks_channel_intercepted_event_handler(switch_event_t *event) +{ + switch_core_session_t *uuid_session = NULL; + const char *uuid = switch_event_get_header(event, "Unique-ID"); + const char *peer_uuid = switch_event_get_header(event, "intercepted_by"); + + if (!kz_test_tweak(KZ_TWEAK_TRANSFERS)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "tweak intercepted handler : %s was intercepted by %s\n", uuid, peer_uuid); + + if ((uuid_session = switch_core_session_force_locate(peer_uuid)) != NULL) { + switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "marking %s for channel_bridge handling\n", peer_uuid); + switch_channel_set_variable(uuid_channel, BRIDGE_INTERCEPT_VARIABLE, "true"); + switch_core_session_rwunlock(uuid_session); + } + +} + +static void kz_tweaks_channel_transferor_event_handler(switch_event_t *event) +{ + switch_core_session_t *uuid_session = NULL; + switch_event_t *evt = NULL; + const char *uuid = switch_event_get_header(event, "Unique-ID"); + + const char *orig_call_id = switch_event_get_header(event, "att_xfer_original_call_id"); + const char *dest_peer_uuid = switch_event_get_header(event, "att_xfer_destination_peer_uuid"); + const char *dest_call_id = switch_event_get_header(event, "att_xfer_destination_call_id"); + + const char *file = switch_event_get_header(event, "Event-Calling-File"); + const char *func = switch_event_get_header(event, "Event-Calling-Function"); + const char *line = switch_event_get_header(event, "Event-Calling-Line-Number"); + + if (!kz_test_tweak(KZ_TWEAK_TRANSFERS)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR : %s , %s , %s, %s, %s , %s , %s \n", uuid, orig_call_id, dest_peer_uuid, dest_call_id, file, func, line); + if ((uuid_session = switch_core_session_force_locate(uuid)) != NULL) { + switch_channel_t *uuid_channel = switch_core_session_get_channel(uuid_session); + const char* interaction_id = switch_channel_get_variable_dup(uuid_channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1); + // set to uuid & peer_uuid + if(interaction_id != NULL) { + switch_core_session_t *session = NULL; + if(dest_call_id && (session = switch_core_session_force_locate(dest_call_id)) != NULL) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING UUID PRV : %s : %s\n", prv_interaction_id, interaction_id); + switch_channel_set_variable(channel, INTERACTION_VARIABLE, interaction_id); + if (switch_event_create(&evt, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, evt); + switch_event_fire(&evt); + } + switch_core_session_rwunlock(session); + switch_safe_strdup(prv_interaction_id); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR NO UUID SESSION: %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid); + } + if(dest_peer_uuid && (session = switch_core_session_force_locate(dest_peer_uuid)) != NULL) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING PEER UUID PRV : %s : %s\n", prv_interaction_id, interaction_id); + switch_channel_set_variable(channel, INTERACTION_VARIABLE, interaction_id); + if (switch_event_create(&evt, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, evt); + switch_event_fire(&evt); + } + switch_core_session_rwunlock(session); + switch_safe_strdup(prv_interaction_id); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR NO PEER SESSION: %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid); + } + if(orig_call_id && (session = switch_core_session_force_locate(orig_call_id)) != NULL) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char* prv_interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_TRUE, -1); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "LOCATING PEER UUID PRV : %s : %s\n", prv_interaction_id, interaction_id); + switch_channel_set_variable(channel, INTERACTION_VARIABLE, interaction_id); + if (switch_event_create(&evt, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, evt); + switch_event_fire(&evt); + } + switch_core_session_rwunlock(session); + switch_safe_strdup(prv_interaction_id); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR NO PEER SESSION: %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid); + } + switch_safe_strdup(interaction_id); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEROR ID = NULL : %s , %s , %s \n", uuid, dest_call_id, dest_peer_uuid); + } + switch_core_session_rwunlock(uuid_session); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "SESSION NOT FOUND : %s\n", uuid); + } +} + +static void kz_tweaks_channel_transferee_event_handler(switch_event_t *event) +{ + const char *uuid = switch_event_get_header(event, "Unique-ID"); + const char *replaced_by_uuid = switch_event_get_header(event, "att_xfer_replaced_call_id"); + + if (!kz_test_tweak(KZ_TWEAK_TRANSFERS)) return; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "TRANSFEREE : %s replaced by %s\n", uuid, replaced_by_uuid); +} + +// END TRANSFERS + + +static switch_status_t kz_tweaks_handle_loopback(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_t *a_channel = NULL; + const char * loopback_leg = NULL; + const char * loopback_aleg = NULL; + switch_core_session_t *a_session = NULL; + switch_event_t *event = NULL; + switch_event_header_t *header = NULL; + switch_event_t *to_add = NULL; + switch_event_t *to_remove = NULL; + switch_caller_profile_t *caller; + int n = 0; + + if (!kz_test_tweak(KZ_TWEAK_LOOPBACK_VARS)) { + return SWITCH_STATUS_SUCCESS; + } + + caller = switch_channel_get_caller_profile(channel); + if(strncmp(caller->source, "mod_loopback", 12)) + return SWITCH_STATUS_SUCCESS; + + if((loopback_leg = switch_channel_get_variable(channel, "loopback_leg")) == NULL) + return SWITCH_STATUS_SUCCESS; + + if(strncmp(loopback_leg, "B", 1)) + return SWITCH_STATUS_SUCCESS; + + switch_channel_get_variables(channel, &event); + switch_event_create_plain(&to_add, SWITCH_EVENT_CHANNEL_DATA); + switch_event_create_plain(&to_remove, SWITCH_EVENT_CHANNEL_DATA); + + for(header = event->headers; header; header = header->next) { + if(!strncmp(header->name, "Export-Loopback-", 16)) { + kz_switch_event_add_variable_name_printf(to_add, SWITCH_STACK_BOTTOM, header->value, "%s", header->name+16); + switch_channel_set_variable(channel, header->name, NULL); + n++; + } else if(!strncmp(header->name, "sip_loopback_", 13)) { + kz_switch_event_add_variable_name_printf(to_add, SWITCH_STACK_BOTTOM, header->value, "sip_%s", header->name+13); + } else if(!strncmp(header->name, "ecallmgr_", 9)) { + switch_event_add_header_string(to_remove, SWITCH_STACK_BOTTOM, header->name, header->value); + } + } + if(n) { + for(header = to_remove->headers; header; header = header->next) { + switch_channel_set_variable(channel, header->name, NULL); + } + } + + for(header = to_add->headers; header; header = header->next) { + switch_channel_set_variable(channel, header->name, header->value); + } + + // cleanup leg A + loopback_aleg = switch_channel_get_variable(channel, "other_loopback_leg_uuid"); + if(loopback_aleg != NULL) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found loopback a-leg uuid - %s\n", loopback_aleg); + if ((a_session = switch_core_session_locate(loopback_aleg))) { + a_channel = switch_core_session_get_channel(a_session); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "found loopback session a - %s\n", loopback_aleg); + switch_channel_del_variable_prefix(a_channel, "Export-Loopback-"); + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Couldn't locate loopback session a - %s\n", loopback_aleg); + } + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Couldn't find loopback a-leg uuid!\n"); + } + + /* + * set Interaction-ID + * if we're not crossing account boundaries + */ + if (kz_test_tweak(KZ_TWEAK_INTERACTION_ID)) { + if (a_channel) { + const char *interaction_id = switch_channel_get_variable_dup(a_channel, INTERACTION_VARIABLE, SWITCH_FALSE, -1); + const char *a_account_id = switch_channel_get_variable_dup(a_channel, "ecallmgr_Account-ID", SWITCH_FALSE, -1); + const char *b_account_id = switch_channel_get_variable_dup(channel, "ecallmgr_Account-ID", SWITCH_FALSE, -1); + if ((!a_account_id) || (!b_account_id) || (!strcmp(a_account_id, b_account_id))) { + switch_channel_set_variable(channel, INTERACTION_VARIABLE, interaction_id); + } + } + } + + if (a_session){ + switch_core_session_rwunlock(a_session); + } + switch_event_destroy(&event); + switch_event_destroy(&to_add); + switch_event_destroy(&to_remove); + + return SWITCH_STATUS_SUCCESS; + +} + +static void kz_tweaks_handle_caller_id(switch_core_session_t *session) +{ + if (kz_test_tweak(KZ_TWEAK_CALLER_ID)) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_caller_profile_t* caller = switch_channel_get_caller_profile(channel); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "CHECKING CALLER-ID\n"); + if (caller && switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) { + const char* val = NULL; + if((val=switch_caller_get_field_by_name(caller, "Endpoint-Caller-ID-Name"))) { + caller->caller_id_name = val; + caller->orig_caller_id_name = val; + } + if((val=switch_caller_get_field_by_name(caller, "Endpoint-Caller-ID-Number"))) { + caller->caller_id_number = val; + caller->orig_caller_id_number = val; + } + } + } +} + +/* +static switch_status_t kz_tweaks_handle_auth_token(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_event_t *event; + const char *token = switch_channel_get_variable(channel, "sip_h_X-FS-Auth-Token"); + if(token) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticating user for nightmare xfer %s\n", token); + if (switch_ivr_set_user(session, token) == SWITCH_STATUS_SUCCESS) { + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "Authenticated user from nightmare xfer %s\n", token); + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Error Authenticating user for nightmare xfer %s\n", token); + } + } + + return SWITCH_STATUS_SUCCESS; + +} +*/ + +static switch_status_t kz_tweaks_handle_nightmare_xfer_interaction_id(switch_core_session_t *session) +{ + if (kz_test_tweak(KZ_TWEAK_INTERACTION_ID)) { + switch_core_session_t *replace_session = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *replaced_call_id = switch_channel_get_variable(channel, "sip_replaces_call_id"); + const char *core_uuid = switch_channel_get_variable(channel, "sip_h_X-FS-From-Core-UUID"); + const char *partner_uuid = switch_channel_get_variable(channel, "sip_h_X-FS-Refer-Partner-UUID"); + const char *interaction_id = switch_channel_get_variable(channel, "sip_h_X-FS-Call-Interaction-ID"); + if(core_uuid && partner_uuid && replaced_call_id && interaction_id) { + switch_channel_set_variable(channel, INTERACTION_VARIABLE, interaction_id); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "checking nightmare xfer tweak for %s\n", switch_channel_get_uuid(channel)); + if ((replace_session = switch_core_session_locate(replaced_call_id))) { + switch_channel_t *replaced_call_channel = switch_core_session_get_channel(replace_session); + switch_channel_set_variable(replaced_call_channel, INTERACTION_VARIABLE, interaction_id); + switch_core_session_rwunlock(replace_session); + } + if ((replace_session = switch_core_session_locate(partner_uuid))) { + switch_channel_t *replaced_call_channel = switch_core_session_get_channel(replace_session); + switch_channel_set_variable(replaced_call_channel, INTERACTION_VARIABLE, interaction_id); + switch_core_session_rwunlock(replace_session); + } + } + } + + return SWITCH_STATUS_SUCCESS; + +} + +static switch_status_t kz_tweaks_handle_replaces_call_id(switch_core_session_t *session) +{ + if (kz_test_tweak(KZ_TWEAK_REPLACES_CALL_ID)) { + switch_core_session_t *replace_call_session = NULL; + switch_event_t *event; + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *replaced_call_id = switch_channel_get_variable(channel, "sip_replaces_call_id"); + const char *core_uuid = switch_channel_get_variable(channel, "sip_h_X-FS-From-Core-UUID"); + if((!core_uuid) && replaced_call_id) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "checking replaces header tweak for %s\n", replaced_call_id); + if ((replace_call_session = switch_core_session_locate(replaced_call_id))) { + switch_channel_t *replaced_call_channel = switch_core_session_get_channel(replace_call_session); + int i; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "setting bridge variables from %s to %s\n", replaced_call_id, switch_channel_get_uuid(channel)); + for(i = 0; bridge_variables[i] != NULL; i++) { + const char *val = switch_channel_get_variable_dup(replaced_call_channel, bridge_variables[i], SWITCH_TRUE, -1); + switch_channel_set_variable(channel, bridge_variables[i], val); + switch_safe_strdup(val); + } + if (switch_event_create(&event, SWITCH_EVENT_CHANNEL_DATA) == SWITCH_STATUS_SUCCESS) { + switch_channel_event_set_data(channel, event); + switch_event_fire(&event); + } + switch_core_session_rwunlock(replace_call_session); + } + } + } + + return SWITCH_STATUS_SUCCESS; + +} + + +static switch_status_t kz_tweaks_handle_switch_uri(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + if (kz_test_tweak(KZ_TWEAK_SWITCH_URI)) { + const char *profile_url = switch_channel_get_variable(channel, "sofia_profile_url"); + if(profile_url) { + int n = strcspn(profile_url, "@"); + switch_channel_set_variable(channel, "Switch-URL", profile_url); + switch_channel_set_variable_printf(channel, "Switch-URI", "sip:%s", n > 0 ? profile_url + n + 1 : profile_url); + } + } + + return SWITCH_STATUS_SUCCESS; + +} + +static void kz_tweaks_handle_interaction_id(switch_core_session_t *session) +{ + const char *expr = "${expr(ceil((${Event-Date-Timestamp} / 1000000) + $${UNIX_EPOCH_IN_GREGORIAN}))}-${regex(${create_uuid()}|^([^-]*)|%1)}"; + switch_channel_t *channel = switch_core_session_get_channel(session); + char * val = NULL; + switch_core_session_t *peer_session = NULL; + const char* peer_interaction_id = NULL; + + if (kz_test_tweak(KZ_TWEAK_INTERACTION_ID)) { + val = kz_expand(expr); + if (val) { + switch_channel_set_variable(channel, "Original-"INTERACTION_VARIABLE, val); + if(switch_core_session_get_partner(session, &peer_session) == SWITCH_STATUS_SUCCESS) { + switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session); + peer_interaction_id = switch_channel_get_variable_dup(peer_channel, INTERACTION_VARIABLE, SWITCH_FALSE, -1); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "PEER_SESSION => %s\n", peer_interaction_id); + if(peer_interaction_id) { + switch_channel_set_variable(channel, INTERACTION_VARIABLE, peer_interaction_id); + } + switch_core_session_rwunlock(peer_session); + } else if (!switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_FALSE, -1)) { + switch_channel_set_variable(channel, INTERACTION_VARIABLE, val); + } + } + + switch_safe_free(val); + } + +} + +static switch_status_t kz_outgoing_channel(switch_core_session_t * session, switch_event_t * event, switch_caller_profile_t * cp, switch_core_session_t * peer_session, switch_originate_flag_t flag) +{ + if (kz_test_tweak(KZ_TWEAK_INTERACTION_ID)) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "GOT OUTGOING\n"); + if (peer_session) { + switch_channel_t *channel = switch_core_session_get_channel(session); + const char* interaction_id = switch_channel_get_variable_dup(channel, INTERACTION_VARIABLE, SWITCH_FALSE, -1); + switch_channel_t *peer_channel = switch_core_session_get_channel(peer_session); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "SESSION && PEER_SESSION => %s\n", interaction_id ); + if (interaction_id) { + switch_channel_set_variable(peer_channel, INTERACTION_VARIABLE, interaction_id); + } + } else { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "NO SESSION && PEER_SESSION\n"); + } + } + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t kz_tweaks_register_handle_blind_xfer(switch_core_session_t *session) +{ + if (kz_test_tweak(KZ_TWEAK_RESTORE_CALLER_ID_ON_BLIND_XFER)) { + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_channel_set_variable(channel, "execute_on_blind_transfer", "kz_restore_caller_id"); + } + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t kz_tweaks_set_export_vars(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + const char *exports; + char *var, *new_exports, *new_exports_d = NULL; + + if (kz_test_tweak(KZ_TWEAK_EXPORT_VARS)) { + exports = switch_channel_get_variable(channel, SWITCH_EXPORT_VARS_VARIABLE); + var = switch_core_session_strdup(session, "Switch-URI,Switch-URL"); + + if (exports) { + new_exports_d = switch_mprintf("%s,%s", exports, var); + new_exports = new_exports_d; + } else { + new_exports = var; + } + + switch_channel_set_variable(channel, SWITCH_EXPORT_VARS_VARIABLE, new_exports); + + switch_safe_free(new_exports_d); + } + + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t kz_tweaks_on_init(switch_core_session_t *session) +{ + switch_channel_t *channel = switch_core_session_get_channel(session); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG1, "checking tweaks for %s\n", switch_channel_get_uuid(channel)); + switch_channel_set_flag(channel, CF_VERBOSE_EVENTS); + switch_core_event_hook_add_outgoing_channel(session, kz_outgoing_channel); + kz_tweaks_handle_interaction_id(session); + kz_tweaks_handle_switch_uri(session); + kz_tweaks_handle_caller_id(session); +// kz_tweaks_handle_auth_token(session); + kz_tweaks_handle_nightmare_xfer_interaction_id(session); + kz_tweaks_handle_replaces_call_id(session); + kz_tweaks_handle_loopback(session); + kz_tweaks_register_handle_blind_xfer(session); + kz_tweaks_set_export_vars(session); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_state_handler_table_t kz_tweaks_state_handlers = { + /*.on_init */ kz_tweaks_on_init, + /*.on_routing */ NULL, + /*.on_execute */ NULL, + /*.on_hangup */ NULL, + /*.on_exchange_media */ NULL, + /*.on_soft_execute */ NULL, + /*.on_consume_media */ NULL, + /*.on_hibernate */ NULL, + /*.on_reset */ NULL, + /*.on_park */ NULL, + /*.on_reporting */ NULL, + /*.on_destroy */ NULL +}; + + +static void kz_tweaks_register_state_handlers() +{ +/* + * we may need two handlers + * one with SSH_FLAG_PRE_EXEC + * and another without it + * mod_loopback tweaks needs post-init (SSH_FLAG_PRE_EXEC off) + * + * kz_tweaks_state_handlers.flags = SSH_FLAG_PRE_EXEC; + * + */ + switch_core_add_state_handler(&kz_tweaks_state_handlers); +} + +static void kz_tweaks_unregister_state_handlers() +{ + switch_core_remove_state_handler(&kz_tweaks_state_handlers); +} + +static void kz_tweaks_bind_events() +{ + if (switch_event_bind("kz_tweaks", SWITCH_EVENT_CHANNEL_BRIDGE, SWITCH_EVENT_SUBCLASS_ANY, kz_tweaks_channel_bridge_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to channel_bridge event!\n"); + } + if (switch_event_bind("kz_tweaks", SWITCH_EVENT_CUSTOM, "sofia::replaced", kz_tweaks_channel_replaced_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to channel_bridge event!\n"); + } + if (switch_event_bind("kz_tweaks", SWITCH_EVENT_CUSTOM, "sofia::intercepted", kz_tweaks_channel_intercepted_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to channel_bridge event!\n"); + } + if (switch_event_bind("kz_tweaks", SWITCH_EVENT_CUSTOM, "sofia::transferor", kz_tweaks_channel_transferor_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to channel_bridge event!\n"); + } + if (switch_event_bind("kz_tweaks", SWITCH_EVENT_CUSTOM, "sofia::transferee", kz_tweaks_channel_transferee_event_handler, NULL) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Couldn't bind to channel_bridge event!\n"); + } +} + +static void kz_tweaks_unbind_events() +{ + switch_event_unbind_callback(kz_tweaks_channel_bridge_event_handler); + switch_event_unbind_callback(kz_tweaks_channel_replaced_event_handler); + switch_event_unbind_callback(kz_tweaks_channel_intercepted_event_handler); + switch_event_unbind_callback(kz_tweaks_channel_transferor_event_handler); + switch_event_unbind_callback(kz_tweaks_channel_transferee_event_handler); +} + +void kz_tweaks_add_core_variables() +{ + switch_core_set_variable("UNIX_EPOCH_IN_GREGORIAN", "62167219200"); +} + +void kz_tweaks_start() +{ + kz_tweaks_add_core_variables(); + kz_tweaks_register_state_handlers(); + kz_tweaks_bind_events(); +} + +void kz_tweaks_stop() +{ + kz_tweaks_unbind_events(); + kz_tweaks_unregister_state_handlers(); +} + +SWITCH_DECLARE(const char *) kz_tweak_name(kz_tweak_t tweak) +{ + return TWEAK_NAMES[tweak]; +} + +SWITCH_DECLARE(switch_status_t) kz_name_tweak(const char *name, kz_tweak_t *type) +{ + kz_tweak_t x; + for (x = 0; x < KZ_TWEAK_MAX; x++) { + if (!strcasecmp(name, TWEAK_NAMES[x])) { + *type = x; + return SWITCH_STATUS_SUCCESS; + } + } + + return SWITCH_STATUS_FALSE; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4: + */ + + diff --git a/src/mod/event_handlers/mod_kazoo/kazoo_utils.c b/src/mod/event_handlers/mod_kazoo/kazoo_utils.c index 024e98b858..f4050bb34a 100644 --- a/src/mod/event_handlers/mod_kazoo/kazoo_utils.c +++ b/src/mod/event_handlers/mod_kazoo/kazoo_utils.c @@ -34,663 +34,603 @@ */ #include "mod_kazoo.h" -/* Stolen from code added to ei in R12B-5. - * Since not everyone has this version yet; - * provide our own version. - * */ +#define kz_resize(l) {\ +char *dp;\ +olen += (len + l + block);\ +cpos = c - data;\ +if ((dp = realloc(data, olen))) {\ + data = dp;\ + c = data + cpos;\ + memset(c, 0, olen - cpos);\ + }} \ -#define put8(s,n) do { \ - (s)[0] = (char)((n) & 0xff); \ - (s) += 1; \ - } while (0) -#define put32be(s,n) do { \ - (s)[0] = ((n) >> 24) & 0xff; \ - (s)[1] = ((n) >> 16) & 0xff; \ - (s)[2] = ((n) >> 8) & 0xff; \ - (s)[3] = (n) & 0xff; \ - (s) += 4; \ - } while (0) +void kz_check_set_profile_var(switch_channel_t *channel, char* var, char *val) +{ + int idx = 0; + while(kazoo_globals.profile_vars_prefixes[idx] != NULL) { + char *prefix = kazoo_globals.profile_vars_prefixes[idx]; + if (!strncasecmp(var, prefix, strlen(prefix))) { + switch_channel_set_profile_var(channel, var + strlen(prefix), val); -#ifdef EI_DEBUG -static void ei_x_print_reg_msg(ei_x_buff *buf, char *dest, int send) { - char *mbuf = NULL; - int i = 1; - - ei_s_print_term(&mbuf, buf->buff, &i); - - if (send) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Encoded term %s to '%s'\n", mbuf, dest); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Decoded term %s for '%s'\n", mbuf, dest); - } - - free(mbuf); -} - -static void ei_x_print_msg(ei_x_buff *buf, erlang_pid *pid, int send) { - char *pbuf = NULL; - int i = 0; - ei_x_buff pidbuf; - - ei_x_new(&pidbuf); - ei_x_encode_pid(&pidbuf, pid); - - ei_s_print_term(&pbuf, pidbuf.buff, &i); - - ei_x_print_reg_msg(buf, pbuf, send); - free(pbuf); -} -#endif - -void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event) { - ei_encode_switch_event_headers_2(ebuf, event, 1); -} - -void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int encode) { - switch_event_header_t *hp; - char *uuid = switch_event_get_header(event, "unique-id"); - int i; - - for (i = 0, hp = event->headers; hp; hp = hp->next, i++); - - if (event->body) - i++; - - ei_x_encode_list_header(ebuf, i + 1); - - if (uuid) { - char *unique_id = switch_event_get_header(event, "unique-id"); - ei_x_encode_binary(ebuf, unique_id, strlen(unique_id)); - } else { - ei_x_encode_atom(ebuf, "undefined"); - } - - for (hp = event->headers; hp; hp = hp->next) { - ei_x_encode_tuple_header(ebuf, 2); - ei_x_encode_binary(ebuf, hp->name, strlen(hp->name)); - if(encode) - switch_url_decode(hp->value); - ei_x_encode_binary(ebuf, hp->value, strlen(hp->value)); - } - - if (event->body) { - ei_x_encode_tuple_header(ebuf, 2); - ei_x_encode_binary(ebuf, "body", strlen("body")); - ei_x_encode_binary(ebuf, event->body, strlen(event->body)); - } - - ei_x_encode_empty_list(ebuf); -} - -void close_socket(switch_socket_t ** sock) { - if (*sock) { - switch_socket_shutdown(*sock, SWITCH_SHUTDOWN_READWRITE); - switch_socket_close(*sock); - *sock = NULL; + } + idx++; } } -void close_socketfd(int *sockfd) { - if (*sockfd) { - shutdown(*sockfd, SHUT_RDWR); - close(*sockfd); +SWITCH_DECLARE(switch_status_t) kz_switch_core_merge_variables(switch_event_t *event) +{ + switch_event_t *global_vars; + switch_status_t status = switch_core_get_variables(&global_vars); + if(status == SWITCH_STATUS_SUCCESS) { + switch_event_merge(event, global_vars); + switch_event_destroy(&global_vars); } + return status; } -switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port) { - switch_sockaddr_t *sa; - switch_socket_t *socket; +SWITCH_DECLARE(switch_status_t) kz_switch_core_base_headers_for_expand(switch_event_t **event) +{ + switch_status_t status = SWITCH_STATUS_GENERR; + *event = NULL; + if(switch_event_create(event, SWITCH_EVENT_GENERAL) == SWITCH_STATUS_SUCCESS) { + status = kz_switch_core_merge_variables(*event); + } + return status; +} - if(switch_sockaddr_info_get(&sa, kazoo_globals.ip, SWITCH_UNSPEC, port, 0, pool)) { +SWITCH_DECLARE(switch_status_t) kz_expand_api_execute(const char *cmd, const char *arg, switch_core_session_t *session, switch_stream_handle_t *stream) +{ + switch_api_interface_t *api; + switch_status_t status; + char *arg_used; + char *cmd_used; + + switch_assert(stream != NULL); + switch_assert(stream->data != NULL); + switch_assert(stream->write_function != NULL); + + if (strcasecmp(cmd, "console_complete")) { + cmd_used = switch_strip_whitespace(cmd); + arg_used = switch_strip_whitespace(arg); + } else { + cmd_used = (char *) cmd; + arg_used = (char *) arg; + } + + if (cmd_used && (api = switch_loadable_module_get_api_interface(cmd_used)) != 0) { + if ((status = api->function(arg_used, session, stream)) != SWITCH_STATUS_SUCCESS) { + stream->write_function(stream, "COMMAND RETURNED ERROR!\n"); + } + UNPROTECT_INTERFACE(api); + } else { + status = SWITCH_STATUS_FALSE; + stream->write_function(stream, "INVALID COMMAND!\n"); + } + + if (cmd_used != cmd) { + switch_safe_free(cmd_used); + } + + if (arg_used != arg) { + switch_safe_free(arg_used); + } + + return status; +} + + +SWITCH_DECLARE(char *) kz_event_expand_headers_check(switch_event_t *event, const char *in, switch_event_t *var_list, switch_event_t *api_list, uint32_t recur) +{ + char *p, *c = NULL; + char *data, *indup, *endof_indup; + size_t sp = 0, len = 0, olen = 0, vtype = 0, br = 0, cpos, block = 128; + const char *sub_val = NULL; + char *cloned_sub_val = NULL, *expanded_sub_val = NULL; + char *func_val = NULL; + int nv = 0; + char *gvar = NULL, *sb = NULL; + + if (recur > 100) { + return (char *) in; + } + + if (zstr(in)) { + return (char *) in; + } + + nv = switch_string_var_check_const(in) || switch_string_has_escaped_data(in); + + if (!nv) { + return (char *) in; + } + + nv = 0; + olen = strlen(in) + 1; + indup = strdup(in); + endof_indup = end_of_p(indup) + 1; + + if ((data = malloc(olen))) { + memset(data, 0, olen); + c = data; + for (p = indup; p && p < endof_indup && *p; p++) { + int global = 0; + vtype = 0; + + if (*p == '\\') { + if (*(p + 1) == '$') { + nv = 1; + p++; + if (*(p + 1) == '$') { + p++; + } + } else if (*(p + 1) == '\'') { + p++; + continue; + } else if (*(p + 1) == '\\') { + if (len + 1 >= olen) { + kz_resize(1); + } + + *c++ = *p++; + len++; + continue; + } + } + + if (*p == '$' && !nv) { + if (*(p + 1) == '$') { + p++; + global++; + } + + if (*(p + 1)) { + if (*(p + 1) == '{') { + vtype = global ? 3 : 1; + } else { + nv = 1; + } + } else { + nv = 1; + } + } + + if (nv) { + if (len + 1 >= olen) { + kz_resize(1); + } + + *c++ = *p; + len++; + nv = 0; + continue; + } + + if (vtype) { + char *s = p, *e, *vname, *vval = NULL; + size_t nlen; + + s++; + + if ((vtype == 1 || vtype == 3) && *s == '{') { + br = 1; + s++; + } + + e = s; + vname = s; + while (*e) { + if (br == 1 && *e == '}') { + br = 0; + *e++ = '\0'; + break; + } + + if (br > 0) { + if (e != s && *e == '{') { + br++; + } else if (br > 1 && *e == '}') { + br--; + } + } + + e++; + } + p = e > endof_indup ? endof_indup : e; + + vval = NULL; + for(sb = vname; sb && *sb; sb++) { + if (*sb == ' ') { + vval = sb; + break; + } else if (*sb == '(') { + vval = sb; + br = 1; + break; + } + } + + if (vval) { + e = vval - 1; + *vval++ = '\0'; + + while (*e == ' ') { + *e-- = '\0'; + } + e = vval; + + while (e && *e) { + if (*e == '(') { + br++; + } else if (br > 1 && *e == ')') { + br--; + } else if (br == 1 && *e == ')') { + *e = '\0'; + break; + } + e++; + } + + vtype = 2; + } + + if (vtype == 1 || vtype == 3) { + char *expanded = NULL; + int offset = 0; + int ooffset = 0; + char *ptr; + int idx = -1; + + if ((expanded = kz_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) { + expanded = NULL; + } else { + vname = expanded; + } + if ((ptr = strchr(vname, ':'))) { + *ptr++ = '\0'; + offset = atoi(ptr); + if ((ptr = strchr(ptr, ':'))) { + ptr++; + ooffset = atoi(ptr); + } + } + + if ((ptr = strchr(vname, '[')) && strchr(ptr, ']')) { + *ptr++ = '\0'; + idx = atoi(ptr); + } + + if (vtype == 3 || !(sub_val = switch_event_get_header_idx(event, vname, idx))) { + switch_safe_free(gvar); + if ((gvar = switch_core_get_variable_dup(vname))) { + sub_val = gvar; + } + + if (var_list && !switch_event_check_permission_list(var_list, vname)) { + sub_val = ""; + } + + + if ((expanded_sub_val = kz_event_expand_headers_check(event, sub_val, var_list, api_list, recur+1)) == sub_val) { + expanded_sub_val = NULL; + } else { + sub_val = expanded_sub_val; + } + } + + if (sub_val) { + if (offset || ooffset) { + cloned_sub_val = strdup(sub_val); + switch_assert(cloned_sub_val); + sub_val = cloned_sub_val; + } + + if (offset >= 0) { + sub_val += offset; + } else if ((size_t) abs(offset) <= strlen(sub_val)) { + sub_val = cloned_sub_val + (strlen(cloned_sub_val) + offset); + } + + if (ooffset > 0 && (size_t) ooffset < strlen(sub_val)) { + if ((ptr = (char *) sub_val + ooffset)) { + *ptr = '\0'; + } + } + } + + switch_safe_free(expanded); + } else { + switch_stream_handle_t stream = { 0 }; + char *expanded = NULL; + + SWITCH_STANDARD_STREAM(stream); + + if (stream.data) { + char *expanded_vname = NULL; + + if ((expanded_vname = kz_event_expand_headers_check(event, (char *) vname, var_list, api_list, recur+1)) == vname) { + expanded_vname = NULL; + } else { + vname = expanded_vname; + } + + if ((expanded = kz_event_expand_headers_check(event, vval, var_list, api_list, recur+1)) == vval) { + expanded = NULL; + } else { + vval = expanded; + } + + if (!switch_core_test_flag(SCF_API_EXPANSION) || (api_list && !switch_event_check_permission_list(api_list, vname))) { + func_val = NULL; + sub_val = ""; + } else { + stream.param_event = event; + if (kz_expand_api_execute(vname, vval, NULL, &stream) == SWITCH_STATUS_SUCCESS) { + func_val = stream.data; + sub_val = func_val; + } else { + free(stream.data); + } + } + + switch_safe_free(expanded); + switch_safe_free(expanded_vname); + + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Memory Error!\n"); + free(data); + free(indup); + return (char *) in; + } + } + if ((nlen = sub_val ? strlen(sub_val) : 0)) { + if (len + nlen >= olen) { + kz_resize(nlen); + } + + len += nlen; + strcat(c, sub_val); + c += nlen; + } + + switch_safe_free(func_val); + switch_safe_free(cloned_sub_val); + switch_safe_free(expanded_sub_val); + sub_val = NULL; + vname = NULL; + vtype = 0; + br = 0; + } + + if (sp) { + if (len + 1 >= olen) { + kz_resize(1); + } + + *c++ = ' '; + sp = 0; + len++; + } + + if (*p == '$') { + p--; + } else { + if (len + 1 >= olen) { + kz_resize(1); + } + + *c++ = *p; + len++; + } + } + } + free(indup); + switch_safe_free(gvar); + + return data; +} + +SWITCH_DECLARE(char *) kz_event_expand_headers(switch_event_t *event, const char *in) +{ + return kz_event_expand_headers_check(event, in, NULL, NULL, 0); +} + +SWITCH_DECLARE(char *) kz_event_expand(const char *in) +{ + switch_event_t *event = NULL; + char *ret = NULL; + kz_switch_core_base_headers_for_expand(&event); + ret = kz_event_expand_headers_check(event, in, NULL, NULL, 0); + switch_event_destroy(&event); + return ret; +} + +SWITCH_DECLARE(char *) kz_expand(const char *in) +{ + switch_event_t *event = NULL; + char *ret = NULL; + kz_switch_core_base_headers_for_expand(&event); + ret = kz_event_expand_headers_check(event, in, NULL, NULL, 0); + switch_event_destroy(&event); + return ret; +} + +SWITCH_DECLARE(char *) kz_expand_pool(switch_memory_pool_t *pool, const char *in) +{ + char *expanded; + char *dup = NULL; + + if(!(expanded = kz_expand(in))) { return NULL; } + dup = switch_core_strdup(pool, expanded); - if (switch_socket_create(&socket, switch_sockaddr_get_family(sa), SOCK_STREAM, SWITCH_PROTO_TCP, pool)) { - return NULL; + if (expanded != in) { + switch_safe_free(expanded); } - if (switch_socket_opt_set(socket, SWITCH_SO_REUSEADDR, 1)) { - return NULL; - } - - if (switch_socket_bind(socket, sa)) { - return NULL; - } - - if (switch_socket_listen(socket, 5)){ - return NULL; - } - - switch_getnameinfo(&kazoo_globals.hostname, sa, 0); - - // if (kazoo_globals.nat_map && switch_nat_get_type()) { - // switch_nat_add_mapping(port, SWITCH_NAT_TCP, NULL, SWITCH_FALSE); - // } - - return socket; + return dup; } -switch_socket_t *create_socket(switch_memory_pool_t *pool) { - return create_socket_with_port(pool, 0); - +char* kz_switch_event_get_first_of(switch_event_t *event, const char *list[]) +{ + switch_event_header_t *header = NULL; + int i = 0; + while(list[i] != NULL) { + if((header = switch_event_get_header_ptr(event, list[i])) != NULL) + break; + i++; + } + if(header != NULL) { + return header->value; + } else { + return "nodomain"; + } } -switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode) { - char hostname[EI_MAXHOSTNAMELEN + 1] = ""; - char nodename[MAXNODELEN + 1]; - char cnodename[EI_MAXALIVELEN + 1]; - //EI_MAX_COOKIE_SIZE+1 - char *atsign; +SWITCH_DECLARE(switch_status_t) kz_switch_event_add_variable_name_printf(switch_event_t *event, switch_stack_t stack, const char *val, const char *fmt, ...) +{ + int ret = 0; + char *varname; + va_list ap; + switch_status_t status = SWITCH_STATUS_SUCCESS; - /* copy the erlang interface nodename into something we can modify */ - strncpy(cnodename, name, EI_MAXALIVELEN); + switch_assert(event != NULL); - if ((atsign = strchr(cnodename, '@'))) { - /* we got a qualified node name, don't guess the host/domain */ - snprintf(nodename, MAXNODELEN + 1, "%s", kazoo_globals.ei_nodename); - /* truncate the alivename at the @ */ - *atsign = '\0'; - } else { - if (zstr(kazoo_globals.hostname) || !strncasecmp(kazoo_globals.ip, "0.0.0.0", 7) || !strncasecmp(kazoo_globals.ip, "::", 2)) { - memcpy(hostname, switch_core_get_hostname(), EI_MAXHOSTNAMELEN); - } else { - memcpy(hostname, kazoo_globals.hostname, EI_MAXHOSTNAMELEN); - } - snprintf(nodename, MAXNODELEN + 1, "%s@%s", kazoo_globals.ei_nodename, hostname); - } + va_start(ap, fmt); + ret = switch_vasprintf(&varname, fmt, ap); + va_end(ap); - if (kazoo_globals.ei_shortname) { - char *off; - if ((off = strchr(nodename, '.'))) { - *off = '\0'; + if (ret == -1) { + return SWITCH_STATUS_MEMERR; + } + + status = switch_event_add_header_string(event, stack, varname, val); + + free(varname); + + return status; +} + +SWITCH_DECLARE(switch_xml_t) kz_xml_child(switch_xml_t xml, const char *name) +{ + xml = (xml) ? xml->child : NULL; + while (xml && strcasecmp(name, xml->name)) + xml = xml->sibling; + return xml; +} + +void kz_xml_process(switch_xml_t cfg) +{ + switch_xml_t xml_process; + for (xml_process = kz_xml_child(cfg, "X-PRE-PROCESS"); xml_process; xml_process = xml_process->next) { + const char *cmd = switch_xml_attr(xml_process, "cmd"); + const char *data = switch_xml_attr(xml_process, "data"); + if(cmd != NULL && !strcasecmp(cmd, "set") && data) { + char *name = (char *) data; + char *val = strchr(name, '='); + + if (val) { + char *ve = val++; + while (*val && *val == ' ') { + val++; + } + *ve-- = '\0'; + while (*ve && *ve == ' ') { + *ve-- = '\0'; + } + } + + if (name && val) { + switch_core_set_variable(name, val); + } } } - /* init the ec stuff */ - if (ei_connect_xinit(ei_cnode, hostname, cnodename, nodename, (Erl_IpAddr) ip_addr, kazoo_globals.ei_cookie, 0) < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to initialize the erlang interface connection structure\n"); - return SWITCH_STATUS_FALSE; - } - - return SWITCH_STATUS_SUCCESS; } -switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2) { - if ((!strcmp(pid1->node, pid2->node)) - && pid1->creation == pid2->creation - && pid1->num == pid2->num - && pid1->serial == pid2->serial) { - return SWITCH_STATUS_SUCCESS; - } else { - return SWITCH_STATUS_FALSE; - } -} - -void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to) { - char msgbuf[2048]; - char *s; - int index = 0; - - index = 5; /* max sizes: */ - ei_encode_version(msgbuf, &index); /* 1 */ - ei_encode_tuple_header(msgbuf, &index, 3); - ei_encode_long(msgbuf, &index, ERL_LINK); - ei_encode_pid(msgbuf, &index, from); /* 268 */ - ei_encode_pid(msgbuf, &index, to); /* 268 */ - - /* 5 byte header missing */ - s = msgbuf; - put32be(s, index - 4); /* 4 */ - put8(s, ERL_PASS_THROUGH); /* 1 */ - /* sum: 542 */ - - if (write(ei_node->nodefd, msgbuf, index) == -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Failed to link to process on %s\n", ei_node->peer_nodename); - } -} - -void ei_encode_switch_event(ei_x_buff *ebuf, switch_event_t *event) { - ei_x_encode_tuple_header(ebuf, 2); - ei_x_encode_atom(ebuf, "event"); - ei_encode_switch_event_headers(ebuf, event); -} - -int ei_helper_send(ei_node_t *ei_node, erlang_pid *to, ei_x_buff *buf) { - int ret = 0; - - if (ei_node->nodefd) { -#ifdef EI_DEBUG - ei_x_print_msg(buf, to, 1); -#endif - ret = ei_send(ei_node->nodefd, to, buf->buff, buf->index); - } - - return ret; -} - -int ei_decode_atom_safe(char *buf, int *index, char *dst) { - int type, size; - - ei_get_type(buf, index, &type, &size); - - if (type != ERL_ATOM_EXT) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed atom\n", type, size); - return -1; - } else if (size > MAXATOMLEN) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of atom with size %d into a buffer of size %d\n", size, MAXATOMLEN); - return -1; - } else { - return ei_decode_atom(buf, index, dst); - } -} - -int ei_decode_string_or_binary(char *buf, int *index, char **dst) { - int type, size, res; - long len; - - ei_get_type(buf, index, &type, &size); - - if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_NIL_EXT) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size); - return -1; - } - - *dst = malloc(size + 1); - - if (type == ERL_NIL_EXT) { - res = 0; - **dst = '\0'; - } else if (type == ERL_BINARY_EXT) { - res = ei_decode_binary(buf, index, *dst, &len); - (*dst)[len] = '\0'; - } else { - res = ei_decode_string(buf, index, *dst); - } - - return res; -} - -int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst) { - int type, size, res; - long len; - - ei_get_type(buf, index, &type, &size); - - if (type != ERL_STRING_EXT && type != ERL_BINARY_EXT && type != ERL_NIL_EXT) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unexpected erlang term type %d (size %d), needed binary or string\n", type, size); - return -1; - } - - if (size > maxsize) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Requested decoding of %s with size %d into a buffer of size %d\n", - type == ERL_BINARY_EXT ? "binary" : "string", size, maxsize); - return -1; - } - - if (type == ERL_NIL_EXT) { - res = 0; - *dst = '\0'; - } else if (type == ERL_BINARY_EXT) { - res = ei_decode_binary(buf, index, dst, &len); - dst[len] = '\0'; /* binaries aren't null terminated */ - } else { - res = ei_decode_string(buf, index, dst); - } - - return res; -} - -switch_hash_t *create_default_filter() { - switch_hash_t *filter; - - switch_core_hash_init(&filter); - - switch_core_hash_insert(filter, "Acquired-UUID", "1"); - switch_core_hash_insert(filter, "action", "1"); - switch_core_hash_insert(filter, "Action", "1"); - switch_core_hash_insert(filter, "alt_event_type", "1"); - switch_core_hash_insert(filter, "Answer-State", "1"); - switch_core_hash_insert(filter, "Application", "1"); - switch_core_hash_insert(filter, "Application-Data", "1"); - switch_core_hash_insert(filter, "Application-Name", "1"); - switch_core_hash_insert(filter, "Application-Response", "1"); - switch_core_hash_insert(filter, "att_xfer_replaced_by", "1"); - switch_core_hash_insert(filter, "Auth-Method", "1"); - switch_core_hash_insert(filter, "Auth-Realm", "1"); - switch_core_hash_insert(filter, "Auth-User", "1"); - switch_core_hash_insert(filter, "Bridge-A-Unique-ID", "1"); - switch_core_hash_insert(filter, "Bridge-B-Unique-ID", "1"); - switch_core_hash_insert(filter, "Call-Direction", "1"); - switch_core_hash_insert(filter, "Caller-Callee-ID-Name", "1"); - switch_core_hash_insert(filter, "Caller-Callee-ID-Number", "1"); - switch_core_hash_insert(filter, "Caller-Caller-ID-Name", "1"); - switch_core_hash_insert(filter, "Caller-Caller-ID-Number", "1"); - switch_core_hash_insert(filter, "Caller-Screen-Bit", "1"); - switch_core_hash_insert(filter, "Caller-Privacy-Hide-Name", "1"); - switch_core_hash_insert(filter, "Caller-Privacy-Hide-Number", "1"); - switch_core_hash_insert(filter, "Caller-Context", "1"); - switch_core_hash_insert(filter, "Caller-Controls", "1"); - switch_core_hash_insert(filter, "Caller-Destination-Number", "1"); - switch_core_hash_insert(filter, "Caller-Dialplan", "1"); - switch_core_hash_insert(filter, "Caller-Network-Addr", "1"); - switch_core_hash_insert(filter, "Caller-Unique-ID", "1"); - switch_core_hash_insert(filter, "Call-ID", "1"); - switch_core_hash_insert(filter, "Channel-Call-State", "1"); - switch_core_hash_insert(filter, "Channel-Call-UUID", "1"); - switch_core_hash_insert(filter, "Channel-Presence-ID", "1"); - switch_core_hash_insert(filter, "Channel-State", "1"); - switch_core_hash_insert(filter, "Chat-Permissions", "1"); - switch_core_hash_insert(filter, "Conference-Name", "1"); - switch_core_hash_insert(filter, "Conference-Profile-Name", "1"); - switch_core_hash_insert(filter, "Conference-Unique-ID", "1"); - switch_core_hash_insert(filter, "contact", "1"); - switch_core_hash_insert(filter, "Detected-Tone", "1"); - switch_core_hash_insert(filter, "dialog_state", "1"); - switch_core_hash_insert(filter, "direction", "1"); - switch_core_hash_insert(filter, "Distributed-From", "1"); - switch_core_hash_insert(filter, "DTMF-Digit", "1"); - switch_core_hash_insert(filter, "DTMF-Duration", "1"); - switch_core_hash_insert(filter, "Event-Date-Timestamp", "1"); - switch_core_hash_insert(filter, "Event-Name", "1"); - switch_core_hash_insert(filter, "Event-Subclass", "1"); - switch_core_hash_insert(filter, "expires", "1"); - switch_core_hash_insert(filter, "Expires", "1"); - switch_core_hash_insert(filter, "Ext-SIP-IP", "1"); - switch_core_hash_insert(filter, "File", "1"); - switch_core_hash_insert(filter, "FreeSWITCH-Hostname", "1"); - switch_core_hash_insert(filter, "from", "1"); - switch_core_hash_insert(filter, "Hunt-Destination-Number", "1"); - switch_core_hash_insert(filter, "ip", "1"); - switch_core_hash_insert(filter, "Message-Account", "1"); - switch_core_hash_insert(filter, "metadata", "1"); - switch_core_hash_insert(filter, "old_node_channel_uuid", "1"); - switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Name", "1"); - switch_core_hash_insert(filter, "Other-Leg-Callee-ID-Number", "1"); - switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Name", "1"); - switch_core_hash_insert(filter, "Other-Leg-Caller-ID-Number", "1"); - switch_core_hash_insert(filter, "Other-Leg-Destination-Number", "1"); - switch_core_hash_insert(filter, "Other-Leg-Direction", "1"); - switch_core_hash_insert(filter, "Other-Leg-Unique-ID", "1"); - switch_core_hash_insert(filter, "Other-Leg-Channel-Name", "1"); - switch_core_hash_insert(filter, "Participant-Type", "1"); - switch_core_hash_insert(filter, "Path", "1"); - switch_core_hash_insert(filter, "profile_name", "1"); - switch_core_hash_insert(filter, "Profiles", "1"); - switch_core_hash_insert(filter, "proto-specific-event-name", "1"); - switch_core_hash_insert(filter, "Raw-Application-Data", "1"); - switch_core_hash_insert(filter, "realm", "1"); - switch_core_hash_insert(filter, "Resigning-UUID", "1"); - switch_core_hash_insert(filter, "set", "1"); - switch_core_hash_insert(filter, "sip_auto_answer", "1"); - switch_core_hash_insert(filter, "sip_auth_method", "1"); - switch_core_hash_insert(filter, "sip_from_host", "1"); - switch_core_hash_insert(filter, "sip_from_user", "1"); - switch_core_hash_insert(filter, "sip_to_host", "1"); - switch_core_hash_insert(filter, "sip_to_user", "1"); - switch_core_hash_insert(filter, "sub-call-id", "1"); - switch_core_hash_insert(filter, "technology", "1"); - switch_core_hash_insert(filter, "to", "1"); - switch_core_hash_insert(filter, "Unique-ID", "1"); - switch_core_hash_insert(filter, "URL", "1"); - switch_core_hash_insert(filter, "username", "1"); - switch_core_hash_insert(filter, "variable_channel_is_moving", "1"); - switch_core_hash_insert(filter, "variable_collected_digits", "1"); - switch_core_hash_insert(filter, "variable_current_application", "1"); - switch_core_hash_insert(filter, "variable_current_application_data", "1"); - switch_core_hash_insert(filter, "variable_domain_name", "1"); - switch_core_hash_insert(filter, "variable_effective_caller_id_name", "1"); - switch_core_hash_insert(filter, "variable_effective_caller_id_number", "1"); - switch_core_hash_insert(filter, "variable_holding_uuid", "1"); - switch_core_hash_insert(filter, "variable_hold_music", "1"); - switch_core_hash_insert(filter, "variable_media_group_id", "1"); - switch_core_hash_insert(filter, "variable_originate_disposition", "1"); - switch_core_hash_insert(filter, "variable_origination_uuid", "1"); - switch_core_hash_insert(filter, "variable_playback_terminator_used", "1"); - switch_core_hash_insert(filter, "variable_presence_id", "1"); - switch_core_hash_insert(filter, "variable_record_ms", "1"); - switch_core_hash_insert(filter, "variable_recovered", "1"); - switch_core_hash_insert(filter, "variable_silence_hits_exhausted", "1"); - switch_core_hash_insert(filter, "variable_sip_auth_realm", "1"); - switch_core_hash_insert(filter, "variable_sip_from_host", "1"); - switch_core_hash_insert(filter, "variable_sip_from_user", "1"); - switch_core_hash_insert(filter, "variable_sip_from_tag", "1"); - switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-IP", "1"); - switch_core_hash_insert(filter, "variable_sip_received_ip", "1"); - switch_core_hash_insert(filter, "variable_sip_to_host", "1"); - switch_core_hash_insert(filter, "variable_sip_to_user", "1"); - switch_core_hash_insert(filter, "variable_sip_to_tag", "1"); - switch_core_hash_insert(filter, "variable_sofia_profile_name", "1"); - switch_core_hash_insert(filter, "variable_transfer_history", "1"); - switch_core_hash_insert(filter, "variable_user_name", "1"); - switch_core_hash_insert(filter, "variable_endpoint_disposition", "1"); - switch_core_hash_insert(filter, "variable_originate_disposition", "1"); - switch_core_hash_insert(filter, "variable_bridge_hangup_cause", "1"); - switch_core_hash_insert(filter, "variable_hangup_cause", "1"); - switch_core_hash_insert(filter, "variable_last_bridge_proto_specific_hangup_cause", "1"); - switch_core_hash_insert(filter, "variable_proto_specific_hangup_cause", "1"); - switch_core_hash_insert(filter, "VM-Call-ID", "1"); - switch_core_hash_insert(filter, "VM-sub-call-id", "1"); - switch_core_hash_insert(filter, "whistle_application_name", "1"); - switch_core_hash_insert(filter, "whistle_application_response", "1"); - switch_core_hash_insert(filter, "whistle_event_name", "1"); - switch_core_hash_insert(filter, "kazoo_application_name", "1"); - switch_core_hash_insert(filter, "kazoo_application_response", "1"); - switch_core_hash_insert(filter, "kazoo_event_name", "1"); - switch_core_hash_insert(filter, "sip_auto_answer_notify", "1"); - switch_core_hash_insert(filter, "eavesdrop_group", "1"); - switch_core_hash_insert(filter, "origination_caller_id_name", "1"); - switch_core_hash_insert(filter, "origination_caller_id_number", "1"); - switch_core_hash_insert(filter, "origination_callee_id_name", "1"); - switch_core_hash_insert(filter, "origination_callee_id_number", "1"); - switch_core_hash_insert(filter, "sip_auth_username", "1"); - switch_core_hash_insert(filter, "sip_auth_password", "1"); - switch_core_hash_insert(filter, "effective_caller_id_name", "1"); - switch_core_hash_insert(filter, "effective_caller_id_number", "1"); - switch_core_hash_insert(filter, "effective_callee_id_name", "1"); - switch_core_hash_insert(filter, "effective_callee_id_number", "1"); - switch_core_hash_insert(filter, "variable_destination_number", "1"); - switch_core_hash_insert(filter, "variable_effective_callee_id_name", "1"); - switch_core_hash_insert(filter, "variable_effective_callee_id_number", "1"); - switch_core_hash_insert(filter, "variable_record_silence_hits", "1"); - switch_core_hash_insert(filter, "variable_refer_uuid", "1"); - switch_core_hash_insert(filter, "variable_sip_call_id", "1"); - switch_core_hash_insert(filter, "variable_sip_h_Referred-By", "1"); - switch_core_hash_insert(filter, "variable_sip_h_X-AUTH-PORT", "1"); - switch_core_hash_insert(filter, "variable_sip_loopback_req_uri", "1"); - switch_core_hash_insert(filter, "variable_sip_received_port", "1"); - switch_core_hash_insert(filter, "variable_sip_refer_to", "1"); - switch_core_hash_insert(filter, "variable_sip_req_host", "1"); - switch_core_hash_insert(filter, "variable_sip_req_uri", "1"); - switch_core_hash_insert(filter, "variable_transfer_source", "1"); - switch_core_hash_insert(filter, "variable_uuid", "1"); - - /* Registration headers */ - switch_core_hash_insert(filter, "call-id", "1"); - switch_core_hash_insert(filter, "profile-name", "1"); - switch_core_hash_insert(filter, "from-user", "1"); - switch_core_hash_insert(filter, "from-host", "1"); - switch_core_hash_insert(filter, "presence-hosts", "1"); - switch_core_hash_insert(filter, "contact", "1"); - switch_core_hash_insert(filter, "rpid", "1"); - switch_core_hash_insert(filter, "status", "1"); - switch_core_hash_insert(filter, "expires", "1"); - switch_core_hash_insert(filter, "to-user", "1"); - switch_core_hash_insert(filter, "to-host", "1"); - switch_core_hash_insert(filter, "network-ip", "1"); - switch_core_hash_insert(filter, "network-port", "1"); - switch_core_hash_insert(filter, "username", "1"); - switch_core_hash_insert(filter, "realm", "1"); - switch_core_hash_insert(filter, "user-agent", "1"); - - switch_core_hash_insert(filter, "Hangup-Cause", "1"); - switch_core_hash_insert(filter, "Unique-ID", "1"); - switch_core_hash_insert(filter, "variable_switch_r_sdp", "1"); - switch_core_hash_insert(filter, "variable_rtp_local_sdp_str", "1"); - switch_core_hash_insert(filter, "variable_sip_to_uri", "1"); - switch_core_hash_insert(filter, "variable_sip_from_uri", "1"); - switch_core_hash_insert(filter, "variable_sip_user_agent", "1"); - switch_core_hash_insert(filter, "variable_duration", "1"); - switch_core_hash_insert(filter, "variable_billsec", "1"); - switch_core_hash_insert(filter, "variable_billmsec", "1"); - switch_core_hash_insert(filter, "variable_progresssec", "1"); - switch_core_hash_insert(filter, "variable_progress_uepoch", "1"); - switch_core_hash_insert(filter, "variable_progress_media_uepoch", "1"); - switch_core_hash_insert(filter, "variable_start_uepoch", "1"); - switch_core_hash_insert(filter, "variable_digits_dialed", "1"); - switch_core_hash_insert(filter, "Member-ID", "1"); - switch_core_hash_insert(filter, "Floor", "1"); - switch_core_hash_insert(filter, "Video", "1"); - switch_core_hash_insert(filter, "Hear", "1"); - switch_core_hash_insert(filter, "Speak", "1"); - switch_core_hash_insert(filter, "Talking", "1"); - switch_core_hash_insert(filter, "Current-Energy", "1"); - switch_core_hash_insert(filter, "Energy-Level", "1"); - switch_core_hash_insert(filter, "Mute-Detect", "1"); - - /* RTMP headers */ - switch_core_hash_insert(filter, "RTMP-Session-ID", "1"); - switch_core_hash_insert(filter, "RTMP-Profile", "1"); - switch_core_hash_insert(filter, "RTMP-Flash-Version", "1"); - switch_core_hash_insert(filter, "RTMP-SWF-URL", "1"); - switch_core_hash_insert(filter, "RTMP-TC-URL", "1"); - switch_core_hash_insert(filter, "RTMP-Page-URL", "1"); - switch_core_hash_insert(filter, "User", "1"); - switch_core_hash_insert(filter, "Domain", "1"); - - /* Fax headers */ - switch_core_hash_insert(filter, "variable_fax_bad_rows", "1"); - switch_core_hash_insert(filter, "variable_fax_document_total_pages", "1"); - switch_core_hash_insert(filter, "variable_fax_document_transferred_pages", "1"); - switch_core_hash_insert(filter, "variable_fax_ecm_used", "1"); - switch_core_hash_insert(filter, "variable_fax_result_code", "1"); - switch_core_hash_insert(filter, "variable_fax_result_text", "1"); - switch_core_hash_insert(filter, "variable_fax_success", "1"); - switch_core_hash_insert(filter, "variable_fax_transfer_rate", "1"); - switch_core_hash_insert(filter, "variable_fax_local_station_id", "1"); - switch_core_hash_insert(filter, "variable_fax_remote_station_id", "1"); - switch_core_hash_insert(filter, "variable_fax_remote_country", "1"); - switch_core_hash_insert(filter, "variable_fax_remote_vendor", "1"); - switch_core_hash_insert(filter, "variable_fax_remote_model", "1"); - switch_core_hash_insert(filter, "variable_fax_image_resolution", "1"); - switch_core_hash_insert(filter, "variable_fax_file_image_resolution", "1"); - switch_core_hash_insert(filter, "variable_fax_image_size", "1"); - switch_core_hash_insert(filter, "variable_fax_image_pixel_size", "1"); - switch_core_hash_insert(filter, "variable_fax_file_image_pixel_size", "1"); - switch_core_hash_insert(filter, "variable_fax_longest_bad_row_run", "1"); - switch_core_hash_insert(filter, "variable_fax_encoding", "1"); - switch_core_hash_insert(filter, "variable_fax_encoding_name", "1"); - switch_core_hash_insert(filter, "variable_fax_header", "1"); - switch_core_hash_insert(filter, "variable_fax_ident", "1"); - switch_core_hash_insert(filter, "variable_fax_timezone", "1"); - switch_core_hash_insert(filter, "variable_fax_doc_id", "1"); - switch_core_hash_insert(filter, "variable_fax_doc_database", "1"); - switch_core_hash_insert(filter, "variable_has_t38", "1"); - - /* Secure headers */ - switch_core_hash_insert(filter, "variable_sdp_secure_savp_only", "1"); - switch_core_hash_insert(filter, "variable_rtp_has_crypto", "1"); - switch_core_hash_insert(filter, "variable_rtp_secure_media", "1"); - switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed", "1"); - switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_audio", "1"); - switch_core_hash_insert(filter, "variable_rtp_secure_media_confirmed_video", "1"); - switch_core_hash_insert(filter, "variable_zrtp_secure_media", "1"); - switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed", "1"); - switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_audio", "1"); - switch_core_hash_insert(filter, "variable_zrtp_secure_media_confirmed_video", "1"); - switch_core_hash_insert(filter, "sdp_secure_savp_only", "1"); - switch_core_hash_insert(filter, "rtp_has_crypto", "1"); - switch_core_hash_insert(filter, "rtp_secure_media", "1"); - switch_core_hash_insert(filter, "rtp_secure_media_confirmed", "1"); - switch_core_hash_insert(filter, "rtp_secure_media_confirmed_audio", "1"); - switch_core_hash_insert(filter, "rtp_secure_media_confirmed_video", "1"); - switch_core_hash_insert(filter, "zrtp_secure_media", "1"); - switch_core_hash_insert(filter, "zrtp_secure_media_confirmed", "1"); - switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_audio", "1"); - switch_core_hash_insert(filter, "zrtp_secure_media_confirmed_video", "1"); - - /* Device Redirect headers */ - switch_core_hash_insert(filter, "variable_last_bridge_hangup_cause", "1"); - switch_core_hash_insert(filter, "variable_sip_redirected_by", "1"); - switch_core_hash_insert(filter, "intercepted_by", "1"); - switch_core_hash_insert(filter, "variable_bridge_uuid", "1"); - switch_core_hash_insert(filter, "Record-File-Path", "1"); - - /* Loopback headers */ - switch_core_hash_insert(filter, "variable_loopback_bowout_on_execute", "1"); - switch_core_hash_insert(filter, "variable_loopback_bowout", "1"); - switch_core_hash_insert(filter, "variable_other_loopback_leg_uuid", "1"); - switch_core_hash_insert(filter, "variable_loopback_leg", "1"); - switch_core_hash_insert(filter, "variable_is_loopback", "1"); - - // SMS - switch_core_hash_insert(filter, "Message-ID", "1"); - switch_core_hash_insert(filter, "Delivery-Failure", "1"); - switch_core_hash_insert(filter, "Delivery-Result-Code", "1"); - - return filter; -} - -static void *SWITCH_THREAD_FUNC fetch_config_filters_exec(switch_thread_t *thread, void *obj) +void kz_event_decode(switch_event_t *event) { - char *cf = "kazoo.conf"; - switch_xml_t cfg, xml, child, param; - switch_event_t *params; - switch_memory_pool_t *pool = (switch_memory_pool_t *)obj; - - switch_event_create(¶ms, SWITCH_EVENT_REQUEST_PARAMS); - switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "Action", "request-filter"); - - if (!(xml = switch_xml_open_cfg(cf, &cfg, params))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf); - } else if ((child = switch_xml_child(cfg, "event-filter"))) { - switch_hash_t *filter; - switch_hash_t *old_filter; - - switch_core_hash_init(&filter); - for (param = switch_xml_child(child, "header"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - switch_core_hash_insert(filter, var, "1"); + switch_event_header_t *hp; + int i; + for (hp = event->headers; hp; hp = hp->next) { + if (hp->idx) { + for(i = 0; i < hp->idx; i++) { + switch_url_decode(hp->array[i]); } + } else { + switch_url_decode(hp->value); + } + } +} - old_filter = kazoo_globals.event_filter; - kazoo_globals.config_filters_fetched = 1; - kazoo_globals.event_filter = filter; - if (old_filter) { - switch_core_hash_destroy(&old_filter); - } +char * kz_expand_vars(char *xml_str) { + return kz_expand_vars_pool(xml_str, NULL); +} - switch_xml_free(xml); +char * kz_expand_vars_pool(char *xml_str, switch_memory_pool_t *pool) { + char *var, *val; + char *rp = xml_str; /* read pointer */ + char *ep, *wp, *buff; /* end pointer, write pointer, write buffer */ + + if (!(strstr(xml_str, "$${"))) { + return xml_str; } - if (params) switch_event_destroy(¶ms); - switch_core_destroy_memory_pool(&pool); + switch_zmalloc(buff, strlen(xml_str) * 2); + wp = buff; + ep = buff + (strlen(xml_str) * 2) - 1; - return NULL; -} + while (*rp && wp < ep) { + if (*rp == '$' && *(rp + 1) == '$' && *(rp + 2) == '{') { + char *e = switch_find_end_paren(rp + 2, '{', '}'); -void fetch_config_filters() { - switch_memory_pool_t *pool; - switch_thread_t *thread; - switch_threadattr_t *thd_attr = NULL; - switch_uuid_t uuid; + if (e) { + rp += 3; + var = rp; + *e++ = '\0'; + rp = e; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "trying to expand %s \n", var); + if ((val = switch_core_get_variable_dup(var))) { + char *p; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "expanded %s to %s\n", var, val); + for (p = val; p && *p && wp <= ep; p++) { + *wp++ = *p; + } + switch_safe_free(val); + } + continue; + } + } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "fetching kazoo filters\n"); + *wp++ = *rp++; + } - switch_core_new_memory_pool(&pool); + *wp++ = '\0'; - switch_threadattr_create(&thd_attr, pool); - switch_threadattr_detach_set(thd_attr, 1); - switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - - switch_uuid_get(&uuid); - switch_thread_create(&thread, thd_attr, fetch_config_filters_exec, pool, pool); + if(pool) { + char * ret = switch_core_strdup(pool, buff); + switch_safe_free(buff); + return ret; + } else { + switch_safe_free(xml_str); + return buff; + } } - +switch_status_t kz_json_api(const char * command, cJSON *args, cJSON **res) +{ + switch_status_t status = SWITCH_STATUS_SUCCESS; + cJSON *req = cJSON_CreateObject(); + cJSON_AddItemToObject(req, "command", cJSON_CreateString(command)); + cJSON_AddItemToObject(req, "data", args ? args : cJSON_CreateObject()); + status = switch_json_api_execute(req, NULL, res); + cJSON_Delete(req); + return status; +} /* For Emacs: * Local Variables: diff --git a/src/mod/event_handlers/mod_kazoo/kz_node.c b/src/mod/event_handlers/mod_kazoo/kz_node.c new file mode 100644 index 0000000000..26c362980b --- /dev/null +++ b/src/mod/event_handlers/mod_kazoo/kz_node.c @@ -0,0 +1,91 @@ +#include "mod_kazoo.h" + +static int kz_nodes_module_names_array_callback(void *pArg, const char *module_name) +{ + cJSON *json = (cJSON *) pArg; + if(!strstr(module_name, "CORE")) { + cJSON_AddItemToArray(json, cJSON_CreateString(module_name)); + } + return 0; +} + +void kz_nodes_collect_media_role(cJSON *container) +{ + cJSON *retval = NULL; + if(kz_json_api("sofia.status.info", NULL, &retval) == SWITCH_STATUS_SUCCESS) { + if(retval != NULL && (!(retval->type & cJSON_NULL))) { + cJSON_AddItemToObject(container, "Media", cJSON_Duplicate(retval, 1)); + } + } + if(retval) { + cJSON_Delete(retval); + } +} + +void kz_nodes_collect_modules(cJSON *container) +{ + cJSON *modules = cJSON_CreateObject(); + cJSON *loaded = cJSON_CreateArray(); + cJSON *available = cJSON_CreateArray(); + switch_loadable_module_enumerate_available(SWITCH_GLOBAL_dirs.mod_dir, kz_nodes_module_names_array_callback, available); + switch_loadable_module_enumerate_loaded(kz_nodes_module_names_array_callback, loaded); + cJSON_AddItemToObject(modules, "available", available); + cJSON_AddItemToObject(modules, "loaded", loaded); + cJSON_AddItemToObject(container, "Modules", modules); +} + +void kz_nodes_collect_runtime(cJSON *container) +{ + cJSON *retval = NULL; + if(kz_json_api("status", NULL, &retval) == SWITCH_STATUS_SUCCESS) { + if(retval != NULL && (!(retval->type & cJSON_NULL))) { + cJSON *val = cJSON_Duplicate(retval, 1); + cJSON_AddItemToObject(val, "Core-UUID", cJSON_CreateString(switch_core_get_uuid())); + cJSON_AddItemToObject(container, "Runtime-Info", val); + } + } + if(retval) { + cJSON_Delete(retval); + } +} + +void kz_nodes_collect_apps(cJSON *container) +{ + cJSON *apps = cJSON_CreateObject(); + cJSON *app = cJSON_CreateObject(); + cJSON_AddItemToObject(app, "Uptime", cJSON_CreateNumber(switch_core_uptime())); + cJSON_AddItemToObject(apps, "freeswitch", app); + cJSON_AddItemToObject(container, "WhApps", apps); +} + +void kz_nodes_collect_roles(cJSON *container) +{ + cJSON *roles = cJSON_CreateObject(); + cJSON_AddItemToObject(container, "Roles", roles); + kz_nodes_collect_media_role(roles); +} + +cJSON * kz_node_create() +{ + cJSON *node = cJSON_CreateObject(); + + kz_nodes_collect_apps(node); + kz_nodes_collect_runtime(node); + kz_nodes_collect_modules(node); + kz_nodes_collect_roles(node); + + return node; +} + +SWITCH_STANDARD_JSON_API(kz_node_info_json_function) +{ + cJSON * ret = kz_node_create(); + *json_reply = ret; + return SWITCH_STATUS_SUCCESS; +} + +void add_kz_node(switch_loadable_module_interface_t **module_interface) +{ + switch_json_api_interface_t *json_api_interface = NULL; + SWITCH_ADD_JSON_API(json_api_interface, "node.info", "JSON node API", kz_node_info_json_function, ""); +} diff --git a/src/mod/event_handlers/mod_kazoo/mod_kazoo.c b/src/mod/event_handlers/mod_kazoo/mod_kazoo.c index b666920d3f..ca0538039b 100644 --- a/src/mod/event_handlers/mod_kazoo/mod_kazoo.c +++ b/src/mod/event_handlers/mod_kazoo/mod_kazoo.c @@ -32,608 +32,12 @@ */ #include "mod_kazoo.h" -#define KAZOO_DESC "kazoo information" -#define KAZOO_SYNTAX " []" +globals_t kazoo_globals = {0}; + -globals_t kazoo_globals; -SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load); -SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown); -SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime); SWITCH_MODULE_DEFINITION(mod_kazoo, mod_kazoo_load, mod_kazoo_shutdown, mod_kazoo_runtime); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ip, kazoo_globals.ip); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_cookie, kazoo_globals.ei_cookie); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_ei_nodename, kazoo_globals.ei_nodename); -SWITCH_DECLARE_GLOBAL_STRING_FUNC(set_pref_kazoo_var_prefix, kazoo_globals.kazoo_var_prefix); - -static switch_status_t api_erlang_status(switch_stream_handle_t *stream) { - switch_sockaddr_t *sa; - uint16_t port; - char ipbuf[48]; - const char *ip_addr; - ei_node_t *ei_node; - - switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor); - - port = switch_sockaddr_get_port(sa); - ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); - - stream->write_function(stream, "Running %s\n", VERSION); - stream->write_function(stream, "Listening for new Erlang connections on %s:%u with cookie %s\n", ip_addr, port, kazoo_globals.ei_cookie); - stream->write_function(stream, "Registered as Erlang node %s, visible as %s\n", kazoo_globals.ei_cnode.thisnodename, kazoo_globals.ei_cnode.thisalivename); - - if (kazoo_globals.ei_compat_rel) { - stream->write_function(stream, "Using Erlang compatibility mode: %d\n", kazoo_globals.ei_compat_rel); - } - - switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); - ei_node = kazoo_globals.ei_nodes; - if (!ei_node) { - stream->write_function(stream, "No erlang nodes connected\n"); - } else { - stream->write_function(stream, "Connected to:\n"); - while(ei_node != NULL) { - unsigned int year, day, hour, min, sec, delta; - - delta = (switch_micro_time_now() - ei_node->created_time) / 1000000; - sec = delta % 60; - min = delta / 60 % 60; - hour = delta / 3600 % 24; - day = delta / 86400 % 7; - year = delta / 31556926 % 12; - stream->write_function(stream, " %s (%s:%d) up %d years, %d days, %d hours, %d minutes, %d seconds\n" - ,ei_node->peer_nodename, ei_node->remote_ip, ei_node->remote_port, year, day, hour, min, sec); - ei_node = ei_node->next; - } - } - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t api_erlang_event_filter(switch_stream_handle_t *stream) { - switch_hash_index_t *hi = NULL; - int column = 0; - - for (hi = (switch_hash_index_t *)switch_core_hash_first_iter(kazoo_globals.event_filter, hi); hi; hi = switch_core_hash_next(&hi)) { - const void *key; - void *val; - switch_core_hash_this(hi, &key, NULL, &val); - stream->write_function(stream, "%-50s", (char *)key); - if (++column > 2) { - stream->write_function(stream, "\n"); - column = 0; - } - } - - if (++column > 2) { - stream->write_function(stream, "\n"); - column = 0; - } - - stream->write_function(stream, "%-50s", kazoo_globals.kazoo_var_prefix); - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t api_erlang_nodes_list(switch_stream_handle_t *stream) { - ei_node_t *ei_node; - - switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); - ei_node = kazoo_globals.ei_nodes; - while(ei_node != NULL) { - stream->write_function(stream, "%s (%s)\n", ei_node->peer_nodename, ei_node->remote_ip); - ei_node = ei_node->next; - } - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t api_erlang_nodes_count(switch_stream_handle_t *stream) { - ei_node_t *ei_node; - int count = 0; - - switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); - ei_node = kazoo_globals.ei_nodes; - while(ei_node != NULL) { - count++; - ei_node = ei_node->next; - } - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - - stream->write_function(stream, "%d\n", count); - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t api_complete_erlang_node(const char *line, const char *cursor, switch_console_callback_match_t **matches) { - switch_console_callback_match_t *my_matches = NULL; - switch_status_t status = SWITCH_STATUS_FALSE; - ei_node_t *ei_node; - - switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); - ei_node = kazoo_globals.ei_nodes; - while(ei_node != NULL) { - switch_console_push_match(&my_matches, ei_node->peer_nodename); - ei_node = ei_node->next; - } - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - - if (my_matches) { - *matches = my_matches; - status = SWITCH_STATUS_SUCCESS; - } - - return status; -} - -static switch_status_t handle_node_api_event_stream(ei_event_stream_t *event_stream, switch_stream_handle_t *stream) { - ei_event_binding_t *binding; - int column = 0; - - switch_mutex_lock(event_stream->socket_mutex); - if (event_stream->connected == SWITCH_FALSE) { - switch_sockaddr_t *sa; - uint16_t port; - char ipbuf[48] = {0}; - const char *ip_addr; - - switch_socket_addr_get(&sa, SWITCH_TRUE, event_stream->acceptor); - port = switch_sockaddr_get_port(sa); - ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); - - if (zstr(ip_addr)) { - ip_addr = kazoo_globals.ip; - } - - stream->write_function(stream, "%s:%d -> disconnected\n" - ,ip_addr, port); - } else { - stream->write_function(stream, "%s:%d -> %s:%d\n" - ,event_stream->local_ip, event_stream->local_port - ,event_stream->remote_ip, event_stream->remote_port); - } - - binding = event_stream->bindings; - while(binding != NULL) { - if (binding->type == SWITCH_EVENT_CUSTOM) { - stream->write_function(stream, "CUSTOM %-43s", binding->subclass_name); - } else { - stream->write_function(stream, "%-50s", switch_event_name(binding->type)); - } - - if (++column > 2) { - stream->write_function(stream, "\n"); - column = 0; - } - - binding = binding->next; - } - switch_mutex_unlock(event_stream->socket_mutex); - - if (!column) { - stream->write_function(stream, "\n"); - } else { - stream->write_function(stream, "\n\n"); - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t handle_node_api_event_streams(ei_node_t *ei_node, switch_stream_handle_t *stream) { - ei_event_stream_t *event_stream; - - switch_mutex_lock(ei_node->event_streams_mutex); - event_stream = ei_node->event_streams; - while(event_stream != NULL) { - handle_node_api_event_stream(event_stream, stream); - event_stream = event_stream->next; - } - switch_mutex_unlock(ei_node->event_streams_mutex); - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t handle_node_api_command(ei_node_t *ei_node, switch_stream_handle_t *stream, uint32_t command) { - unsigned int year, day, hour, min, sec, delta; - - switch (command) { - case API_COMMAND_DISCONNECT: - stream->write_function(stream, "Disconnecting erlang node %s at managers request\n", ei_node->peer_nodename); - switch_clear_flag(ei_node, LFLAG_RUNNING); - break; - case API_COMMAND_REMOTE_IP: - delta = (switch_micro_time_now() - ei_node->created_time) / 1000000; - sec = delta % 60; - min = delta / 60 % 60; - hour = delta / 3600 % 24; - day = delta / 86400 % 7; - year = delta / 31556926 % 12; - - stream->write_function(stream, "Uptime %d years, %d days, %d hours, %d minutes, %d seconds\n", year, day, hour, min, sec); - stream->write_function(stream, "Local Address %s:%d\n", ei_node->local_ip, ei_node->local_port); - stream->write_function(stream, "Remote Address %s:%d\n", ei_node->remote_ip, ei_node->remote_port); - break; - case API_COMMAND_STREAMS: - handle_node_api_event_streams(ei_node, stream); - break; - case API_COMMAND_BINDINGS: - handle_api_command_streams(ei_node, stream); - break; - default: - break; - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t api_erlang_node_command(switch_stream_handle_t *stream, const char *nodename, uint32_t command) { - ei_node_t *ei_node; - - switch_thread_rwlock_rdlock(kazoo_globals.ei_nodes_lock); - ei_node = kazoo_globals.ei_nodes; - while(ei_node != NULL) { - int length = strlen(ei_node->peer_nodename); - - if (!strncmp(ei_node->peer_nodename, nodename, length)) { - handle_node_api_command(ei_node, stream, command); - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - return SWITCH_STATUS_SUCCESS; - } - - ei_node = ei_node->next; - } - switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); - - return SWITCH_STATUS_NOTFOUND; -} - -static int read_cookie_from_file(char *filename) { - int fd; - char cookie[MAXATOMLEN + 1]; - char *end; - struct stat buf; - ssize_t res; - - if (!stat(filename, &buf)) { - if ((buf.st_mode & S_IRWXG) || (buf.st_mode & S_IRWXO)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s must only be accessible by owner only.\n", filename); - return 2; - } - if (buf.st_size > MAXATOMLEN) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s contains a cookie larger than the maximum atom size of %d.\n", filename, MAXATOMLEN); - return 2; - } - fd = open(filename, O_RDONLY); - if (fd < 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to open cookie file %s : %d.\n", filename, errno); - return 2; - } - - if ((res = read(fd, cookie, MAXATOMLEN)) < 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie file %s : %d.\n", filename, errno); - } - - cookie[MAXATOMLEN] = '\0'; - - /* replace any end of line characters with a null */ - if ((end = strchr(cookie, '\n'))) { - *end = '\0'; - } - - if ((end = strchr(cookie, '\r'))) { - *end = '\0'; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie from file %s: %s\n", filename, cookie); - - set_pref_ei_cookie(cookie); - return 0; - } else { - /* don't error here, because we might be blindly trying to read $HOME/.erlang.cookie, and that can fail silently */ - return 1; - } -} - -static switch_status_t config(void) { - char *cf = "kazoo.conf"; - switch_xml_t cfg, xml, child, param; - kazoo_globals.send_all_headers = 0; - kazoo_globals.send_all_private_headers = 1; - kazoo_globals.connection_timeout = 500; - kazoo_globals.receive_timeout = 200; - kazoo_globals.receive_msg_preallocate = 2000; - kazoo_globals.event_stream_preallocate = 4000; - kazoo_globals.send_msg_batch = 10; - kazoo_globals.event_stream_framing = 2; - kazoo_globals.port = 0; - kazoo_globals.io_fault_tolerance = 10; - - if (!(xml = switch_xml_open_cfg(cf, &cfg, NULL))) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Failed to open configuration file %s\n", cf); - return SWITCH_STATUS_FALSE; - } else { - if ((child = switch_xml_child(cfg, "settings"))) { - for (param = switch_xml_child(child, "param"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - char *val = (char *) switch_xml_attr_soft(param, "value"); - - if (!strcmp(var, "listen-ip")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind ip address: %s\n", val); - set_pref_ip(val); - } else if (!strcmp(var, "listen-port")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set bind port: %s\n", val); - kazoo_globals.port = atoi(val); - } else if (!strcmp(var, "cookie")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set cookie: %s\n", val); - set_pref_ei_cookie(val); - } else if (!strcmp(var, "cookie-file")) { - if (read_cookie_from_file(val) == 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to read cookie from %s\n", val); - } - } else if (!strcmp(var, "nodename")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set node name: %s\n", val); - set_pref_ei_nodename(val); - } else if (!strcmp(var, "shortname")) { - kazoo_globals.ei_shortname = switch_true(val); - } else if (!strcmp(var, "kazoo-var-prefix")) { - set_pref_kazoo_var_prefix(val); - } else if (!strcmp(var, "compat-rel")) { - if (atoi(val) >= 7) - kazoo_globals.ei_compat_rel = atoi(val); - else - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Invalid compatibility release '%s' specified\n", val); - } else if (!strcmp(var, "nat-map")) { - kazoo_globals.nat_map = switch_true(val); - } else if (!strcmp(var, "send-all-headers")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-headers: %s\n", val); - kazoo_globals.send_all_headers = switch_true(val); - } else if (!strcmp(var, "send-all-private-headers")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-all-private-headers: %s\n", val); - kazoo_globals.send_all_private_headers = switch_true(val); - } else if (!strcmp(var, "connection-timeout")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set connection-timeout: %s\n", val); - kazoo_globals.connection_timeout = atoi(val); - } else if (!strcmp(var, "receive-timeout")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-timeout: %s\n", val); - kazoo_globals.receive_timeout = atoi(val); - } else if (!strcmp(var, "receive-msg-preallocate")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set receive-msg-preallocate: %s\n", val); - kazoo_globals.receive_msg_preallocate = atoi(val); - } else if (!strcmp(var, "event-stream-preallocate")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-preallocate: %s\n", val); - kazoo_globals.event_stream_preallocate = atoi(val); - } else if (!strcmp(var, "send-msg-batch-size")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set send-msg-batch-size: %s\n", val); - kazoo_globals.send_msg_batch = atoi(val); - } else if (!strcmp(var, "event-stream-framing")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set event-stream-framing: %s\n", val); - kazoo_globals.event_stream_framing = atoi(val); - } else if (!strcmp(var, "io-fault-tolerance")) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Set io-fault-tolerance: %s\n", val); - kazoo_globals.io_fault_tolerance = atoi(val); - } - } - } - - if ((child = switch_xml_child(cfg, "event-filter"))) { - switch_hash_t *filter; - - switch_core_hash_init(&filter); - for (param = switch_xml_child(child, "header"); param; param = param->next) { - char *var = (char *) switch_xml_attr_soft(param, "name"); - switch_core_hash_insert(filter, var, "1"); - } - - kazoo_globals.event_filter = filter; - } - - switch_xml_free(xml); - } - - if (kazoo_globals.receive_msg_preallocate < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid receive message preallocate value, disabled\n"); - kazoo_globals.receive_msg_preallocate = 0; - } - - if (kazoo_globals.event_stream_preallocate < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream preallocate value, disabled\n"); - kazoo_globals.event_stream_preallocate = 0; - } - - if (kazoo_globals.send_msg_batch < 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid send message batch size, reverting to default\n"); - kazoo_globals.send_msg_batch = 10; - } - - if (kazoo_globals.io_fault_tolerance < 1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid I/O fault tolerance, reverting to default\n"); - kazoo_globals.io_fault_tolerance = 10; - } - - if (!kazoo_globals.event_filter) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Event filter not found in configuration, using default\n"); - kazoo_globals.event_filter = create_default_filter(); - } - - if (kazoo_globals.event_stream_framing < 1 || kazoo_globals.event_stream_framing > 4) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid event stream framing value, using default\n"); - kazoo_globals.event_stream_framing = 2; - } - - if (zstr(kazoo_globals.kazoo_var_prefix)) { - set_pref_kazoo_var_prefix("variable_ecallmgr*"); - kazoo_globals.var_prefix_length = 17; //ignore the * - } else { - /* we could use the global pool but then we would have to conditionally - * free the pointer if it was not drawn from the XML */ - char *buf; - int size = switch_snprintf(NULL, 0, "variable_%s*", kazoo_globals.kazoo_var_prefix) + 1; - - switch_malloc(buf, size); - switch_snprintf(buf, size, "variable_%s*", kazoo_globals.kazoo_var_prefix); - switch_safe_free(kazoo_globals.kazoo_var_prefix); - kazoo_globals.kazoo_var_prefix = buf; - kazoo_globals.var_prefix_length = size - 2; //ignore the * - } - - if (!kazoo_globals.num_worker_threads) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Number of worker threads not found in configuration, using default\n"); - kazoo_globals.num_worker_threads = 10; - } - - if (zstr(kazoo_globals.ip)) { - set_pref_ip("0.0.0.0"); - } - - if (zstr(kazoo_globals.ei_cookie)) { - int res; - char *home_dir = getenv("HOME"); - char path_buf[1024]; - - if (!zstr(home_dir)) { - /* $HOME/.erlang.cookie */ - switch_snprintf(path_buf, sizeof (path_buf), "%s%s%s", home_dir, SWITCH_PATH_SEPARATOR, ".erlang.cookie"); - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Checking for cookie at path: %s\n", path_buf); - - res = read_cookie_from_file(path_buf); - if (res) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "No cookie or valid cookie file specified, using default cookie\n"); - set_pref_ei_cookie("ClueCon"); - } - } - } - - if (!kazoo_globals.ei_nodename) { - set_pref_ei_nodename("freeswitch"); - } - - if (!kazoo_globals.nat_map) { - kazoo_globals.nat_map = 0; - } - - return SWITCH_STATUS_SUCCESS; -} - -static switch_status_t create_acceptor() { - switch_sockaddr_t *sa; - uint16_t port; - char ipbuf[48]; - const char *ip_addr; - - /* if the config has specified an erlang release compatibility then pass that along to the erlang interface */ - if (kazoo_globals.ei_compat_rel) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Compatability with OTP R%d requested\n", kazoo_globals.ei_compat_rel); - ei_set_compat_rel(kazoo_globals.ei_compat_rel); - } - - if (!(kazoo_globals.acceptor = create_socket_with_port(kazoo_globals.pool, kazoo_globals.port))) { - return SWITCH_STATUS_SOCKERR; - } - - switch_socket_addr_get(&sa, SWITCH_FALSE, kazoo_globals.acceptor); - - port = switch_sockaddr_get_port(sa); - ip_addr = switch_get_addr(ipbuf, sizeof (ipbuf), sa); - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor listening on %s:%u\n", ip_addr, port); - - /* try to initialize the erlang interface */ - if (create_ei_cnode(ip_addr, kazoo_globals.ei_nodename, &kazoo_globals.ei_cnode) != SWITCH_STATUS_SUCCESS) { - return SWITCH_STATUS_SOCKERR; - } - - /* tell the erlang port manager where we can be reached. this returns a file descriptor pointing to epmd or -1 */ - if ((kazoo_globals.epmdfd = ei_publish(&kazoo_globals.ei_cnode, port)) == -1) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, - "Failed to publish port to epmd. Try starting it yourself or run an erl shell with the -sname or -name option.\n"); - return SWITCH_STATUS_SOCKERR; - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Connected to epmd and published erlang cnode name %s at port %d\n", kazoo_globals.ei_cnode.thisnodename, port); - - return SWITCH_STATUS_SUCCESS; -} - -SWITCH_STANDARD_API(exec_api_cmd) -{ - char *argv[1024] = { 0 }; - int unknown_command = 1, argc = 0; - char *mycmd = NULL; - - const char *usage_string = "USAGE:\n" - "--------------------------------------------------------------------------------------------------------------------\n" - "erlang status - provides an overview of the current status\n" - "erlang event_filter - lists the event headers that will be sent to Erlang nodes\n" - "erlang nodes list - lists connected Erlang nodes (usefull for monitoring tools)\n" - "erlang nodes count - provides a count of connected Erlang nodes (usefull for monitoring tools)\n" - "erlang node disconnect - disconnects an Erlang node\n" - "erlang node connection - Shows the connection info\n" - "erlang node event_streams - lists the event streams for an Erlang node\n" - "erlang node fetch_bindings - lists the XML fetch bindings for an Erlang node\n" - "---------------------------------------------------------------------------------------------------------------------\n"; - - if (zstr(cmd)) { - stream->write_function(stream, "%s", usage_string); - return SWITCH_STATUS_SUCCESS; - } - - if (!(mycmd = strdup(cmd))) { - return SWITCH_STATUS_MEMERR; - } - - if (!(argc = switch_separate_string(mycmd, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { - stream->write_function(stream, "%s", usage_string); - switch_safe_free(mycmd); - return SWITCH_STATUS_SUCCESS; - } - - if (zstr(argv[0])) { - stream->write_function(stream, "%s", usage_string); - switch_safe_free(mycmd); - return SWITCH_STATUS_SUCCESS; - } - - if (!strncmp(argv[0], "status", 6)) { - unknown_command = 0; - api_erlang_status(stream); - } else if (!strncmp(argv[0], "event_filter", 6)) { - unknown_command = 0; - api_erlang_event_filter(stream); - } else if (!strncmp(argv[0], "nodes", 6) && !zstr(argv[1])) { - if (!strncmp(argv[1], "list", 6)) { - unknown_command = 0; - api_erlang_nodes_list(stream); - } else if (!strncmp(argv[1], "count", 6)) { - unknown_command = 0; - api_erlang_nodes_count(stream); - } - } else if (!strncmp(argv[0], "node", 6) && !zstr(argv[1]) && !zstr(argv[2])) { - if (!strncmp(argv[2], "disconnect", 6)) { - unknown_command = 0; - api_erlang_node_command(stream, argv[1], API_COMMAND_DISCONNECT); - } else if (!strncmp(argv[2], "connection", 2)) { - unknown_command = 0; - api_erlang_node_command(stream, argv[1], API_COMMAND_REMOTE_IP); - } else if (!strncmp(argv[2], "event_streams", 6)) { - unknown_command = 0; - api_erlang_node_command(stream, argv[1], API_COMMAND_STREAMS); - } else if (!strncmp(argv[2], "fetch_bindings", 6)) { - unknown_command = 0; - api_erlang_node_command(stream, argv[1], API_COMMAND_BINDINGS); - } - } - - if (unknown_command) { - stream->write_function(stream, "%s", usage_string); - } - - switch_safe_free(mycmd); - return SWITCH_STATUS_SUCCESS; -} - SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load) { switch_api_interface_t *api_interface = NULL; switch_application_interface_t *app_interface = NULL; @@ -643,34 +47,17 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load) { kazoo_globals.pool = pool; kazoo_globals.ei_nodes = NULL; - if(config() != SWITCH_STATUS_SUCCESS) { + // ensure epmd is running + + if(kazoo_load_config() != SWITCH_STATUS_SUCCESS) { // TODO: what would we need to clean up here? switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Improper configuration!\n"); return SWITCH_STATUS_TERM; } - if(create_acceptor() != SWITCH_STATUS_SUCCESS) { - // TODO: what would we need to clean up here - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Unable to create erlang connection acceptor!\n"); - close_socket(&kazoo_globals.acceptor); - return SWITCH_STATUS_TERM; - } - /* connect my internal structure to the blank pointer passed to me */ *module_interface = switch_loadable_module_create_module_interface(pool, modname); - /* create an api for cli debug commands */ - SWITCH_ADD_API(api_interface, "erlang", KAZOO_DESC, exec_api_cmd, KAZOO_SYNTAX); - switch_console_set_complete("add erlang status"); - switch_console_set_complete("add erlang event_filter"); - switch_console_set_complete("add erlang nodes list"); - switch_console_set_complete("add erlang nodes count"); - switch_console_set_complete("add erlang node ::erlang::node disconnect"); - switch_console_set_complete("add erlang node ::erlang::node connection"); - switch_console_set_complete("add erlang node ::erlang::node event_streams"); - switch_console_set_complete("add erlang node ::erlang::node fetch_bindings"); - switch_console_add_complete_func("::erlang::node", api_complete_erlang_node); - switch_thread_rwlock_create(&kazoo_globals.ei_nodes_lock, pool); switch_set_flag(&kazoo_globals, LFLAG_RUNNING); @@ -678,12 +65,24 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load) { /* create all XML fetch agents */ bind_fetch_agents(); + /* create an api for cli debug commands */ + add_cli_api(module_interface, api_interface); + /* add our modified commands */ add_kz_commands(module_interface, api_interface); /* add our modified dptools */ add_kz_dptools(module_interface, app_interface); + /* add our endpoints */ + add_kz_endpoints(module_interface); + + /* add our kz_node api */ + add_kz_node(module_interface); + + /* add tweaks */ + kz_tweaks_start(); + /* indicate that the module should continue to be loaded */ return SWITCH_STATUS_SUCCESS; } @@ -691,8 +90,10 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load) { SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown) { int sanity = 0; - switch_console_set_complete("del erlang"); - switch_console_del_complete_func("::erlang::node"); + + remove_cli_api(); + + kz_tweaks_stop(); /* stop taking new requests and start shuting down the threads */ switch_clear_flag(&kazoo_globals, LFLAG_RUNNING); @@ -706,6 +107,13 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown) { } } + /* close the connection to epmd and the acceptor */ + close_socketfd(&kazoo_globals.epmdfd); + close_socket(&kazoo_globals.acceptor); + + /* remove all XML fetch agents */ + unbind_fetch_agents(); + if (kazoo_globals.event_filter) { switch_core_hash_destroy(&kazoo_globals.event_filter); } @@ -714,71 +122,21 @@ SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown) { switch_thread_rwlock_unlock(kazoo_globals.ei_nodes_lock); switch_thread_rwlock_destroy(kazoo_globals.ei_nodes_lock); - /* close the connection to epmd and the acceptor */ - close_socketfd(&kazoo_globals.epmdfd); - close_socket(&kazoo_globals.acceptor); - - /* remove all XML fetch agents */ - unbind_fetch_agents(); - /* Close the port we reserved for uPnP/Switch behind firewall, if necessary */ - // if (kazoo_globals.nat_map && switch_nat_get_type()) { - // switch_nat_del_mapping(kazoo_globals.port, SWITCH_NAT_TCP); - // } + if (kazoo_globals.nat_map && switch_nat_get_type()) { + switch_nat_del_mapping(kazoo_globals.port, SWITCH_NAT_TCP); + } + + kazoo_destroy_config(); /* clean up our allocated preferences */ switch_safe_free(kazoo_globals.ip); switch_safe_free(kazoo_globals.ei_cookie); switch_safe_free(kazoo_globals.ei_nodename); - switch_safe_free(kazoo_globals.kazoo_var_prefix); return SWITCH_STATUS_SUCCESS; } -SWITCH_MODULE_RUNTIME_FUNCTION(mod_kazoo_runtime) { - switch_os_socket_t os_socket; - - switch_atomic_inc(&kazoo_globals.threads); - - switch_os_sock_get(&os_socket, kazoo_globals.acceptor); - - while (switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { - int nodefd; - ErlConnect conn; - - /* zero out errno because ei_accept doesn't differentiate between a */ - /* failed authentication or a socket failure, or a client version */ - /* mismatch or a godzilla attack (and a godzilla attack is highly likely) */ - errno = 0; - - /* wait here for an erlang node to connect, timming out to check if our module is still running every now-and-again */ - if ((nodefd = ei_accept_tmo(&kazoo_globals.ei_cnode, (int) os_socket, &conn, kazoo_globals.connection_timeout)) == ERL_ERROR) { - if (erl_errno == ETIMEDOUT) { - continue; - } else if (errno) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Erlang connection acceptor socket error %d %d\n", erl_errno, errno); - } else { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, - "Erlang node connection failed - ensure your cookie matches '%s' and you are using a good nodename\n", kazoo_globals.ei_cookie); - } - continue; - } - - if (!switch_test_flag(&kazoo_globals, LFLAG_RUNNING)) { - break; - } - - /* NEW ERLANG NODE CONNECTION! Hello friend! */ - new_kazoo_node(nodefd, &conn); - } - - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Erlang connection acceptor shut down\n"); - - switch_atomic_dec(&kazoo_globals.threads); - - return SWITCH_STATUS_TERM; -} - /* For Emacs: * Local Variables: diff --git a/src/mod/event_handlers/mod_kazoo/mod_kazoo.h b/src/mod/event_handlers/mod_kazoo/mod_kazoo.h index 9de7db6ea0..1fc12ba2aa 100644 --- a/src/mod/event_handlers/mod_kazoo/mod_kazoo.h +++ b/src/mod/event_handlers/mod_kazoo/mod_kazoo.h @@ -1,167 +1,29 @@ #include #include +#include #include #include #include #include #include +#include #define MAX_ACL 100 #define CMD_BUFLEN 1024 * 1000 #define MAX_QUEUE_LEN 25000 #define MAX_MISSED 500 #define MAX_PID_CHARS 255 -#define VERSION "mod_kazoo v1.4.0-1" -#define API_COMMAND_DISCONNECT 0 -#define API_COMMAND_REMOTE_IP 1 -#define API_COMMAND_STREAMS 2 -#define API_COMMAND_BINDINGS 3 +extern const char kz_default_config[]; +extern const int kz_default_config_size; + +#include "kazoo_ei.h" +#include "kazoo_message.h" typedef enum { LFLAG_RUNNING = (1 << 0) } event_flag_t; -struct ei_send_msg_s { - ei_x_buff buf; - erlang_pid pid; -}; -typedef struct ei_send_msg_s ei_send_msg_t; - -struct ei_received_msg_s { - ei_x_buff buf; - erlang_msg msg; -}; -typedef struct ei_received_msg_s ei_received_msg_t; - -struct ei_event_binding_s { - char id[SWITCH_UUID_FORMATTED_LENGTH + 1]; - switch_event_node_t *node; - switch_event_types_t type; - const char *subclass_name; - struct ei_event_binding_s *next; -}; -typedef struct ei_event_binding_s ei_event_binding_t; - -struct ei_event_stream_s { - switch_memory_pool_t *pool; - ei_event_binding_t *bindings; - switch_queue_t *queue; - switch_socket_t *acceptor; - switch_pollset_t *pollset; - switch_pollfd_t *pollfd; - switch_socket_t *socket; - switch_mutex_t *socket_mutex; - switch_bool_t connected; - char remote_ip[48]; - uint16_t remote_port; - char local_ip[48]; - uint16_t local_port; - erlang_pid pid; - uint32_t flags; - struct ei_event_stream_s *next; -}; -typedef struct ei_event_stream_s ei_event_stream_t; - -struct ei_node_s { - int nodefd; - switch_atomic_t pending_bgapi; - switch_atomic_t receive_handlers; - switch_memory_pool_t *pool; - ei_event_stream_t *event_streams; - switch_mutex_t *event_streams_mutex; - switch_queue_t *send_msgs; - switch_queue_t *received_msgs; - char *peer_nodename; - switch_time_t created_time; - switch_socket_t *socket; - char remote_ip[48]; - uint16_t remote_port; - char local_ip[48]; - uint16_t local_port; - uint32_t flags; - struct ei_node_s *next; -}; -typedef struct ei_node_s ei_node_t; - -struct globals_s { - switch_memory_pool_t *pool; - switch_atomic_t threads; - switch_socket_t *acceptor; - struct ei_cnode_s ei_cnode; - switch_thread_rwlock_t *ei_nodes_lock; - ei_node_t *ei_nodes; - switch_xml_binding_t *config_fetch_binding; - switch_xml_binding_t *directory_fetch_binding; - switch_xml_binding_t *dialplan_fetch_binding; - switch_xml_binding_t *chatplan_fetch_binding; - switch_xml_binding_t *channels_fetch_binding; - switch_hash_t *event_filter; - int epmdfd; - int num_worker_threads; - switch_bool_t nat_map; - switch_bool_t ei_shortname; - int ei_compat_rel; - char *ip; - char *hostname; - char *ei_cookie; - char *ei_nodename; - char *kazoo_var_prefix; - int var_prefix_length; - uint32_t flags; - int send_all_headers; - int send_all_private_headers; - int connection_timeout; - int receive_timeout; - int receive_msg_preallocate; - int event_stream_preallocate; - int send_msg_batch; - short event_stream_framing; - switch_port_t port; - int config_filters_fetched; - int io_fault_tolerance; -}; -typedef struct globals_s globals_t; -extern globals_t kazoo_globals; - -/* kazoo_node.c */ -switch_status_t new_kazoo_node(int nodefd, ErlConnect *conn); - -/* kazoo_event_stream.c */ -ei_event_stream_t *find_event_stream(ei_event_stream_t *event_streams, const erlang_pid *from); -ei_event_stream_t *new_event_stream(ei_event_stream_t **event_streams, const erlang_pid *from); -switch_status_t remove_event_stream(ei_event_stream_t **event_streams, const erlang_pid *from); -switch_status_t remove_event_streams(ei_event_stream_t **event_streams); -unsigned long get_stream_port(const ei_event_stream_t *event_stream); -switch_status_t add_event_binding(ei_event_stream_t *event_stream, const switch_event_types_t event_type, const char *subclass_name); -switch_status_t remove_event_binding(ei_event_stream_t *event_stream, const switch_event_types_t event_type, const char *subclass_name); -switch_status_t remove_event_bindings(ei_event_stream_t *event_stream); - -/* kazoo_fetch_agent.c */ -switch_status_t bind_fetch_agents(); -switch_status_t unbind_fetch_agents(); -switch_status_t remove_xml_clients(ei_node_t *ei_node); -switch_status_t add_fetch_handler(ei_node_t *ei_node, erlang_pid *from, switch_xml_binding_t *binding); -switch_status_t remove_fetch_handlers(ei_node_t *ei_node, erlang_pid *from); -switch_status_t fetch_reply(char *uuid_str, char *xml_str, switch_xml_binding_t *binding); -switch_status_t handle_api_command_streams(ei_node_t *ei_node, switch_stream_handle_t *stream); - -/* kazoo_utils.c */ -void close_socket(switch_socket_t **sock); -void close_socketfd(int *sockfd); -switch_socket_t *create_socket_with_port(switch_memory_pool_t *pool, switch_port_t port); -switch_socket_t *create_socket(switch_memory_pool_t *pool); -switch_status_t create_ei_cnode(const char *ip_addr, const char *name, struct ei_cnode_s *ei_cnode); -switch_status_t ei_compare_pids(const erlang_pid *pid1, const erlang_pid *pid2); -void ei_encode_switch_event_headers(ei_x_buff *ebuf, switch_event_t *event); -void ei_encode_switch_event_headers_2(ei_x_buff *ebuf, switch_event_t *event, int decode); -void ei_link(ei_node_t *ei_node, erlang_pid * from, erlang_pid * to); -void ei_encode_switch_event(ei_x_buff * ebuf, switch_event_t *event); -int ei_helper_send(ei_node_t *ei_node, erlang_pid* to, ei_x_buff *buf); -int ei_decode_atom_safe(char *buf, int *index, char *dst); -int ei_decode_string_or_binary_limited(char *buf, int *index, int maxsize, char *dst); -int ei_decode_string_or_binary(char *buf, int *index, char **dst); -switch_hash_t *create_default_filter(); /* kazoo_commands.c */ void add_kz_commands(switch_loadable_module_interface_t **module_interface, switch_api_interface_t *api_interface); @@ -169,9 +31,41 @@ void add_kz_commands(switch_loadable_module_interface_t **module_interface, swit /* kazoo_dptools.c */ void add_kz_dptools(switch_loadable_module_interface_t **module_interface, switch_application_interface_t *app_interface); -#define _ei_x_encode_string(buf, string) { ei_x_encode_binary(buf, string, strlen(string)); } +/* kazoo_api.c */ +void add_cli_api(switch_loadable_module_interface_t **module_interface, switch_api_interface_t *api_interface); +void remove_cli_api(); + +/* kazoo_utils.c */ +SWITCH_DECLARE(switch_status_t) kz_switch_core_merge_variables(switch_event_t *event); +SWITCH_DECLARE(switch_status_t) kz_switch_core_base_headers_for_expand(switch_event_t **event); +void kz_check_set_profile_var(switch_channel_t *channel, char* var, char *val); +char* kz_switch_event_get_first_of(switch_event_t *event, const char *list[]); +SWITCH_DECLARE(switch_status_t) kz_switch_event_add_variable_name_printf(switch_event_t *event, switch_stack_t stack, const char *val, const char *fmt, ...); +void kz_xml_process(switch_xml_t cfg); +void kz_event_decode(switch_event_t *event); +char * kz_expand_vars(char *xml_str); +char * kz_expand_vars_pool(char *xml_str, switch_memory_pool_t *pool); +SWITCH_DECLARE(char *) kz_event_expand_headers(switch_event_t *event, const char *in); +SWITCH_DECLARE(char *) kz_expand(const char *in); +SWITCH_DECLARE(char *) kz_expand_pool(switch_memory_pool_t *pool, const char *in); +switch_status_t kz_json_api(const char * command, cJSON *args, cJSON **res); + +/* kazoo_endpoints.c */ +void add_kz_endpoints(switch_loadable_module_interface_t **module_interface); + + +/* kazoo_tweaks.c */ +void kz_tweaks_start(); +void kz_tweaks_stop(); +SWITCH_DECLARE(const char *) kz_tweak_name(kz_tweak_t tweak); +SWITCH_DECLARE(switch_status_t) kz_name_tweak(const char *name, kz_tweak_t *type); + +/* kazoo_node.c */ +void add_kz_node(switch_loadable_module_interface_t **module_interface); + +SWITCH_MODULE_LOAD_FUNCTION(mod_kazoo_load); +SWITCH_MODULE_SHUTDOWN_FUNCTION(mod_kazoo_shutdown); -void fetch_config_filters(); /* For Emacs: * Local Variables: diff --git a/src/mod/event_handlers/mod_rayo/mod_rayo.c b/src/mod/event_handlers/mod_rayo/mod_rayo.c index 92699ca843..9ef5b8c913 100644 --- a/src/mod/event_handlers/mod_rayo/mod_rayo.c +++ b/src/mod/event_handlers/mod_rayo/mod_rayo.c @@ -468,6 +468,8 @@ static const char *switch_cause_to_rayo_cause(switch_call_cause_t cause) case SWITCH_CAUSE_NO_PICKUP: case SWITCH_CAUSE_SRTP_READ_ERROR: return RAYO_END_REASON_ERROR; + default: + break; } return RAYO_END_REASON_HANGUP; } diff --git a/src/mod/formats/mod_opusfile/Makefile.am b/src/mod/formats/mod_opusfile/Makefile.am new file mode 100644 index 0000000000..abf251e700 --- /dev/null +++ b/src/mod/formats/mod_opusfile/Makefile.am @@ -0,0 +1,19 @@ +include $(top_srcdir)/build/modmake.rulesam +MODNAME=mod_opusfile + +mod_LTLIBRARIES = mod_opusfile.la +mod_opusfile_la_SOURCES = mod_opusfile.c +mod_opusfile_la_CFLAGS = $(AM_CFLAGS) +mod_opusfile_la_LIBADD = $(switch_builddir)/libfreeswitch.la +mod_opusfile_la_LDFLAGS = -avoid-version -module -no-undefined -shared + +if HAVE_OPUSFILE_DECODE +mod_opusfile_la_CFLAGS += $(OPUSFILE_DECODE_CFLAGS) +mod_opusfile_la_LIBADD += $(OPUSFILE_DECODE_LIBS) +endif + +if HAVE_OPUSFILE_ENCODE +mod_opusfile_la_CFLAGS += $(OPUSFILE_ENCODE_CFLAGS) -DHAVE_OPUSFILE_ENCODE +mod_opusfile_la_LIBADD += $(OPUSFILE_ENCODE_LIBS) +endif + diff --git a/src/mod/formats/mod_opusfile/mod_opusfile.c b/src/mod/formats/mod_opusfile/mod_opusfile.c new file mode 100644 index 0000000000..418628b8e4 --- /dev/null +++ b/src/mod/formats/mod_opusfile/mod_opusfile.c @@ -0,0 +1,533 @@ +/* + * FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * Copyright (C) 2005-2014, Anthony Minessale II + * + * Version: MPL 1.1 + * + * The contents of this file are subject to the Mozilla Public License Version + * 1.1 (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * http://www.mozilla.org/MPL/ + * + * Software distributed under the License is distributed on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License + * for the specific language governing rights and limitations under the + * License. + * + * The Original Code is FreeSWITCH Modular Media Switching Software Library / Soft-Switch Application + * + * The Initial Developer of the Original Code is + * Anthony Minessale II + * Portions created by the Initial Developer are Copyright (C) + * the Initial Developer. All Rights Reserved. + * + * Contributor(s): + * + * Dragos Oancea (mod_opusfile.c) + * + * + * mod_opusfile.c -- Read and Write OGG/Opus files . Some parts inspired from mod_shout.c, libopusfile, libopusenc + * + */ +#include + +#include + +#ifdef HAVE_OPUSFILE_ENCODE +#include +#endif + +#define OPUSFILE_MAX 32*1024 +#define TC_BUFFER_SIZE 1024 * 256 /* max ammount of decoded audio we can have at a time (bytes)*/ +#define DEFAULT_RATE 48000 /* default fullband */ +#define OPUS_MAX_PCM 5760 /* opus recommended max output buf */ + +//#undef HAVE_OPUSFILE_ENCODE /*don't encode anything */ + +SWITCH_MODULE_LOAD_FUNCTION(mod_opusfile_load); +SWITCH_MODULE_DEFINITION(mod_opusfile, mod_opusfile_load, NULL, NULL); + +struct opus_file_context { + switch_file_t *fd; + OggOpusFile *of; + ogg_int64_t duration; + int output_seekable; + ogg_int64_t pcm_offset; + ogg_int64_t pcm_print_offset; + ogg_int64_t next_pcm_offset; + ogg_int64_t nsamples; + opus_int32 bitrate; + int li; + int prev_li; + switch_mutex_t *audio_mutex; + switch_buffer_t *audio_buffer; + switch_mutex_t *ogg_mutex; + switch_buffer_t *ogg_buffer; + opus_int16 decode_buf[OPUS_MAX_PCM]; + switch_bool_t eof; + switch_thread_rwlock_t *rwlock; + switch_file_handle_t *handle; + size_t samplerate; + int frame_size; + int channels; + size_t buffer_seconds; + size_t err; + opus_int16 *opusbuf; + switch_size_t opusbuflen; + FILE *fp; +#ifdef HAVE_OPUSFILE_ENCODE + OggOpusEnc *enc; + OggOpusComments *comments; + unsigned char encode_buf[OPUSFILE_MAX]; + int encoded_buflen; + size_t samples_encode; +#endif + switch_memory_pool_t *pool; +}; + +typedef struct opus_file_context opus_file_context; + +static struct { + int debug; +} globals; + +static switch_status_t switch_opusfile_decode(opus_file_context *context, void *data, size_t max_bytes, int channels) +{ + int ret = 0; + size_t buf_inuse; + + if (!context->of) { + return SWITCH_STATUS_FALSE; + } + + memset(context->decode_buf, 0, sizeof(context->decode_buf)); + switch_mutex_lock(context->audio_mutex); + while (!(context->eof) && (buf_inuse = switch_buffer_inuse(context->audio_buffer)) <= max_bytes) { + + if (channels == 1) { + ret = op_read(context->of, (opus_int16 *)context->decode_buf, OPUS_MAX_PCM, NULL); + } else if (channels == 2) { + ret = op_read_stereo(context->of, (opus_int16 *)context->decode_buf, OPUS_MAX_PCM); + } else if (channels > 2) { + ret = op_read(context->of, (opus_int16 *)context->decode_buf, OPUS_MAX_PCM, NULL); + } else if ((channels > 255) || (channels < 1)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[OGG/OPUS File] Invalid number of channels"); + switch_mutex_unlock(context->audio_mutex); + return SWITCH_STATUS_FALSE; + } + if (ret < 0) { + switch(ret) { + case OP_HOLE: /* There was a hole in the data, and some samples may have been skipped. Call this function again to continue decoding past the hole.*/ + case OP_EREAD: /*An underlying read operation failed. This may signal a truncation attack from an source.*/ + + case OP_EFAULT: /* An internal memory allocation failed. */ + + case OP_EIMPL: /*An unseekable stream encountered a new link that used a feature that is not implemented, such as an unsupported channel family.*/ + + case OP_EINVAL: /* The stream was only partially open. */ + + case OP_ENOTFORMAT: /* An unseekable stream encountered a new link that did not have any logical Opus streams in it. */ + + case OP_EBADHEADER: /*An unseekable stream encountered a new link with a required header packet that was not properly formatted, contained illegal values, or was missing altogether.*/ + + case OP_EVERSION: /*An unseekable stream encountered a new link with an ID header that contained an unrecognized version number.*/ + + case OP_EBADPACKET: /*Failed to properly decode the next packet.*/ + + case OP_EBADLINK: /*We failed to find data we had seen before.*/ + + case OP_EBADTIMESTAMP: /*An unseekable stream encountered a new link with a starting timestamp that failed basic validity checks.*/ + + default: + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[OGG/OPUS Decoder]: error decoding file: [%d]\n", ret); + switch_mutex_unlock(context->audio_mutex); + return SWITCH_STATUS_FALSE; + } + } else if (ret == 0) { + /*The number of samples returned may be 0 if the buffer was too small to store even a single sample for both channels, or if end-of-file was reached*/ + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[OGG/OPUS Decoder]: EOF reached [%d]\n", ret); + } + context->eof = TRUE; + break; + } else /* (ret > 0)*/ { + /*The number of samples read per channel on success*/ + switch_buffer_write(context->audio_buffer, (opus_int16 *)context->decode_buf, ret * sizeof(opus_int16) * channels); + + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "[OGG/OPUS Decoder]: Read samples: %d. Wrote bytes to buffer: [%d] bytes in use: [%u]\n", ret, (int)(ret * sizeof(int16_t) * channels), (unsigned int)buf_inuse); + } + } + } + switch_mutex_unlock(context->audio_mutex); + context->eof = FALSE; // for next page + return SWITCH_STATUS_SUCCESS; +} + + +static switch_status_t switch_opusfile_open(switch_file_handle_t *handle, const char *path) +{ + opus_file_context *context; + char *ext; + unsigned int flags = 0; + int ret; + + if ((ext = strrchr(path, '.')) == 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[OGG/OPUS File] Invalid Format\n"); + return SWITCH_STATUS_GENERR; + } + ext++; + + if ((context = switch_core_alloc(handle->memory_pool, sizeof(*context))) == 0) { + return SWITCH_STATUS_MEMERR; + } + + context->pool = handle->memory_pool; + + switch_thread_rwlock_create(&(context->rwlock), context->pool); + + switch_thread_rwlock_rdlock(context->rwlock); + + switch_mutex_init(&context->audio_mutex, SWITCH_MUTEX_NESTED, context->pool); + + if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + flags |= SWITCH_FOPEN_WRITE | SWITCH_FOPEN_CREATE; + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND) || switch_test_flag(handle, SWITCH_FILE_WRITE_OVER)) { + flags |= SWITCH_FOPEN_READ; + } else { + flags |= SWITCH_FOPEN_TRUNCATE; + } + } + + if (switch_test_flag(handle, SWITCH_FILE_FLAG_READ)) { + if (switch_buffer_create_dynamic(&context->audio_buffer, TC_BUFFER_SIZE, TC_BUFFER_SIZE * 2, 0) != SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Memory Error!\n"); + goto err; + } + + flags |= SWITCH_FOPEN_READ; + } + + handle->samples = 0; + handle->samplerate = context->samplerate = DEFAULT_RATE; /*open files at 48 khz always*/ + handle->format = 0; + handle->sections = 0; + handle->seekable = 1; + handle->speed = 0; + handle->pos = 0; + handle->private_info = context; + context->handle = handle; + memcpy(handle->file_path, path, strlen(path)); + +#ifdef HAVE_OPUSFILE_ENCODE + if (switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + int err; int mapping_family = 0; + + context->channels = handle->channels; + context->samplerate = handle->samplerate; + handle->seekable = 0; + context->comments = ope_comments_create(); + ope_comments_add(context->comments, "METADATA", "Freeswitch/mod_opusfile"); + // opus_multistream_surround_encoder_get_size() in libopus will check these + if ((context->channels > 2) && (context->channels <= 8)) { + mapping_family = 1; + } else if ((context->channels > 8) && (context->channels <= 255)) { + mapping_family = 255; + } + context->enc = ope_encoder_create_file(handle->file_path, context->comments, context->samplerate, context->channels, mapping_family, &err); + if (!context->enc) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open file for writing [%d] [%s]\n", err, ope_strerror(err)); + switch_thread_rwlock_unlock(context->rwlock); + return SWITCH_STATUS_FALSE; + } + switch_thread_rwlock_unlock(context->rwlock); + return SWITCH_STATUS_SUCCESS; + } +#endif + + context->of = op_open_file(path, &ret); + if (!context->of) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[OGG/OPUS File] Error opening %s\n", path); + return SWITCH_STATUS_GENERR; + } + + if (switch_test_flag(handle, SWITCH_FILE_WRITE_APPEND)) { + op_pcm_seek(context->of, 0); // overwrite + handle->pos = 0; + } + + context->prev_li = -1; + context->nsamples = 0; + + handle->channels = context->channels = op_channel_count(context->of, -1); + context->pcm_offset = op_pcm_tell(context->of); + + if(context->pcm_offset!=0){ + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[OGG/OPUS File] Non-zero starting PCM offset: [%li]\n", (long)context->pcm_offset); + } + context->pcm_print_offset = context->pcm_offset - DEFAULT_RATE; + context->bitrate = 0; + context->buffer_seconds = 1; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "[OGG/OPUS File] Opening File [%s] %dhz\n", path, handle->samplerate); + + context->li = op_current_link(context->of); + + if (context->li != context->prev_li) { + const OpusHead *head; + const OpusTags *tags; + head=op_head(context->of, context->li); + if (head) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "[OGG/OPUS File] Channels: %i\n", head->channel_count); + if (head->input_sample_rate) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "[OGG/OPUS File] Original sampling rate: %lu Hz\n", (unsigned long)head->input_sample_rate); + handle->samplerate = context->samplerate = head->input_sample_rate; + } + } + if (op_seekable(context->of)) { + ogg_int64_t duration; + opus_int64 size; + duration = op_pcm_total(context->of, context->li); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO , "[OGG/OPUS File] Duration (samples): %u", (unsigned int)duration); + size = op_raw_total(context->of, context->li); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO,"[OGG/OPUS File] Size (bytes): %u", (unsigned int)size); + } + tags = op_tags(context->of, context->li); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "[OGG/OPUS File] Encoded by: %s\n", tags->vendor); + } + + switch_thread_rwlock_unlock(context->rwlock); + return SWITCH_STATUS_SUCCESS; + +err: + switch_thread_rwlock_unlock(context->rwlock); + + return SWITCH_STATUS_FALSE; +} + +static switch_status_t switch_opusfile_close(switch_file_handle_t *handle) +{ + opus_file_context *context = handle->private_info; + + switch_thread_rwlock_rdlock(context->rwlock); + if (context->of) { + op_free(context->of); + } +#ifdef HAVE_OPUSFILE_ENCODE + if (context->enc) { + ope_encoder_destroy(context->enc); + } + if (context->comments) { + ope_comments_destroy(context->comments); + } +#endif + if (context->audio_buffer) { + switch_buffer_destroy(&context->audio_buffer); + } + switch_thread_rwlock_unlock(context->rwlock); + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t switch_opusfile_seek(switch_file_handle_t *handle, unsigned int *cur_sample, int64_t samples, int whence) +{ + int ret; + opus_file_context *context = handle->private_info; + + if (handle->handler || switch_test_flag(handle, SWITCH_FILE_FLAG_WRITE)) { + return SWITCH_STATUS_FALSE; + } else { + if (whence == SWITCH_SEEK_CUR) { + samples -= switch_buffer_inuse(context->audio_buffer) / sizeof(int16_t); + } + switch_buffer_zero(context->audio_buffer); + ret = op_pcm_seek(context->of, samples); + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"[OGG/OPUS File] seek samples: [%u]", (unsigned int)samples); + } + if (ret == 0) { + handle->pos = *cur_sample = samples; + return SWITCH_STATUS_SUCCESS; + } + } + return SWITCH_STATUS_FALSE; +} + +static switch_status_t switch_opusfile_read(switch_file_handle_t *handle, void *data, size_t *len) +{ + opus_file_context *context = handle->private_info; + size_t bytes = *len * sizeof(int16_t) * handle->real_channels; + size_t rb = 0, newbytes; + + if (!context) { + return SWITCH_STATUS_FALSE; + } + + if (!handle->handler) { + if (switch_opusfile_decode(context, data, bytes, handle->real_channels) == SWITCH_STATUS_FALSE) { + context->eof = 1; + } + } + switch_mutex_lock(context->audio_mutex); + rb = switch_buffer_read(context->audio_buffer, data, bytes); + switch_mutex_unlock(context->audio_mutex); + + if (!rb && (context->eof)) { + return SWITCH_STATUS_FALSE; + } + if (rb) { + *len = rb / sizeof(int16_t) / handle->real_channels; + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "[OGG/OPUS File] rb: [%d] *len: [%d]\n", (int)rb, (int)*len); + } + } else { + newbytes = (2 * handle->samplerate * handle->real_channels) * context->buffer_seconds; + if (newbytes < bytes) { + bytes = newbytes; + } + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "[OGG/OPUS File] Padding with empty audio. seconds: [%d] bytes: [%d] newbytes: [%d] real_channels: [%d]\n", + (int)context->buffer_seconds, (int)bytes, (int)newbytes, (int)handle->real_channels); + } + memset(data, 255, bytes); + *len = bytes / sizeof(int16_t) / handle->real_channels; + } + + handle->pos += *len; + handle->sample_count += *len; + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t switch_opusfile_write(switch_file_handle_t *handle, void *data, size_t *len) +{ +#ifdef HAVE_OPUSFILE_ENCODE + size_t nsamples = *len; + int err; + int mapping_family = 0; + + opus_file_context *context = handle->private_info; + + if (!handle) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error no handle\n"); + return SWITCH_STATUS_FALSE; + } + + if (!(context = handle->private_info)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error no context\n"); + return SWITCH_STATUS_FALSE; + } + if (!context->comments) { + context->comments = ope_comments_create(); + ope_comments_add(context->comments, "METADATA", "Freeswitch/mod_opusfile"); + } + if (context->channels > 2) { + mapping_family = 1; + } + if (!context->enc) { + context->enc = ope_encoder_create_file(handle->file_path, context->comments, handle->samplerate, handle->channels, mapping_family, &err); + if (!context->enc) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Can't open file for writing. err: [%d] [%s]\n", err, ope_strerror(err)); + return SWITCH_STATUS_FALSE; + } + } + + if (globals.debug) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG,"[OGG/OPUS File] write nsamples: [%d]", (int)nsamples); + } + + err = ope_encoder_write(context->enc, (opus_int16 *)data, nsamples); + + if (err != OPE_OK) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "[OGG/OPUS File] Can't encode. err: [%d] [%s]", err, ope_strerror(err)); + return SWITCH_STATUS_FALSE; + } + + handle->sample_count += *len; +#endif + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t switch_opusfile_set_string(switch_file_handle_t *handle, switch_audio_col_t col, const char *string) +{ + return SWITCH_STATUS_FALSE; +} + +static switch_status_t switch_opusfile_get_string(switch_file_handle_t *handle, switch_audio_col_t col, const char **string) +{ + return SWITCH_STATUS_FALSE; +} + + +#define OPUSFILE_DEBUG_SYNTAX "" +SWITCH_STANDARD_API(mod_opusfile_debug) +{ + if (zstr(cmd)) { + stream->write_function(stream, "-USAGE: %s\n", OPUSFILE_DEBUG_SYNTAX); + } else { + if (!strcasecmp(cmd, "on")) { + globals.debug = 1; + stream->write_function(stream, "OPUSFILE Debug: on\n"); +#ifdef HAVE_OPUSFILE_ENCODE + stream->write_function(stream, "Library version (encoding): %s\n", ope_get_version_string()); +#endif + } else if (!strcasecmp(cmd, "off")) { + globals.debug = 0; + stream->write_function(stream, "OPUSFILE Debug: off\n"); + } else { + stream->write_function(stream, "-USAGE: %s\n", OPUSFILE_DEBUG_SYNTAX); + } + } + return SWITCH_STATUS_SUCCESS; +} + +/* Registration */ + +static char *supported_formats[SWITCH_MAX_CODECS] = { 0 }; + +SWITCH_MODULE_LOAD_FUNCTION(mod_opusfile_load) +{ + switch_file_interface_t *file_interface; + switch_api_interface_t *commands_api_interface; + + supported_formats[0] = "opus"; + + *module_interface = switch_loadable_module_create_module_interface(pool, modname); + + SWITCH_ADD_API(commands_api_interface, "opusfile_debug", "Set OPUSFILE Debug", mod_opusfile_debug, OPUSFILE_DEBUG_SYNTAX); + + switch_console_set_complete("add opusfile_debug on"); + switch_console_set_complete("add opusfile_debug off"); + + globals.debug = 0; + + file_interface = switch_loadable_module_create_interface(*module_interface, SWITCH_FILE_INTERFACE); + file_interface->interface_name = modname; + file_interface->extens = supported_formats; + file_interface->file_open = switch_opusfile_open; + file_interface->file_close = switch_opusfile_close; + file_interface->file_read = switch_opusfile_read; + file_interface->file_write = switch_opusfile_write; + file_interface->file_seek = switch_opusfile_seek; + file_interface->file_set_string = switch_opusfile_set_string; + file_interface->file_get_string = switch_opusfile_get_string; + + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "mod_opusfile loaded\n"); + + /* indicate that the module should continue to be loaded */ + return SWITCH_STATUS_SUCCESS; +} + +/* For Emacs: + * Local Variables: + * mode:c + * indent-tabs-mode:t + * tab-width:4 + * c-basic-offset:4 + * End: + * For VIM: + * vim:set softtabstop=4 shiftwidth=4 tabstop=4 noet: + */ + diff --git a/src/mod/languages/mod_managed/freeswitch_wrap.cxx b/src/mod/languages/mod_managed/freeswitch_wrap.cxx index e5ac0ef514..7d7e664256 100644 --- a/src/mod/languages/mod_managed/freeswitch_wrap.cxx +++ b/src/mod/languages/mod_managed/freeswitch_wrap.cxx @@ -3215,7 +3215,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_SWITCH_MAX_STACKS_get___() { int jresult ; int result; - result = (int)(16); + result = (int)(32); jresult = result; return jresult; } @@ -15378,7 +15378,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_core_speech_feed_tts_ arg1 = (switch_speech_handle_t *)jarg1; arg2 = (char *)jarg2; arg3 = (switch_speech_flag_t *)jarg3; - result = (switch_status_t)switch_core_speech_feed_tts(arg1,arg2,arg3); + result = (switch_status_t)switch_core_speech_feed_tts(arg1,(char const *)arg2,arg3); jresult = (int)result; return jresult; } @@ -16297,6 +16297,24 @@ SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_load_network_lists__ } +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_check_network_list_ip_port_token___(char * jarg1, int jarg2, char * jarg3, void * jarg4) { + int jresult ; + char *arg1 = (char *) 0 ; + int arg2 ; + char *arg3 = (char *) 0 ; + char **arg4 = (char **) 0 ; + switch_bool_t result; + + arg1 = (char *)jarg1; + arg2 = (int)jarg2; + arg3 = (char *)jarg3; + arg4 = (char **)jarg4; + result = (switch_bool_t)switch_check_network_list_ip_port_token((char const *)arg1,arg2,(char const *)arg3,(char const **)arg4); + jresult = (int)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_check_network_list_ip_token___(char * jarg1, char * jarg2, void * jarg3) { int jresult ; char *arg1 = (char *) 0 ; @@ -18923,7 +18941,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_loadable_module_load_ arg2 = (char *)jarg2; arg3 = (switch_bool_t)jarg3; arg4 = (char **)jarg4; - result = (switch_status_t)switch_loadable_module_load_module(arg1,arg2,arg3,(char const **)arg4); + result = (switch_status_t)switch_loadable_module_load_module((char const *)arg1,(char const *)arg2,arg3,(char const **)arg4); jresult = (int)result; return jresult; } @@ -18953,7 +18971,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_loadable_module_unloa arg2 = (char *)jarg2; arg3 = (switch_bool_t)jarg3; arg4 = (char **)jarg4; - result = (switch_status_t)switch_loadable_module_unload_module(arg1,arg2,arg3,(char const **)arg4); + result = (switch_status_t)switch_loadable_module_unload_module((char const *)arg1,(char const *)arg2,arg3,(char const **)arg4); jresult = (int)result; return jresult; } @@ -19317,6 +19335,126 @@ result = (char *)("\r\n #%&+:;<=>?@[\\]^`{|}\""); } +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_MAX_NETWORK_PORTS_get___() { + int jresult ; + int result; + + result = (int)(10); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_port_set___(void * jarg1, int jarg2) { + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int arg2 ; + + arg1 = (switch_network_port_range *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->port = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_port_get___(void * jarg1) { + int jresult ; + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int result; + + arg1 = (switch_network_port_range *)jarg1; + result = (int) ((arg1)->port); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_ports_set___(void * jarg1, void * jarg2) { + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int *arg2 ; + + arg1 = (switch_network_port_range *)jarg1; + arg2 = (int *)jarg2; + { + size_t ii; + int *b = (int *) arg1->ports; + for (ii = 0; ii < (size_t)10; ii++) b[ii] = *((int *) arg2 + ii); + } +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_ports_get___(void * jarg1) { + void * jresult ; + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int *result = 0 ; + + arg1 = (switch_network_port_range *)jarg1; + result = (int *)(int *) ((arg1)->ports); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_min_port_set___(void * jarg1, int jarg2) { + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int arg2 ; + + arg1 = (switch_network_port_range *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->min_port = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_min_port_get___(void * jarg1) { + int jresult ; + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int result; + + arg1 = (switch_network_port_range *)jarg1; + result = (int) ((arg1)->min_port); + jresult = result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_max_port_set___(void * jarg1, int jarg2) { + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int arg2 ; + + arg1 = (switch_network_port_range *)jarg1; + arg2 = (int)jarg2; + if (arg1) (arg1)->max_port = arg2; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_port_range_max_port_get___(void * jarg1) { + int jresult ; + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + int result; + + arg1 = (switch_network_port_range *)jarg1; + result = (int) ((arg1)->max_port); + jresult = result; + return jresult; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_FreeSWITCHfNative_new_switch_network_port_range___() { + void * jresult ; + switch_network_port_range *result = 0 ; + + result = (switch_network_port_range *)new switch_network_port_range(); + jresult = (void *)result; + return jresult; +} + + +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_delete_switch_network_port_range___(void * jarg1) { + switch_network_port_range *arg1 = (switch_network_port_range *) 0 ; + + arg1 = (switch_network_port_range *)jarg1; + delete arg1; +} + + SWIGEXPORT char * SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_get_hex_bytes___(void * jarg1, void * jarg2, char * jarg3, void * jarg4) { char * jresult ; switch_byte_t *arg1 = (switch_byte_t *) 0 ; @@ -21130,6 +21268,88 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_add_host } +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_add_cidr_port_token___(void * jarg1, char * jarg2, int jarg3, char * jarg4, void * jarg5) { + int jresult ; + switch_network_list_t *arg1 = (switch_network_list_t *) 0 ; + char *arg2 = (char *) 0 ; + switch_bool_t arg3 ; + char *arg4 = (char *) 0 ; + switch_network_port_range_p arg5 = (switch_network_port_range_p) 0 ; + switch_status_t result; + + arg1 = (switch_network_list_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (switch_bool_t)jarg3; + arg4 = (char *)jarg4; + arg5 = (switch_network_port_range_p)jarg5; + result = (switch_status_t)switch_network_list_add_cidr_port_token(arg1,(char const *)arg2,arg3,(char const *)arg4,arg5); + jresult = (int)result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_add_host_port_mask___(void * jarg1, char * jarg2, char * jarg3, int jarg4, void * jarg5) { + int jresult ; + switch_network_list_t *arg1 = (switch_network_list_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_bool_t arg4 ; + switch_network_port_range_p arg5 = (switch_network_port_range_p) 0 ; + switch_status_t result; + + arg1 = (switch_network_list_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + arg4 = (switch_bool_t)jarg4; + arg5 = (switch_network_port_range_p)jarg5; + result = (switch_status_t)switch_network_list_add_host_port_mask(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5); + jresult = (int)result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_validate_ip_port_token___(void * jarg1, unsigned long jarg2, int jarg3, void * jarg4) { + int jresult ; + switch_network_list_t *arg1 = (switch_network_list_t *) 0 ; + uint32_t arg2 ; + int arg3 ; + char **arg4 = (char **) 0 ; + switch_bool_t result; + + arg1 = (switch_network_list_t *)jarg1; + arg2 = (uint32_t)jarg2; + arg3 = (int)jarg3; + arg4 = (char **)jarg4; + result = (switch_bool_t)switch_network_list_validate_ip_port_token(arg1,arg2,arg3,(char const **)arg4); + jresult = (int)result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_validate_ip6_port_token___(void * jarg1, void * jarg2, int jarg3, void * jarg4) { + int jresult ; + switch_network_list_t *arg1 = (switch_network_list_t *) 0 ; + ip_t arg2 ; + int arg3 ; + char **arg4 = (char **) 0 ; + ip_t *argp2 ; + switch_bool_t result; + + arg1 = (switch_network_list_t *)jarg1; + argp2 = (ip_t *)jarg2; + if (!argp2) { + SWIG_CSharpSetPendingExceptionArgument(SWIG_CSharpArgumentNullException, "Attempt to dereference null ip_t", 0); + return 0; + } + arg2 = *argp2; + arg3 = (int)jarg3; + arg4 = (char **)jarg4; + result = (switch_bool_t)switch_network_list_validate_ip6_port_token(arg1,arg2,arg3,(char const **)arg4); + jresult = (int)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_network_list_validate_ip_token___(void * jarg1, unsigned long jarg2, void * jarg3) { int jresult ; switch_network_list_t *arg1 = (switch_network_list_t *) 0 ; @@ -34617,6 +34837,36 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_channel_set_profile_v } +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_channel_set_log_tag___(void * jarg1, char * jarg2, char * jarg3) { + int jresult ; + switch_channel_t *arg1 = (switch_channel_t *) 0 ; + char *arg2 = (char *) 0 ; + char *arg3 = (char *) 0 ; + switch_status_t result; + + arg1 = (switch_channel_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (char *)jarg3; + result = (switch_status_t)switch_channel_set_log_tag(arg1,(char const *)arg2,(char const *)arg3); + jresult = (int)result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_channel_get_log_tags___(void * jarg1, void * jarg2) { + int jresult ; + switch_channel_t *arg1 = (switch_channel_t *) 0 ; + switch_event_t **arg2 = (switch_event_t **) 0 ; + switch_status_t result; + + arg1 = (switch_channel_t *)jarg1; + arg2 = (switch_event_t **)jarg2; + result = (switch_status_t)switch_channel_get_log_tags(arg1,arg2); + jresult = (int)result; + return jresult; +} + + SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_channel_set_variable_var_check___(void * jarg1, char * jarg2, char * jarg3, int jarg4) { int jresult ; switch_channel_t *arg1 = (switch_channel_t *) 0 ; @@ -39797,7 +40047,27 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_record_session___ arg2 = (char *)jarg2; arg3 = (uint32_t)jarg3; arg4 = (switch_file_handle_t *)jarg4; - result = (switch_status_t)switch_ivr_record_session(arg1,arg2,arg3,arg4); + result = (switch_status_t)switch_ivr_record_session(arg1,(char const *)arg2,arg3,arg4); + jresult = (int)result; + return jresult; +} + + +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_record_session_event___(void * jarg1, char * jarg2, unsigned long jarg3, void * jarg4, void * jarg5) { + int jresult ; + switch_core_session_t *arg1 = (switch_core_session_t *) 0 ; + char *arg2 = (char *) 0 ; + uint32_t arg3 ; + switch_file_handle_t *arg4 = (switch_file_handle_t *) 0 ; + switch_event_t *arg5 = (switch_event_t *) 0 ; + switch_status_t result; + + arg1 = (switch_core_session_t *)jarg1; + arg2 = (char *)jarg2; + arg3 = (uint32_t)jarg3; + arg4 = (switch_file_handle_t *)jarg4; + arg5 = (switch_event_t *)jarg5; + result = (switch_status_t)switch_ivr_record_session_event(arg1,(char const *)arg2,arg3,arg4,arg5); jresult = (int)result; return jresult; } @@ -40239,7 +40509,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_speak_text_handle arg4 = (switch_timer_t *)jarg4; arg5 = (char *)jarg5; arg6 = (switch_input_args_t *)jarg6; - result = (switch_status_t)switch_ivr_speak_text_handle(arg1,arg2,arg3,arg4,arg5,arg6); + result = (switch_status_t)switch_ivr_speak_text_handle(arg1,arg2,arg3,arg4,(char const *)arg5,arg6); jresult = (int)result; return jresult; } @@ -40267,7 +40537,7 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_ivr_speak_text___(voi arg3 = (char *)jarg3; arg4 = (char *)jarg4; arg5 = (switch_input_args_t *)jarg5; - result = (switch_status_t)switch_ivr_speak_text(arg1,(char const *)arg2,(char const *)arg3,arg4,arg5); + result = (switch_status_t)switch_ivr_speak_text(arg1,(char const *)arg2,(char const *)arg3,(char const *)arg4,arg5); jresult = (int)result; return jresult; } @@ -44021,19 +44291,21 @@ SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_rtp_set_interdigit_d } -SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_rtp_add_dtls___(void * jarg1, void * jarg2, void * jarg3, int jarg4) { +SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_rtp_add_dtls___(void * jarg1, void * jarg2, void * jarg3, int jarg4, unsigned char jarg5) { int jresult ; switch_rtp_t *arg1 = (switch_rtp_t *) 0 ; dtls_fingerprint_t *arg2 = (dtls_fingerprint_t *) 0 ; dtls_fingerprint_t *arg3 = (dtls_fingerprint_t *) 0 ; dtls_type_t arg4 ; + uint8_t arg5 ; switch_status_t result; arg1 = (switch_rtp_t *)jarg1; arg2 = (dtls_fingerprint_t *)jarg2; arg3 = (dtls_fingerprint_t *)jarg3; arg4 = (dtls_type_t)jarg4; - result = (switch_status_t)switch_rtp_add_dtls(arg1,arg2,arg3,arg4); + arg5 = (uint8_t)jarg5; + result = (switch_status_t)switch_rtp_add_dtls(arg1,arg2,arg3,arg4,arg5); jresult = (int)result; return jresult; } @@ -44385,6 +44657,28 @@ SWIGEXPORT int SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_log_node_t_slevel_get } +SWIGEXPORT void SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_log_node_t_tags_set___(void * jarg1, void * jarg2) { + switch_log_node_t *arg1 = (switch_log_node_t *) 0 ; + switch_event_t *arg2 = (switch_event_t *) 0 ; + + arg1 = (switch_log_node_t *)jarg1; + arg2 = (switch_event_t *)jarg2; + if (arg1) (arg1)->tags = arg2; +} + + +SWIGEXPORT void * SWIGSTDCALL CSharp_FreeSWITCHfNative_switch_log_node_t_tags_get___(void * jarg1) { + void * jresult ; + switch_log_node_t *arg1 = (switch_log_node_t *) 0 ; + switch_event_t *result = 0 ; + + arg1 = (switch_log_node_t *)jarg1; + result = (switch_event_t *) ((arg1)->tags); + jresult = (void *)result; + return jresult; +} + + SWIGEXPORT void * SWIGSTDCALL CSharp_FreeSWITCHfNative_new_switch_log_node_t___() { void * jresult ; switch_log_node_t *result = 0 ; diff --git a/src/mod/languages/mod_managed/managed/swig.cs b/src/mod/languages/mod_managed/managed/swig.cs index 192da11ea6..8d057bf319 100644 --- a/src/mod/languages/mod_managed/managed/swig.cs +++ b/src/mod/languages/mod_managed/managed/swig.cs @@ -9486,6 +9486,19 @@ else freeswitchPINVOKE.switch_load_network_lists((int)reload); } + public static switch_bool_t switch_check_network_list_ip_port_token(string ip_str, int port, string list_name, out string token) { +var token_ptr = global::System.IntPtr.Zero; + try { + switch_bool_t ret = (switch_bool_t)freeswitchPINVOKE.switch_check_network_list_ip_port_token(ip_str, port, list_name, ref token_ptr); + return ret; + } finally { +if(token_ptr != global::System.IntPtr.Zero) + token = global::System.Runtime.InteropServices.Marshal.PtrToStringAnsi(token_ptr); +else + token = null; + } + } + public static switch_bool_t switch_check_network_list_ip_token(string ip_str, string list_name, out string token) { var token_ptr = global::System.IntPtr.Zero; try { @@ -10895,6 +10908,43 @@ else return ret; } + public static switch_status_t switch_network_list_add_cidr_port_token(SWIGTYPE_p_switch_network_list list, string cidr_str, switch_bool_t ok, string token, switch_network_port_range port) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_network_list_add_cidr_port_token(SWIGTYPE_p_switch_network_list.getCPtr(list), cidr_str, (int)ok, token, switch_network_port_range.getCPtr(port)); + return ret; + } + + public static switch_status_t switch_network_list_add_host_port_mask(SWIGTYPE_p_switch_network_list list, string host, string mask_str, switch_bool_t ok, switch_network_port_range port) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_network_list_add_host_port_mask(SWIGTYPE_p_switch_network_list.getCPtr(list), host, mask_str, (int)ok, switch_network_port_range.getCPtr(port)); + return ret; + } + + public static switch_bool_t switch_network_list_validate_ip_port_token(SWIGTYPE_p_switch_network_list list, uint ip, int port, out string token) { +var token_ptr = global::System.IntPtr.Zero; + try { + switch_bool_t ret = (switch_bool_t)freeswitchPINVOKE.switch_network_list_validate_ip_port_token(SWIGTYPE_p_switch_network_list.getCPtr(list), ip, port, ref token_ptr); + return ret; + } finally { +if(token_ptr != global::System.IntPtr.Zero) + token = global::System.Runtime.InteropServices.Marshal.PtrToStringAnsi(token_ptr); +else + token = null; + } + } + + public static switch_bool_t switch_network_list_validate_ip6_port_token(SWIGTYPE_p_switch_network_list list, ip_t ip, int port, out string token) { +var token_ptr = global::System.IntPtr.Zero; + try { + switch_bool_t ret = (switch_bool_t)freeswitchPINVOKE.switch_network_list_validate_ip6_port_token(SWIGTYPE_p_switch_network_list.getCPtr(list), ip_t.getCPtr(ip), port, ref token_ptr); + if (freeswitchPINVOKE.SWIGPendingException.Pending) throw freeswitchPINVOKE.SWIGPendingException.Retrieve(); + return ret; + } finally { +if(token_ptr != global::System.IntPtr.Zero) + token = global::System.Runtime.InteropServices.Marshal.PtrToStringAnsi(token_ptr); +else + token = null; + } + } + public static switch_bool_t switch_network_list_validate_ip_token(SWIGTYPE_p_switch_network_list list, uint ip, out string token) { var token_ptr = global::System.IntPtr.Zero; try { @@ -11275,6 +11325,16 @@ else return ret; } + public static switch_status_t switch_channel_set_log_tag(SWIGTYPE_p_switch_channel channel, string tagname, string tagvalue) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_set_log_tag(SWIGTYPE_p_switch_channel.getCPtr(channel), tagname, tagvalue); + return ret; + } + + public static switch_status_t switch_channel_get_log_tags(SWIGTYPE_p_switch_channel channel, SWIGTYPE_p_p_switch_event log_tags) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_get_log_tags(SWIGTYPE_p_switch_channel.getCPtr(channel), SWIGTYPE_p_p_switch_event.getCPtr(log_tags)); + return ret; + } + public static switch_status_t switch_channel_set_variable_var_check(SWIGTYPE_p_switch_channel channel, string varname, string value, switch_bool_t var_check) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_channel_set_variable_var_check(SWIGTYPE_p_switch_channel.getCPtr(channel), varname, value, (int)var_check); return ret; @@ -12567,6 +12627,11 @@ else return ret; } + public static switch_status_t switch_ivr_record_session_event(SWIGTYPE_p_switch_core_session session, string file, uint limit, switch_file_handle fh, switch_event variables) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_record_session_event(SWIGTYPE_p_switch_core_session.getCPtr(session), file, limit, switch_file_handle.getCPtr(fh), switch_event.getCPtr(variables)); + return ret; + } + public static switch_status_t switch_ivr_transfer_recordings(SWIGTYPE_p_switch_core_session orig_session, SWIGTYPE_p_switch_core_session new_session) { switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_ivr_transfer_recordings(SWIGTYPE_p_switch_core_session.getCPtr(orig_session), SWIGTYPE_p_switch_core_session.getCPtr(new_session)); return ret; @@ -13642,8 +13707,8 @@ else freeswitchPINVOKE.switch_rtp_set_interdigit_delay(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), delay); } - public static switch_status_t switch_rtp_add_dtls(SWIGTYPE_p_switch_rtp rtp_session, dtls_fingerprint_t local_fp, dtls_fingerprint_t remote_fp, dtls_type_t type) { - switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_dtls(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), dtls_fingerprint_t.getCPtr(local_fp), dtls_fingerprint_t.getCPtr(remote_fp), (int)type); + public static switch_status_t switch_rtp_add_dtls(SWIGTYPE_p_switch_rtp rtp_session, dtls_fingerprint_t local_fp, dtls_fingerprint_t remote_fp, dtls_type_t type, byte want_DTLSv1_2) { + switch_status_t ret = (switch_status_t)freeswitchPINVOKE.switch_rtp_add_dtls(SWIGTYPE_p_switch_rtp.getCPtr(rtp_session), dtls_fingerprint_t.getCPtr(local_fp), dtls_fingerprint_t.getCPtr(remote_fp), (int)type, want_DTLSv1_2); return ret; } @@ -14511,6 +14576,7 @@ else public static readonly int CACHE_DB_LEN = freeswitchPINVOKE.CACHE_DB_LEN_get(); public static readonly int SWITCH_CMD_CHUNK_LEN = freeswitchPINVOKE.SWITCH_CMD_CHUNK_LEN_get(); public static readonly string SWITCH_URL_UNSAFE = freeswitchPINVOKE.SWITCH_URL_UNSAFE_get(); + public static readonly int MAX_NETWORK_PORTS = freeswitchPINVOKE.MAX_NETWORK_PORTS_get(); public static readonly int SWITCH_SMAX = freeswitchPINVOKE.SWITCH_SMAX_get(); public static readonly int SWITCH_SMIN = freeswitchPINVOKE.SWITCH_SMIN_get(); public static readonly int NO_EVENT_CHANNEL_ID = freeswitchPINVOKE.NO_EVENT_CHANNEL_ID_get(); @@ -18736,6 +18802,9 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_load_network_lists___")] public static extern void switch_load_network_lists(int jarg1); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_check_network_list_ip_port_token___")] + public static extern int switch_check_network_list_ip_port_token(string jarg1, int jarg2, string jarg3, ref global::System.IntPtr jarg4); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_check_network_list_ip_token___")] public static extern int switch_check_network_list_ip_token(string jarg1, string jarg2, ref global::System.IntPtr jarg3); @@ -19462,6 +19531,39 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_SWITCH_URL_UNSAFE_get___")] public static extern string SWITCH_URL_UNSAFE_get(); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_MAX_NETWORK_PORTS_get___")] + public static extern int MAX_NETWORK_PORTS_get(); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_port_set___")] + public static extern void switch_network_port_range_port_set(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_port_get___")] + public static extern int switch_network_port_range_port_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_ports_set___")] + public static extern void switch_network_port_range_ports_set(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_ports_get___")] + public static extern global::System.IntPtr switch_network_port_range_ports_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_min_port_set___")] + public static extern void switch_network_port_range_min_port_set(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_min_port_get___")] + public static extern int switch_network_port_range_min_port_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_max_port_set___")] + public static extern void switch_network_port_range_max_port_set(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_port_range_max_port_get___")] + public static extern int switch_network_port_range_max_port_get(global::System.Runtime.InteropServices.HandleRef jarg1); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_new_switch_network_port_range___")] + public static extern global::System.IntPtr new_switch_network_port_range(); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_delete_switch_network_port_range___")] + public static extern void delete_switch_network_port_range(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_get_hex_bytes___")] public static extern string switch_get_hex_bytes(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, string jarg3, global::System.Runtime.InteropServices.HandleRef jarg4); @@ -19828,6 +19930,18 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_add_host_mask___")] public static extern int switch_network_list_add_host_mask(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3, int jarg4); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_add_cidr_port_token___")] + public static extern int switch_network_list_add_cidr_port_token(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, int jarg3, string jarg4, global::System.Runtime.InteropServices.HandleRef jarg5); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_add_host_port_mask___")] + public static extern int switch_network_list_add_host_port_mask(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3, int jarg4, global::System.Runtime.InteropServices.HandleRef jarg5); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_validate_ip_port_token___")] + public static extern int switch_network_list_validate_ip_port_token(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2, int jarg3, ref global::System.IntPtr jarg4); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_validate_ip6_port_token___")] + public static extern int switch_network_list_validate_ip6_port_token(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, int jarg3, ref global::System.IntPtr jarg4); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_network_list_validate_ip_token___")] public static extern int switch_network_list_validate_ip_token(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2, ref global::System.IntPtr jarg3); @@ -23266,6 +23380,12 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_channel_set_profile_var___")] public static extern int switch_channel_set_profile_var(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_channel_set_log_tag___")] + public static extern int switch_channel_set_log_tag(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_channel_get_log_tags___")] + public static extern int switch_channel_get_log_tags(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_channel_set_variable_var_check___")] public static extern int switch_channel_set_variable_var_check(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, string jarg3, int jarg4); @@ -24424,6 +24544,9 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_record_session___")] public static extern int switch_ivr_record_session(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, uint jarg3, global::System.Runtime.InteropServices.HandleRef jarg4); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_record_session_event___")] + public static extern int switch_ivr_record_session_event(global::System.Runtime.InteropServices.HandleRef jarg1, string jarg2, uint jarg3, global::System.Runtime.InteropServices.HandleRef jarg4, global::System.Runtime.InteropServices.HandleRef jarg5); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_ivr_transfer_recordings___")] public static extern int switch_ivr_transfer_recordings(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); @@ -25304,7 +25427,7 @@ class freeswitchPINVOKE { public static extern void switch_rtp_set_interdigit_delay(global::System.Runtime.InteropServices.HandleRef jarg1, uint jarg2); [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_rtp_add_dtls___")] - public static extern int switch_rtp_add_dtls(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, int jarg4); + public static extern int switch_rtp_add_dtls(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2, global::System.Runtime.InteropServices.HandleRef jarg3, int jarg4, byte jarg5); [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_rtp_del_dtls___")] public static extern int switch_rtp_del_dtls(global::System.Runtime.InteropServices.HandleRef jarg1, int jarg2); @@ -25387,6 +25510,12 @@ class freeswitchPINVOKE { [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_log_node_t_slevel_get___")] public static extern int switch_log_node_t_slevel_get(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_log_node_t_tags_set___")] + public static extern void switch_log_node_t_tags_set(global::System.Runtime.InteropServices.HandleRef jarg1, global::System.Runtime.InteropServices.HandleRef jarg2); + + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_switch_log_node_t_tags_get___")] + public static extern global::System.IntPtr switch_log_node_t_tags_get(global::System.Runtime.InteropServices.HandleRef jarg1); + [global::System.Runtime.InteropServices.DllImport("mod_managed", EntryPoint="CSharp_FreeSWITCHfNative_new_switch_log_node_t___")] public static extern global::System.IntPtr new_switch_log_node_t(); @@ -29582,7 +29711,13 @@ public enum switch_call_cause_t { SWITCH_CAUSE_INVALID_URL = 610, SWITCH_CAUSE_INVALID_PROFILE = 611, SWITCH_CAUSE_NO_PICKUP = 612, - SWITCH_CAUSE_SRTP_READ_ERROR = 613 + SWITCH_CAUSE_SRTP_READ_ERROR = 613, + SWITCH_CAUSE_BOWOUT = 614, + SWITCH_CAUSE_BUSY_EVERYWHERE = 615, + SWITCH_CAUSE_DECLINE = 616, + SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE = 617, + SWITCH_CAUSE_NOT_ACCEPTABLE = 618, + SWITCH_CAUSE_UNWANTED = 619 } } @@ -30311,7 +30446,9 @@ namespace FreeSWITCH.Native { SWITCH_CPF_NONE = 0, SWITCH_CPF_SCREEN = (1 << 0), SWITCH_CPF_HIDE_NAME = (1 << 1), - SWITCH_CPF_HIDE_NUMBER = (1 << 2) + SWITCH_CPF_HIDE_NUMBER = (1 << 2), + SWITCH_CPF_SOFT_PREFIX = (1 << 3), + SWITCH_CPF_SOFT_LOOKUP = (1 << 4) } } @@ -30566,6 +30703,7 @@ public enum switch_channel_flag_t { CF_STREAM_CHANGED, CF_ARRANGED_BRIDGE, CF_STATE_REPEAT, + CF_WANT_DTLSv1_2, CF_FLAG_MAX } @@ -32316,7 +32454,9 @@ namespace FreeSWITCH.Native { SCF_DEBUG_SQL = (1 << 21), SCF_API_EXPANSION = (1 << 22), SCF_SESSION_THREAD_POOL = (1 << 23), - SCF_DIALPLAN_TIMESTAMPS = (1 << 24) + SCF_DIALPLAN_TIMESTAMPS = (1 << 24), + SCF_CPF_SOFT_PREFIX = (1 << 25), + SCF_CPF_SOFT_LOOKUP = (1 << 26) } } @@ -32335,7 +32475,8 @@ namespace FreeSWITCH.Native { public enum switch_core_media_ice_type_t { ICE_GOOGLE_JINGLE = (1 << 0), ICE_VANILLA = (1 << 1), - ICE_CONTROLLED = (1 << 2) + ICE_CONTROLLED = (1 << 2), + ICE_LITE = (1 << 3) } } @@ -39673,6 +39814,17 @@ public class switch_log_node_t : global::System.IDisposable { } } + public switch_event tags { + set { + freeswitchPINVOKE.switch_log_node_t_tags_set(swigCPtr, switch_event.getCPtr(value)); + } + get { + global::System.IntPtr cPtr = freeswitchPINVOKE.switch_log_node_t_tags_get(swigCPtr); + switch_event ret = (cPtr == global::System.IntPtr.Zero) ? null : new switch_event(cPtr, false); + return ret; + } + } + public switch_log_node_t() : this(freeswitchPINVOKE.new_switch_log_node_t(), true) { } @@ -40234,6 +40386,95 @@ public enum switch_module_interface_name_t { namespace FreeSWITCH.Native { +public class switch_network_port_range : global::System.IDisposable { + private global::System.Runtime.InteropServices.HandleRef swigCPtr; + protected bool swigCMemOwn; + + internal switch_network_port_range(global::System.IntPtr cPtr, bool cMemoryOwn) { + swigCMemOwn = cMemoryOwn; + swigCPtr = new global::System.Runtime.InteropServices.HandleRef(this, cPtr); + } + + internal static global::System.Runtime.InteropServices.HandleRef getCPtr(switch_network_port_range obj) { + return (obj == null) ? new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero) : obj.swigCPtr; + } + + ~switch_network_port_range() { + Dispose(); + } + + public virtual void Dispose() { + lock(this) { + if (swigCPtr.Handle != global::System.IntPtr.Zero) { + if (swigCMemOwn) { + swigCMemOwn = false; + freeswitchPINVOKE.delete_switch_network_port_range(swigCPtr); + } + swigCPtr = new global::System.Runtime.InteropServices.HandleRef(null, global::System.IntPtr.Zero); + } + global::System.GC.SuppressFinalize(this); + } + } + + public int port { + set { + freeswitchPINVOKE.switch_network_port_range_port_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_network_port_range_port_get(swigCPtr); + return ret; + } + } + + public SWIGTYPE_p_int ports { + set { + freeswitchPINVOKE.switch_network_port_range_ports_set(swigCPtr, SWIGTYPE_p_int.getCPtr(value)); + } + get { + global::System.IntPtr cPtr = freeswitchPINVOKE.switch_network_port_range_ports_get(swigCPtr); + SWIGTYPE_p_int ret = (cPtr == global::System.IntPtr.Zero) ? null : new SWIGTYPE_p_int(cPtr, false); + return ret; + } + } + + public int min_port { + set { + freeswitchPINVOKE.switch_network_port_range_min_port_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_network_port_range_min_port_get(swigCPtr); + return ret; + } + } + + public int max_port { + set { + freeswitchPINVOKE.switch_network_port_range_max_port_set(swigCPtr, value); + } + get { + int ret = freeswitchPINVOKE.switch_network_port_range_max_port_get(swigCPtr); + return ret; + } + } + + public switch_network_port_range() : this(freeswitchPINVOKE.new_switch_network_port_range(), true) { + } + +} + +} +//------------------------------------------------------------------------------ +// +// +// This file was automatically generated by SWIG (http://www.swig.org). +// Version 3.0.10 +// +// Do not make changes to this file unless you know what you are doing--modify +// the SWIG interface file instead. +//------------------------------------------------------------------------------ + +namespace FreeSWITCH.Native { + [System.Flags] public enum switch_originate_flag_enum_t { SOF_NONE = 0, SOF_NOBLOCK = (1 << 0), diff --git a/src/mod/loggers/mod_graylog2/mod_graylog2.c b/src/mod/loggers/mod_graylog2/mod_graylog2.c index fef005f56b..f5ee058210 100644 --- a/src/mod/loggers/mod_graylog2/mod_graylog2.c +++ b/src/mod/loggers/mod_graylog2/mod_graylog2.c @@ -126,8 +126,13 @@ static char *to_gelf(const switch_log_node_t *node, switch_log_level_t log_level full_message++; } + /* get fields from log tags */ + if (node->tags) { + switch_event_dup(&log_fields, node->tags); + } + /* get fields from channel data, if configured */ - if (!zstr(node->userdata) && (session = switch_core_session_locate(node->userdata))) { + if (!zstr(node->userdata) && globals.session_fields->headers && (session = switch_core_session_locate(node->userdata))) { switch_channel_t *channel = switch_core_session_get_channel(session); switch_event_header_t *hp; /* session_fields name mapped to variable name */ diff --git a/src/mod/say/mod_say_de/mod_say_de.c b/src/mod/say/mod_say_de/mod_say_de.c index 55f65c3241..3f0245aac2 100644 --- a/src/mod/say/mod_say_de/mod_say_de.c +++ b/src/mod/say/mod_say_de/mod_say_de.c @@ -384,6 +384,11 @@ static switch_status_t de_say_time(switch_core_session_t *session, char *tosay, break; } + if (say_date) { + say_dow = say_day = say_month = say_year = 1; + say_today = say_yesterday = 0; + } + if (say_today) { say_file("time/today.wav"); } @@ -408,11 +413,6 @@ static switch_status_t de_say_time(switch_core_session_t *session, char *tosay, say_num(tm.tm_year + 1900, SSM_PRONOUNCED_YEAR); } - if (say_date) { - say_dow = say_day = say_month = say_year = 1; - say_today = say_yesterday = 0; - } - if (say_time) { if (say_date || say_today || say_yesterday || say_dow) { say_file("time/at.wav"); diff --git a/src/mod/say/mod_say_en/mod_say_en.c b/src/mod/say/mod_say_en/mod_say_en.c index 426de61752..99c2a2b1ff 100644 --- a/src/mod/say/mod_say_en/mod_say_en.c +++ b/src/mod/say/mod_say_en/mod_say_en.c @@ -355,6 +355,11 @@ static switch_status_t en_say_time(switch_say_file_handle_t *sh, char *tosay, sw break; } + if (say_date) { + say_year = say_month = say_day = say_dow = 1; + say_today = say_yesterday = 0; + } + if (say_today) { switch_say_file(sh, "time/today"); } @@ -364,12 +369,6 @@ static switch_status_t en_say_time(switch_say_file_handle_t *sh, char *tosay, sw if (say_dow) { switch_say_file(sh, "time/day-%d", tm.tm_wday); } - - if (say_date) { - say_year = say_month = say_day = say_dow = 1; - say_today = say_yesterday = 0; - } - if (say_month) { switch_say_file(sh, "time/mon-%d", tm.tm_mon); } diff --git a/src/mod/say/mod_say_it/mod_say_it.c b/src/mod/say/mod_say_it/mod_say_it.c index c94ea7990a..14276e98e5 100644 --- a/src/mod/say/mod_say_it/mod_say_it.c +++ b/src/mod/say/mod_say_it/mod_say_it.c @@ -390,7 +390,7 @@ static switch_status_t it_say_time(switch_core_session_t *session, char *tosay, } if (say_date) { - say_year = say_month = say_day = say_dow = 1; + say_year = say_month = say_day = say_dow = 0; say_today = say_yesterday = 0; say_file("time/day-%d.wav", tm.tm_wday); diff --git a/src/switch_caller.c b/src/switch_caller.c index d3b835ec80..37a3683039 100644 --- a/src/switch_caller.c +++ b/src/switch_caller.c @@ -97,6 +97,12 @@ SWITCH_DECLARE(switch_caller_profile_t *) switch_caller_profile_new(switch_memor profile->callee_id_name = SWITCH_BLANK_STRING; profile->callee_id_number = SWITCH_BLANK_STRING; switch_set_flag(profile, SWITCH_CPF_SCREEN); + if (switch_core_test_flag(SCF_CPF_SOFT_PREFIX)) { + switch_set_flag(profile, SWITCH_CPF_SOFT_PREFIX); + } + if (switch_core_test_flag(SCF_CPF_SOFT_LOOKUP)) { + switch_set_flag(profile, SWITCH_CPF_SOFT_LOOKUP); + } profile->pool = pool; return profile; } @@ -301,6 +307,14 @@ SWITCH_DECLARE(const char *) switch_caller_get_field_by_name(switch_caller_profi return switch_core_sprintf(caller_profile->pool, "%" SWITCH_TIME_T_FMT, caller_profile->times->transferred); } + if (caller_profile->soft && switch_test_flag(caller_profile, SWITCH_CPF_SOFT_LOOKUP)) { + profile_node_t *pn; + for (pn = caller_profile->soft; pn; pn = pn->next) { + if (!strcasecmp(name, pn->var)) { + return pn->val; + } + } + } return NULL; } @@ -399,7 +413,12 @@ SWITCH_DECLARE(void) switch_caller_profile_event_set_data(switch_caller_profile_ profile_node_t *pn; for (pn = caller_profile->soft; pn; pn = pn->next) { - switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, pn->var, pn->val); + if (switch_test_flag(caller_profile, SWITCH_CPF_SOFT_PREFIX)) { + switch_snprintf(header_name, sizeof(header_name), "%s-%s", prefix, pn->var); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, header_name, pn->val); + } else { + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, pn->var, pn->val); + } } } diff --git a/src/switch_channel.c b/src/switch_channel.c index 684c4014ec..933317ad81 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -124,6 +124,12 @@ static struct switch_cause_table CAUSE_CHART[] = { {"INVALID_PROFILE", SWITCH_CAUSE_INVALID_PROFILE}, {"NO_PICKUP", SWITCH_CAUSE_NO_PICKUP}, {"SRTP_READ_ERROR", SWITCH_CAUSE_SRTP_READ_ERROR}, + {"BOWOUT", SWITCH_CAUSE_BOWOUT}, + {"BUSY_EVERYWHERE", SWITCH_CAUSE_BUSY_EVERYWHERE}, + {"DECLINE", SWITCH_CAUSE_DECLINE}, + {"DOES_NOT_EXIST_ANYWHERE", SWITCH_CAUSE_DOES_NOT_EXIST_ANYWHERE}, + {"NOT_ACCEPTABLE", SWITCH_CAUSE_NOT_ACCEPTABLE}, + {"UNWANTED", SWITCH_CAUSE_UNWANTED}, {NULL, 0} }; @@ -176,6 +182,7 @@ struct switch_channel { switch_hold_record_t *hold_record; switch_device_node_t *device_node; char *device_id; + switch_event_t *log_tags; }; static void process_device_hup(switch_channel_t *channel); @@ -741,6 +748,9 @@ SWITCH_DECLARE(void) switch_channel_uninit(switch_channel_t *channel) switch_event_destroy(&channel->api_list); switch_event_destroy(&channel->var_list); switch_event_destroy(&channel->app_list); + if (channel->log_tags) { + switch_event_destroy(&channel->log_tags); + } switch_mutex_unlock(channel->profile_mutex); } @@ -1412,6 +1422,40 @@ SWITCH_DECLARE(void) switch_channel_set_presence_data_vals(switch_channel_t *cha switch_safe_free(data_copy); } +SWITCH_DECLARE(switch_status_t) switch_channel_set_log_tag(switch_channel_t *channel, const char *tagname, const char *tagvalue) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_assert(channel != NULL); + switch_mutex_lock(channel->profile_mutex); + if (!zstr(tagname)) { + if (!channel->log_tags) { + switch_event_create_plain(&channel->log_tags, SWITCH_EVENT_CHANNEL_DATA); + } + if (zstr(tagvalue)) { + switch_event_del_header(channel->log_tags, tagname); + } else { + switch_event_add_header_string(channel->log_tags, SWITCH_STACK_BOTTOM, tagname, tagvalue); + } + status = SWITCH_STATUS_SUCCESS; + } + switch_mutex_unlock(channel->profile_mutex); + return status; +} + +SWITCH_DECLARE(switch_status_t) switch_channel_get_log_tags(switch_channel_t *channel, switch_event_t **log_tags) +{ + switch_status_t status = SWITCH_STATUS_FALSE; + switch_assert(channel != NULL); + if (!channel->log_tags) { + return status; + } + switch_mutex_lock(channel->profile_mutex); + if (channel->log_tags && log_tags) { + status = switch_event_dup(log_tags, channel->log_tags); + } + switch_mutex_unlock(channel->profile_mutex); + return status; +} SWITCH_DECLARE(switch_status_t) switch_channel_set_variable_var_check(switch_channel_t *channel, const char *varname, const char *value, switch_bool_t var_check) diff --git a/src/switch_core.c b/src/switch_core.c index ca87b5f8cd..0fb040fbbd 100644 --- a/src/switch_core.c +++ b/src/switch_core.c @@ -1370,7 +1370,7 @@ typedef struct { static switch_ip_list_t IP_LIST = { 0 }; -SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token) +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_port_token(const char *ip_str, int port, const char *list_name, const char **token) { switch_network_list_t *list; ip_t ip, mask, net; @@ -1398,9 +1398,9 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ if ((list = switch_core_hash_find(IP_LIST.hash, list_name))) { if (ipv6) { - ok = switch_network_list_validate_ip6_token(list, ip, token); + ok = switch_network_list_validate_ip6_port_token(list, ip, port, token); } else { - ok = switch_network_list_validate_ip_token(list, ip.v4, token); + ok = switch_network_list_validate_ip_port_token(list, ip.v4, port, token); } } else if (strchr(list_name, '/')) { if (strchr(list_name, ',')) { @@ -1443,6 +1443,10 @@ SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_ return ok; } +SWITCH_DECLARE(switch_bool_t) switch_check_network_list_ip_token(const char *ip_str, const char *list_name, const char **token) +{ + return switch_check_network_list_ip_port_token(ip_str, 0, list_name, token); +} SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) { @@ -1589,9 +1593,12 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) for (x_node = switch_xml_child(x_list, "node"); x_node; x_node = x_node->next) { - const char *cidr = NULL, *host = NULL, *mask = NULL, *domain = NULL; + const char *cidr = NULL, *host = NULL, *mask = NULL, *domain = NULL, *port = NULL; switch_bool_t ok = default_type; const char *type = switch_xml_attr(x_node, "type"); + switch_network_port_range_t port_range; + char *argv[MAX_NETWORK_PORTS] = { 0 }; + int argc = 0, i; if (type) { ok = switch_true(type); @@ -1602,6 +1609,25 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) mask = switch_xml_attr(x_node, "mask"); domain = switch_xml_attr(x_node, "domain"); + memset(&port_range, 0, sizeof(switch_network_port_range_t)); + + if( (port = switch_xml_attr(x_node, "port")) != NULL) { + port_range.port = atoi(port); + } + + if( (port = switch_xml_attr(x_node, "ports")) != NULL) { + argc = switch_separate_string((char*)port, ',', argv, (sizeof(argv) / sizeof(argv[0]))); + for(i=0; i < argc; i++) { + port_range.ports[i] = atoi(argv[i]); + } + } + if( (port = switch_xml_attr(x_node, "port-min")) != NULL) { + port_range.min_port = atoi(port); + } + if( (port = switch_xml_attr(x_node, "port-max")) != NULL) { + port_range.max_port = atoi(port); + } + if (domain) { switch_event_t *my_params = NULL; switch_xml_t x_domain, xml_root; @@ -1646,7 +1672,7 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) if (id && user_cidr) { char *token = switch_mprintf("%s@%s", id, domain); switch_assert(token); - switch_network_list_add_cidr_token(list, user_cidr, ok, token); + switch_network_list_add_cidr_port_token(list, user_cidr, ok, token, &port_range); free(token); } } @@ -1656,13 +1682,13 @@ SWITCH_DECLARE(void) switch_load_network_lists(switch_bool_t reload) switch_xml_free(xml_root); } else if (cidr) { - switch_network_list_add_cidr(list, cidr, ok); + switch_network_list_add_cidr_port_token(list, cidr, ok, NULL, &port_range); } else if (host && mask) { - switch_network_list_add_host_mask(list, host, mask, ok); + switch_network_list_add_host_port_mask(list, host, mask, ok, &port_range); } - - switch_core_hash_insert(IP_LIST.hash, name, list); } + + switch_core_hash_insert(IP_LIST.hash, name, list); } } @@ -2340,6 +2366,20 @@ static void switch_load_core_config(const char *file) "rtp-retain-crypto-keys enabled. Could be used to decrypt secure media.\n"); } switch_core_set_variable("rtp_retain_crypto_keys", val); + } else if (!strcasecmp(var, "caller-profile-soft-variables-uses-prefix") && !zstr(val)) { + int v = switch_true(val); + if (v) { + switch_set_flag((&runtime), SCF_CPF_SOFT_PREFIX); + } else { + switch_clear_flag((&runtime), SCF_CPF_SOFT_PREFIX); + } + } else if (!strcasecmp(var, "caller-profile-soft-lookup-values") && !zstr(val)) { + int v = switch_true(val); + if (v) { + switch_set_flag((&runtime), SCF_CPF_SOFT_LOOKUP); + } else { + switch_clear_flag((&runtime), SCF_CPF_SOFT_LOOKUP); + } } } } diff --git a/src/switch_core_file.c b/src/switch_core_file.c index 8fc0008b78..ca5a340214 100644 --- a/src/switch_core_file.c +++ b/src/switch_core_file.c @@ -404,6 +404,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_perform_file_open(const char *file, if (fh->real_channels != fh->channels && (flags & SWITCH_FILE_FLAG_READ) && !(fh->flags & SWITCH_FILE_NOMUX)) { + fh->cur_channels = fh->real_channels; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "File has %d channels, muxing to %d channel%s will occur.\n", fh->real_channels, fh->channels, fh->channels == 1 ? "" : "s"); } @@ -639,6 +640,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, if (fh->pre_buffer) { switch_size_t rlen, blen; + switch_size_t datalen_adj = fh->pre_buffer_datalen; switch_status_t status = SWITCH_STATUS_SUCCESS; int asis = switch_test_flag(fh, SWITCH_FILE_NATIVE); @@ -646,8 +648,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_file_write(switch_file_handle_t *fh, rlen = switch_buffer_inuse(fh->pre_buffer); - if (rlen >= fh->pre_buffer_datalen) { - if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, fh->pre_buffer_datalen))) { + if (fh->pre_buffer_datalen % fh->channels) { + datalen_adj = fh->pre_buffer_datalen - (fh->pre_buffer_datalen % fh->channels); + } + + if (rlen >= datalen_adj) { + if ((blen = switch_buffer_read(fh->pre_buffer, fh->pre_buffer_data, datalen_adj))) { if (!asis) blen /= 2; if (fh->channels > 1) diff --git a/src/switch_core_media.c b/src/switch_core_media.c index 4df391da54..48861b1e3d 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -4008,6 +4008,21 @@ static switch_call_direction_t switch_ice_direction(switch_rtp_engine_t *engine, return r; } +static switch_core_media_ice_type_t switch_determine_ice_type(switch_rtp_engine_t *engine, switch_core_session_t *session) { + switch_core_media_ice_type_t ice_type = ICE_VANILLA; + + if (switch_channel_var_true(session->channel, "ice_lite")) { + ice_type |= ICE_CONTROLLED; + ice_type |= ICE_LITE; + } else { + switch_call_direction_t direction = switch_ice_direction(engine, session); + if (direction == SWITCH_CALL_DIRECTION_INBOUND) { + ice_type |= ICE_CONTROLLED; + } + } + + return ice_type; +} //? static switch_status_t ip_choose_family(switch_media_handle_t *smh, const char *ip) @@ -4090,7 +4105,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t for (attr_idx = 0; attr_idx < 2 && !(ice_seen && cand_seen); attr_idx++) { for (attr = attrs[attr_idx]; attr; attr = attr->a_next) { char *data; - char *fields[15]; + char *fields[32] = {0}; int argc = 0, j = 0; if (zstr(attr->a_name)) { @@ -4205,13 +4220,13 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Drop %s Candidate cid: %d proto: %s type: %s addr: %s:%s (no network path)\n", type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", - cid+1, fields[2], fields[7], fields[4], fields[5]); + cid+1, fields[2], fields[7] ? fields[7] : "N/A", fields[4], fields[5]); continue; } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_DEBUG, "Save %s Candidate cid: %d proto: %s type: %s addr: %s:%s\n", type == SWITCH_MEDIA_TYPE_VIDEO ? "video" : "audio", - cid+1, fields[2], fields[7], fields[4], fields[5]); + cid+1, fields[2], fields[7] ? fields[7] : "N/A", fields[4], fields[5]); } @@ -4224,7 +4239,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t j = 6; - while(j < argc && fields[j+1]) { + while(j < argc && j <= sizeof(fields)/sizeof(char*) && fields[j+1] && engine->ice_in.cand_idx[cid] < MAX_CAND - 1) { if (!strcasecmp(fields[j], "typ")) { engine->ice_in.cands[engine->ice_in.cand_idx[cid]][cid].cand_type = switch_core_session_strdup(smh->session, fields[j+1]); } else if (!strcasecmp(fields[j], "raddr")) { @@ -4405,8 +4420,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(engine, smh->session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(engine, smh->session), &engine->ice_in #endif ); @@ -4460,8 +4474,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(engine, smh->session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(engine, smh->session), &engine->ice_in #endif ); @@ -4610,7 +4623,7 @@ static void media_flow_get_mode(switch_media_flow_t smode, const char **mode_str } -static void check_stream_changes(switch_core_session_t *session, switch_sdp_type_t sdp_type) +static void check_stream_changes(switch_core_session_t *session, const char *r_sdp, switch_sdp_type_t sdp_type) { switch_core_session_t *other_session = NULL; switch_core_session_message_t *msg; @@ -4624,6 +4637,15 @@ static void check_stream_changes(switch_core_session_t *session, switch_sdp_type if (other_session) { switch_channel_set_flag(other_session->channel, CF_PROCESSING_STREAM_CHANGE); switch_channel_set_flag(session->channel, CF_AWAITING_STREAM_CHANGE); + + if (sdp_type == SDP_TYPE_REQUEST && r_sdp) { + const char *filter_codec_string = switch_channel_get_variable(session->channel, "filter_codec_string"); + + switch_channel_set_variable(session->channel, "codec_string", NULL); + switch_core_media_merge_sdp_codec_string(session, r_sdp, sdp_type, filter_codec_string); + } + switch_core_session_check_outgoing_crypto(other_session); + msg = switch_core_session_alloc(other_session, sizeof(*msg)); msg->message_id = SWITCH_MESSAGE_INDICATE_MEDIA_RENEG; msg->string_arg = switch_core_session_sprintf(other_session, "=%s", switch_channel_get_variable(session->channel, "ep_codec_string")); @@ -4634,22 +4656,33 @@ static void check_stream_changes(switch_core_session_t *session, switch_sdp_type if (other_session) { if (sdp_type == SDP_TYPE_RESPONSE && switch_channel_test_flag(session->channel, CF_PROCESSING_STREAM_CHANGE)) { + switch_channel_clear_flag(session->channel, CF_PROCESSING_STREAM_CHANGE); + if (switch_channel_test_flag(other_session->channel, CF_AWAITING_STREAM_CHANGE)) { + uint8_t proceed = 1; + const char *sdp_in, *other_ep; + + if ((other_ep = switch_channel_get_variable(session->channel, "ep_codec_string"))) { + switch_channel_set_variable(other_session->channel, "codec_string", other_ep); + } + + sdp_in = switch_channel_get_variable(other_session->channel, SWITCH_R_SDP_VARIABLE); + switch_core_media_negotiate_sdp(other_session, sdp_in, &proceed, SDP_TYPE_REQUEST); + switch_core_media_activate_rtp(other_session); msg = switch_core_session_alloc(other_session, sizeof(*msg)); msg->message_id = SWITCH_MESSAGE_INDICATE_RESPOND; msg->from = __FILE__; - + + switch_channel_set_flag(other_session->channel, CF_AWAITING_STREAM_CHANGE); switch_core_session_queue_message(other_session, msg); } - - switch_channel_clear_flag(session->channel, CF_PROCESSING_STREAM_CHANGE); } switch_core_session_rwunlock(other_session); } } -static void switch_core_media_set_smode(switch_core_session_t *session, switch_media_type_t type, switch_media_flow_t smode, switch_sdp_type_t sdp_type) +SWITCH_DECLARE(void) switch_core_media_set_smode(switch_core_session_t *session, switch_media_type_t type, switch_media_flow_t smode, switch_sdp_type_t sdp_type) { switch_media_handle_t *smh; switch_rtp_engine_t *engine; @@ -4890,13 +4923,13 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s switch(m->m_type) { case sdp_media_audio: smh->rejected_streams[smh->rej_idx++] = sdp_media_audio; - break; + continue; case sdp_media_video: smh->rejected_streams[smh->rej_idx++] = sdp_media_video; - break; + continue; case sdp_media_image: smh->rejected_streams[smh->rej_idx++] = sdp_media_image; - break; + continue; default: break; } @@ -5959,6 +5992,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s memset(near_matches, 0, sizeof(near_matches[0]) * MAX_MATCHES); switch_channel_set_variable(session->channel, "video_possible", "true"); + switch_channel_set_flag(session->channel, CF_VIDEO_POSSIBLE); switch_channel_set_flag(session->channel, CF_VIDEO_SDP_RECVD); connection = sdp->sdp_connection; @@ -6148,6 +6182,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s vmatch = 1; v_engine->codec_negotiated = 1; + v_engine->payload_map = NULL; for(j = 0; j < m_idx && smh->num_negotiated_codecs < SWITCH_MAX_CODECS; j++) { payload_map_t *pmap = switch_core_media_add_payload_map(session, @@ -6334,7 +6369,7 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s smh->mparams->cng_pt = cng_pt; smh->mparams->cng_rate = cng_rate; - check_stream_changes(session, sdp_type); + check_stream_changes(session, r_sdp, sdp_type); return match || vmatch || tmatch || fmatch; } @@ -8353,6 +8388,13 @@ static void check_dtls_reinvite(switch_core_session_t *session, switch_rtp_engin if (switch_channel_test_flag(session->channel, CF_REINVITE) && engine->new_dtls) { if (!zstr(engine->local_dtls_fingerprint.str) && switch_rtp_has_dtls() && dtls_ok(session)) { + +#ifdef HAVE_OPENSSL_DTLSv1_2_method + uint8_t want_DTLSv1_2 = 1; +#else + uint8_t want_DTLSv1_2 = 0; +#endif // HAVE_OPENSSL_DTLSv1_2_method + dtls_type_t xtype, dtype = engine->dtls_controller ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_INFO, "RE-SETTING %s DTLS\n", type2str(engine->type)); @@ -8360,11 +8402,16 @@ static void check_dtls_reinvite(switch_core_session_t *session, switch_rtp_engin xtype = DTLS_TYPE_RTP; if (engine->rtcp_mux > 0) xtype |= DTLS_TYPE_RTCP; - switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype); + if (switch_channel_var_true(session->channel, "legacyDTLS")) { + switch_channel_clear_flag(session->channel, CF_WANT_DTLSv1_2); + want_DTLSv1_2 = 0; + } + + switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); if (engine->rtcp_mux < 1) { xtype = DTLS_TYPE_RTCP; - switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype); + switch_rtp_add_dtls(engine->rtp_session, &engine->local_dtls_fingerprint, &engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); } } @@ -8387,6 +8434,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi switch_media_handle_t *smh; int is_reinvite = 0; +#ifdef HAVE_OPENSSL_DTLSv1_2_method + uint8_t want_DTLSv1_2 = 1; +#else + uint8_t want_DTLSv1_2 = 0; +#endif + switch_assert(session); if (!(smh = session->media_handle)) { @@ -8415,6 +8468,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi if (a_engine->crypto_type != CRYPTO_INVALID) { switch_channel_set_flag(session->channel, CF_SECURE); } + + if (want_DTLSv1_2) { + switch_channel_set_flag(session->channel, CF_WANT_DTLSv1_2); + } if (switch_channel_test_flag(session->channel, CF_PROXY_MODE)) { status = SWITCH_STATUS_SUCCESS; @@ -8699,8 +8756,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(a_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(a_engine, session), &a_engine->ice_in #endif ); @@ -8753,8 +8809,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(a_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(a_engine, session), &a_engine->ice_in #endif ); @@ -8773,11 +8828,16 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi xtype = DTLS_TYPE_RTP; if (a_engine->rtcp_mux > 0 && smh->mparams->rtcp_audio_interval_msec) xtype |= DTLS_TYPE_RTCP; - switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype); + if (switch_channel_var_true(session->channel, "legacyDTLS")) { + switch_channel_clear_flag(session->channel, CF_WANT_DTLSv1_2); + want_DTLSv1_2 = 0; + } + + switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); if (a_engine->rtcp_mux < 1 && smh->mparams->rtcp_audio_interval_msec) { xtype = DTLS_TYPE_RTCP; - switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype); + switch_rtp_add_dtls(a_engine->rtp_session, &a_engine->local_dtls_fingerprint, &a_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); } } @@ -9065,8 +9125,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(t_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(t_engine, session), &t_engine->ice_in #endif ); @@ -9117,8 +9176,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(t_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(t_engine, session), &t_engine->ice_in #endif ); @@ -9135,12 +9193,17 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi dtype = t_engine->dtls_controller ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER; xtype = DTLS_TYPE_RTP; if (t_engine->rtcp_mux > 0 && smh->mparams->rtcp_text_interval_msec) xtype |= DTLS_TYPE_RTCP; + + if (switch_channel_var_true(session->channel, "legacyDTLS")) { + switch_channel_clear_flag(session->channel, CF_WANT_DTLSv1_2); + want_DTLSv1_2 = 0; + } - switch_rtp_add_dtls(t_engine->rtp_session, &t_engine->local_dtls_fingerprint, &t_engine->remote_dtls_fingerprint, dtype | xtype); + switch_rtp_add_dtls(t_engine->rtp_session, &t_engine->local_dtls_fingerprint, &t_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); if (t_engine->rtcp_mux < 1 && smh->mparams->rtcp_text_interval_msec) { xtype = DTLS_TYPE_RTCP; - switch_rtp_add_dtls(t_engine->rtp_session, &t_engine->local_dtls_fingerprint, &t_engine->remote_dtls_fingerprint, dtype | xtype); + switch_rtp_add_dtls(t_engine->rtp_session, &t_engine->local_dtls_fingerprint, &t_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); } } @@ -9393,8 +9456,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(v_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(v_engine, session), &v_engine->ice_in #endif ); @@ -9446,8 +9508,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi ICE_GOOGLE_JINGLE, NULL #else - switch_ice_direction(v_engine, session) == - SWITCH_CALL_DIRECTION_OUTBOUND ? ICE_VANILLA : (ICE_VANILLA | ICE_CONTROLLED), + switch_determine_ice_type(v_engine, session), &v_engine->ice_in #endif ); @@ -9464,12 +9525,18 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_activate_rtp(switch_core_sessi dtype = v_engine->dtls_controller ? DTLS_TYPE_CLIENT : DTLS_TYPE_SERVER; xtype = DTLS_TYPE_RTP; if (v_engine->rtcp_mux > 0 && smh->mparams->rtcp_video_interval_msec) xtype |= DTLS_TYPE_RTCP; + - switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype); + if (switch_channel_var_true(session->channel, "legacyDTLS")) { + switch_channel_clear_flag(session->channel, CF_WANT_DTLSv1_2); + want_DTLSv1_2 = 0; + } + + switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); if (v_engine->rtcp_mux < 1 && smh->mparams->rtcp_video_interval_msec) { xtype = DTLS_TYPE_RTCP; - switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype); + switch_rtp_add_dtls(v_engine->rtp_session, &v_engine->local_dtls_fingerprint, &v_engine->remote_dtls_fingerprint, dtype | xtype, want_DTLSv1_2); } } @@ -10364,6 +10431,9 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess "%s", username, smh->owner_id, smh->session_id, family, ip, username, family, ip, srbuf); + if (switch_channel_test_flag(smh->session->channel, CF_ICE) && switch_channel_var_true(session->channel, "ice_lite")) { + switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-lite\r\n"); + } if (a_engine->rmode == SWITCH_MEDIA_FLOW_DISABLED) { goto video; @@ -10580,9 +10650,6 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess } switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=end-of-candidates\r\n"); - if (switch_true(switch_channel_get_variable(session->channel, "ice_lite"))) { - switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ice-lite\r\n"); - } switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u cname:%s\r\n", a_engine->ssrc, smh->cname); switch_snprintf(buf + strlen(buf), SDPBUFLEN - strlen(buf), "a=ssrc:%u msid:%s a0\r\n", a_engine->ssrc, smh->msid); @@ -11538,7 +11605,7 @@ SWITCH_DECLARE(void) switch_core_media_gen_local_sdp(switch_core_session_t *sess switch_core_media_set_local_sdp(session, buf, SWITCH_TRUE); - check_stream_changes(session, sdp_type); + check_stream_changes(session, NULL, sdp_type); switch_safe_free(buf); } @@ -13057,6 +13124,15 @@ SWITCH_DECLARE(switch_jb_t *) switch_core_media_get_jb(switch_core_session_t *se //? SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, switch_sdp_type_t sdp_type) { + switch_core_media_merge_sdp_codec_string(session, r_sdp, sdp_type, switch_core_media_get_codec_string(session)); +} + +SWITCH_DECLARE(void) switch_core_media_merge_sdp_codec_string(switch_core_session_t *session, const char *r_sdp, + switch_sdp_type_t sdp_type, const char *codec_string) +{ + + + sdp_parser_t *parser; sdp_session_t *sdp; switch_media_handle_t *smh; @@ -13071,10 +13147,15 @@ SWITCH_DECLARE(void) switch_core_media_set_sdp_codec_string(switch_core_session_ switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Setting NULL SDP is invalid\n"); return; } + + if (zstr(codec_string)) { + codec_string = switch_core_media_get_codec_string(session); + } + if ((parser = sdp_parse(NULL, r_sdp, (int) strlen(r_sdp), 0))) { if ((sdp = sdp_session(parser))) { - switch_core_media_set_r_sdp_codec_string(session, switch_core_media_get_codec_string(session), sdp, sdp_type); + switch_core_media_set_r_sdp_codec_string(session, codec_string, sdp, sdp_type); } sdp_parser_free(parser); @@ -13212,13 +13293,21 @@ static void switch_core_media_set_r_sdp_codec_string(switch_core_session_t *sess if ((m->m_type == sdp_media_audio || m->m_type == sdp_media_video) && m->m_port) { for (map = m->m_rtpmaps; map; map = map->rm_next) { - for (attr = m->m_attributes; attr; attr = attr->a_next) { + int found = 0; + for (attr = m->m_attributes; attr && found < 2; attr = attr->a_next) { if (zstr(attr->a_name)) { continue; } if (!strcasecmp(attr->a_name, "ptime") && attr->a_value) { ptime = atoi(attr->a_value); - break; + found++; + } + if (!strcasecmp(attr->a_name, "rtcp-mux")) { + if (switch_channel_var_true(channel, "rtcp_mux_auto_detect")) { + switch_log_printf(SWITCH_CHANNEL_CHANNEL_LOG(channel), SWITCH_LOG_DEBUG, "setting rtcp-mux from sdp\n"); + switch_channel_set_variable(channel, "rtcp_mux", "true"); + } + found++; } } switch_core_media_add_payload_map(session, diff --git a/src/switch_core_session.c b/src/switch_core_session.c index a27b4ce284..8a4ca0663a 100644 --- a/src/switch_core_session.c +++ b/src/switch_core_session.c @@ -1580,6 +1580,17 @@ SWITCH_DECLARE(void) switch_core_session_perform_destroy(switch_core_session_t * } } + if ((*session)->event_queue) { + switch_status_t status; + void *pop; + while ((status = (switch_status_t) switch_queue_trypop((*session)->event_queue, &pop)) == SWITCH_STATUS_SUCCESS) { + if (pop) { + switch_event_t *event = (switch_event_t *) pop; + switch_event_destroy(&event); + } + } + } + pool = (*session)->pool; //#ifndef NDEBUG //memset(*session, 0, sizeof(switch_core_session_t)); @@ -2404,6 +2415,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_session_request_uuid(switch_ session->enc_read_frame.buflen = sizeof(session->enc_read_buf); switch_mutex_init(&session->mutex, SWITCH_MUTEX_NESTED, session->pool); + switch_mutex_init(&session->stack_count_mutex, SWITCH_MUTEX_NESTED, session->pool); switch_mutex_init(&session->resample_mutex, SWITCH_MUTEX_NESTED, session->pool); switch_mutex_init(&session->codec_read_mutex, SWITCH_MUTEX_NESTED, session->pool); switch_mutex_init(&session->codec_write_mutex, SWITCH_MUTEX_NESTED, session->pool); @@ -2758,7 +2770,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * const char *var; switch_channel_t *channel = switch_core_session_get_channel(session); char *expanded = NULL; - const char *app, *app_uuid_var; + const char *app, *app_uuid_var, *app_uuid_name; switch_core_session_message_t msg = { 0 }; char delim = ','; int scope = 0; @@ -2772,6 +2784,10 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * switch_uuid_str(uuid_str, sizeof(uuid_str)); } + if((app_uuid_name = switch_channel_get_variable(channel, "app_uuid_name"))) { + switch_channel_set_variable(channel, "app_uuid_name", NULL); + } + switch_assert(application_interface); app = application_interface->interface_name; @@ -2806,11 +2822,11 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * if ( switch_core_test_flag(SCF_DIALPLAN_TIMESTAMPS) ) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", - switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "EXECUTE [depth=%d] %s %s(%s)\n", + switch_core_session_stack_count(session, 0), switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); } else { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE %s %s(%s)\n", - switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG_CLEAN(session), SWITCH_LOG_DEBUG, "EXECUTE [depth=%d] %s %s(%s)\n", + switch_core_session_stack_count(session, 0), switch_channel_get_name(session->channel), app, switch_str_nil(expanded)); } if ((var = switch_channel_get_variable(session->channel, "verbose_presence")) && switch_true(var)) { @@ -2856,6 +2872,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application", application_interface->interface_name); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-Data", expanded); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-UUID", app_uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-UUID-Name", app_uuid_name); switch_event_fire(&event); } @@ -2880,6 +2897,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-Data", expanded); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-Response", resp ? resp : "_none_"); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-UUID", app_uuid); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Application-UUID-Name", app_uuid_name); switch_event_fire(&event); } @@ -2899,10 +2917,14 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_exec(switch_core_session_t * SWITCH_DECLARE(uint32_t) switch_core_session_stack_count(switch_core_session_t *session, int x) { + uint32_t stack_count = 0; + switch_mutex_lock(session->stack_count_mutex); if (x > 0) session->stack_count++; else if (x < 0) session->stack_count--; - return session->stack_count; + stack_count = session->stack_count; + switch_mutex_unlock(session->stack_count_mutex); + return stack_count; } SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_session_t *session, const char *exten, const char *dialplan, @@ -2911,6 +2933,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_se char *dp[25]; char *dpstr; int argc, x, count = 0; + uint32_t stack_count = 0; switch_caller_profile_t *profile, *new_profile, *pp = NULL; switch_channel_t *channel = switch_core_session_get_channel(session); switch_dialplan_interface_t *dialplan_interface = NULL; @@ -2921,13 +2944,13 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_se return SWITCH_STATUS_FALSE; } - if (session->stack_count > SWITCH_MAX_STACKS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error %s too many stacked extensions\n", - switch_channel_get_name(session->channel)); + if ((stack_count = switch_core_session_stack_count(session, 0)) > SWITCH_MAX_STACKS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error %s too many stacked extensions [depth=%d]\n", + switch_channel_get_name(session->channel), stack_count); return SWITCH_STATUS_FALSE; } - session->stack_count++; + switch_core_session_stack_count(session, 1); new_profile = switch_caller_profile_clone(session, profile); new_profile->destination_number = switch_core_strdup(new_profile->pool, exten); @@ -2991,7 +3014,8 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_se } while (switch_channel_ready(channel) && extension->current_application) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Execute %s(%s)\n", + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Execute [depth=%d] %s(%s)\n", + switch_core_session_stack_count(session, 0), extension->current_application->application_name, switch_str_nil(extension->current_application->application_data)); if (switch_core_session_execute_application(session, @@ -3006,7 +3030,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_execute_exten(switch_core_se done: switch_channel_set_hunt_caller_profile(channel, NULL); - session->stack_count--; + switch_core_session_stack_count(session, -1); return status; } diff --git a/src/switch_core_sqldb.c b/src/switch_core_sqldb.c index 49a10e06c3..02e6897778 100644 --- a/src/switch_core_sqldb.c +++ b/src/switch_core_sqldb.c @@ -3380,13 +3380,7 @@ switch_status_t switch_core_sqldb_start(switch_memory_pool_t *pool, switch_bool_ return SWITCH_STATUS_FALSE; } - if (runtime.odbc_dsn) { - runtime.odbc_dsn = NULL; - runtime.odbc_dbtype = DBTYPE_DEFAULT; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Falling back to core_db.\n"); - goto top; - } - + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "CORE DATABASE INITIALIZATION FAILURE! CHECK `core-db-dsn`!\n"); switch_clear_flag((&runtime), SCF_USE_SQL); return SWITCH_STATUS_FALSE; diff --git a/src/switch_core_video.c b/src/switch_core_video.c index 96a39a107f..d199df5ccd 100644 --- a/src/switch_core_video.c +++ b/src/switch_core_video.c @@ -579,7 +579,7 @@ SWITCH_DECLARE(void) switch_img_copy(switch_image_t *img, switch_image_t **new_i if (*new_img) { if ((*new_img)->fmt != SWITCH_IMG_FMT_I420 && (*new_img)->fmt != SWITCH_IMG_FMT_ARGB) return; - if (img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_w ) { + if (img->d_w != (*new_img)->d_w || img->d_h != (*new_img)->d_h ) { new_fmt = (*new_img)->fmt; switch_img_free(new_img); } diff --git a/src/switch_ivr.c b/src/switch_ivr.c index 920e4edb4a..a448a5e67e 100644 --- a/src/switch_ivr.c +++ b/src/switch_ivr.c @@ -550,6 +550,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se if (cmd_hash == CMD_EXECUTE) { char *app_name = switch_event_get_header(event, "execute-app-name"); char *event_uuid = switch_event_get_header(event, "event-uuid"); + char *event_uuid_name = switch_event_get_header(event, "event-uuid-name"); char *app_arg = switch_event_get_header(event, "execute-app-arg"); char *content_type = switch_event_get_header(event, "content-type"); char *loop_h = switch_event_get_header(event, "loops"); @@ -622,13 +623,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_event(switch_core_session_t *se for (x = 0; x < loops || loops < 0; x++) { switch_time_t b4, aftr; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Command Execute %s(%s)\n", - switch_channel_get_name(channel), app_name, switch_str_nil(app_arg)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s Command Execute [depth=%d] %s(%s)\n", + switch_channel_get_name(channel), switch_core_session_stack_count(session, 0), app_name, switch_str_nil(app_arg)); b4 = switch_micro_time_now(); if (event_uuid) { switch_channel_set_variable(channel, "app_uuid", event_uuid); } + if (event_uuid_name) { + switch_channel_set_variable(channel, "app_uuid_name", event_uuid_name); + } switch_channel_set_variable_printf(channel, "current_loop", "%d", x + 1); switch_channel_set_variable_printf(channel, "total_loops", "%d", loops); @@ -821,6 +825,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_process_indications(switch_core_sessi switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); } break; + case SWITCH_MESSAGE_INDICATE_RESPOND: + switch_core_session_receive_message(session, message); + status = SWITCH_STATUS_SUCCESS; + break; + default: status = SWITCH_STATUS_FALSE; break; @@ -897,17 +906,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_next_signal_data(switch_core_se SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_t *session) { - int x = 0; switch_channel_t *channel; - - if (switch_core_session_stack_count(session, 0) > SWITCH_MAX_STACKS) { - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error %s too many stacked extensions\n", - switch_core_session_get_name(session)); + uint32_t stack_count = 0; + if ((stack_count = switch_core_session_stack_count(session, 0)) > SWITCH_MAX_STACKS) { + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error %s too many stacked extensions [depth=%d]\n", + switch_core_session_get_name(session), stack_count); return SWITCH_STATUS_FALSE; } switch_core_session_stack_count(session, 1); - + switch_ivr_parse_all_messages(session); channel = switch_core_session_get_channel(session); @@ -920,9 +928,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_parse_all_events(switch_core_session_ } } - while (switch_ivr_parse_next_event(session) == SWITCH_STATUS_SUCCESS) { - x++; - } + while (switch_ivr_parse_next_event(session) == SWITCH_STATUS_SUCCESS) {} done: switch_core_session_stack_count(session, -1); @@ -2095,7 +2101,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ const char *forwardvar = switch_channel_get_variable(channel, forwardvar_name); int forwardval = 70; const char *use_dialplan = dialplan, *use_context = context; - + switch_media_flow_t flow; + if (zstr(forwardvar)) { forwardvar_name = SWITCH_MAX_FORWARDS_VARIABLE; /* fall back to max_forwards variable for setting maximum */ forwardvar = switch_channel_get_variable(channel, forwardvar_name); @@ -2108,6 +2115,16 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_session_transfer(switch_core_session_ return SWITCH_STATUS_FALSE; } + if ((flow = switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_AUDIO)) != SWITCH_MEDIA_FLOW_SENDRECV) { + switch_core_session_message_t msg = { 0 }; + + msg.message_id = SWITCH_MESSAGE_INDICATE_MEDIA_RENEG; + msg.from = __FILE__; + + switch_core_media_set_smode(session, SWITCH_MEDIA_TYPE_AUDIO, SWITCH_MEDIA_FLOW_SENDRECV, SDP_TYPE_REQUEST); + switch_core_session_receive_message(session, &msg); + } + max_forwards = switch_core_session_sprintf(session, "%d", forwardval); switch_channel_set_variable(channel, forwardvar_name, max_forwards); diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index db4ceac9cc..113f4463d5 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -1146,6 +1146,7 @@ struct record_helper { uint32_t vwrites; const char *completion_cause; int start_event_sent; + switch_event_t *variables; }; /** @@ -1185,6 +1186,24 @@ static switch_bool_t is_silence_frame(switch_frame_t *frame, int silence_thresho return is_silence; } +static void merge_recording_variables(struct record_helper *rh, switch_event_t *event) +{ + switch_event_header_t *hi; + if (rh->variables) { + for (hi = rh->variables->headers; hi; hi = hi->next) { + char buf[1024]; + char *vvar = NULL, *vval = NULL; + + vvar = (char *) hi->name; + vval = (char *) hi->value; + + switch_assert(vvar && vval); + switch_snprintf(buf, sizeof(buf), "Recording-Variable-%s", vvar); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, buf, vval); + } + } +} + static void send_record_stop_event(switch_channel_t *channel, switch_codec_implementation_t *read_impl, struct record_helper *rh) { switch_event_t *event; @@ -1205,10 +1224,12 @@ static void send_record_stop_event(switch_channel_t *channel, switch_codec_imple if (switch_event_create(&event, SWITCH_EVENT_RECORD_STOP) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); + merge_recording_variables(rh, event); if (!zstr(rh->completion_cause)) { switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-Completion-Cause", rh->completion_cause); } switch_event_fire(&event); + switch_event_safe_destroy(rh->variables); } } @@ -1311,6 +1332,7 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s if (switch_event_create(&event, SWITCH_EVENT_RECORD_START) == SWITCH_STATUS_SUCCESS) { switch_channel_event_set_data(channel, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Record-File-Path", rh->file); + merge_recording_variables(rh, event); switch_event_fire(&event); } } @@ -1760,6 +1782,11 @@ static void* switch_ivr_record_user_data_dup(switch_core_session_t *session, voi dup->file = switch_core_session_strdup(session, rh->file); dup->fh = switch_core_session_alloc(session, sizeof(switch_file_handle_t)); memcpy(dup->fh, rh->fh, sizeof(switch_file_handle_t)); + dup->variables = NULL; + if (rh->variables) { + switch_event_dup(&dup->variables, rh->variables); + switch_event_safe_destroy(rh->variables); + } return dup; } @@ -2538,7 +2565,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_eavesdrop_session(switch_core_session return status; } -SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh) +SWITCH_DECLARE(switch_status_t) switch_ivr_record_session_event(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh, switch_event_t *vars) { switch_channel_t *channel = switch_core_session_get_channel(session); const char *p; @@ -2904,6 +2931,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t } } + if(vars) { + switch_event_dup(&rh->variables, vars); + } + rh->hangup_on_error = hangup_on_error; if ((status = switch_core_media_bug_add(session, "session_record", file, @@ -2942,6 +2973,10 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_ivr_record_session(switch_core_session_t *session, const char *file, uint32_t limit, switch_file_handle_t *fh) +{ + return switch_ivr_record_session_event(session, file, limit, fh, NULL); +} typedef struct { SpeexPreprocessState *read_st; diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index 0ab870c6a5..c7fd49674a 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1259,7 +1259,20 @@ static switch_status_t uuid_bridge_on_soft_execute(switch_core_session_t *sessio switch_channel_set_state(channel, CS_EXECUTE); } } else { - switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + int hup = 1; + const char *var; + + if (switch_true(switch_channel_get_variable(channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE))) { + switch_ivr_park_session(session); + hup = 0; + } else if ((var = switch_channel_get_variable(channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE))) { + transfer_after_bridge(session, var); + hup = 0; + } + + if (hup) { + switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER); + } } done: diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index 8887670fa9..f482809994 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1364,6 +1364,11 @@ static switch_status_t setup_ringback(originate_global_t *oglobals, originate_st } SWITCH_IVR_VERIFY_SILENCE_DIVISOR(ringback->silence); } else { + if (ringback->audio_buffer) { + switch_buffer_destroy(&ringback->audio_buffer); + teletone_destroy_session(&ringback->ts); + } + switch_buffer_create_dynamic(&ringback->audio_buffer, 512, 1024, 0); switch_buffer_set_loops(ringback->audio_buffer, -1); diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index dd923be81a..908ca2e8aa 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -957,9 +957,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_record_file(switch_core_session_t *se } - if (read_impl.actual_samples_per_second) { + if (read_impl.actual_samples_per_second && fh->native_rate >= 1000) { switch_channel_set_variable_printf(channel, "record_seconds", "%d", fh->samples_out / fh->native_rate); - switch_channel_set_variable_printf(channel, "record_ms", "%d", fh->samples_out / (fh->native_rate/ 1000)); + switch_channel_set_variable_printf(channel, "record_ms", "%d", fh->samples_out / (fh->native_rate / 1000)); } @@ -1664,7 +1664,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } } - buflen = (FILE_STARTSAMPLES * sizeof(*abuf) * fh->cur_channels) > 0 ? fh->cur_channels : fh->channels; + buflen = FILE_STARTSAMPLES * sizeof(*abuf) * (fh->cur_channels > 0 ? fh->cur_channels : fh->channels); if (buflen > write_frame.buflen) { abuf = realloc(abuf, buflen); @@ -1682,9 +1682,9 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess } else if (fh->sp_audio_buffer && (eof || (switch_buffer_inuse(fh->sp_audio_buffer) > (switch_size_t) (framelen)))) { if (!(bread = switch_buffer_read(fh->sp_audio_buffer, abuf, framelen))) { if (eof) { - continue; - } else { break; + } else { + continue; } } @@ -1941,10 +1941,11 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "done playing file %s\n", file); switch_channel_set_variable_printf(channel, "playback_last_offset_pos", "%d", fh->offset_pos); - if (read_impl.samples_per_second) { + if (read_impl.samples_per_second && fh->native_rate >= 1000) { switch_channel_set_variable_printf(channel, "playback_seconds", "%d", fh->samples_in / fh->native_rate); switch_channel_set_variable_printf(channel, "playback_ms", "%d", fh->samples_in / (fh->native_rate / 1000)); } + switch_channel_set_variable_printf(channel, "playback_samples", "%d", fh->samples_in); if (switch_event_create(&event, SWITCH_EVENT_PLAYBACK_STOP) == SWITCH_STATUS_SUCCESS) { @@ -2082,7 +2083,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_silence(switch_core_session_ switch_channel_set_variable(channel, "wait_for_silence_timeout", "true"); switch_channel_set_variable_printf(channel, "wait_for_silence_listenhits", "%d", listening); switch_channel_set_variable_printf(channel, "wait_for_silence_silence_hits", "%d", silence_hits); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_wait_for_silence: TIMEOUT %d\n", countdown); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_wait_for_silence: TIMEOUT %d\n", countdown); break; } } @@ -2104,7 +2105,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_wait_for_silence(switch_core_session_ if (countdown) { if (!--countdown) { switch_channel_set_variable(channel, "wait_for_silence_timeout", "false"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_wait_for_silence: SILENCE DETECTED\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_wait_for_silence: SILENCE DETECTED\n"); break; } else { continue; @@ -2218,7 +2219,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_audio(switch_core_session_t *s if (sample_count <= 0) { switch_channel_set_variable(channel, "detect_audio_timeout", "true"); switch_channel_set_variable_printf(channel, "detect_audio_hits", "%d", hits); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_audio: TIMEOUT %d hits\n", hits); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_detect_audio: TIMEOUT %d hits\n", hits); break; } } @@ -2254,7 +2255,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_audio(switch_core_session_t *s if (hits > audio_hits) { switch_channel_set_variable(channel, "detect_audio_timeout", "false"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_audio: AUDIO DETECTED\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_detect_audio: AUDIO DETECTED\n"); break; } } @@ -2345,7 +2346,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_silence(switch_core_session_t if (sample_count <= 0) { switch_channel_set_variable(channel, "detect_silence_timeout", "true"); switch_channel_set_variable_printf(channel, "detect_silence_hits", "%d", hits); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_silence: TIMEOUT %d hits\n", hits); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_detect_silence: TIMEOUT %d hits\n", hits); break; } } @@ -2381,7 +2382,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_detect_silence(switch_core_session_t if (hits > silence_hits) { switch_channel_set_variable(channel, "detect_silence_timeout", "false"); - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "switch_ivr_detect_silence: SILENCE DETECTED\n"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "switch_ivr_detect_silence: SILENCE DETECTED\n"); break; } } diff --git a/src/switch_jitterbuffer.c b/src/switch_jitterbuffer.c index 206deb5806..d823e4709b 100644 --- a/src/switch_jitterbuffer.c +++ b/src/switch_jitterbuffer.c @@ -1140,8 +1140,8 @@ SWITCH_DECLARE(uint32_t) switch_jb_pop_nack(switch_jb_t *jb) seq = ntohs(*((uint16_t *) var)); then = (intptr_t) val; - if (then != 1 && switch_time_now() - then < RENACK_TIME) { - //jb_debug(jb, 3, "NACKABLE seq %u too soon to repeat\n", seq); + if (then != 1 && ((uint32_t)(switch_time_now() - then)) < RENACK_TIME) { + jb_debug(jb, 3, "NACKABLE seq %u too soon to repeat\n", seq); continue; } @@ -1251,8 +1251,11 @@ SWITCH_DECLARE(switch_status_t) switch_jb_put_packet(switch_jb_t *jb, switch_rtp add_node(jb, packet, len); - if (switch_test_flag(jb, SJB_QUEUE_ONLY) && jb->complete_frames > jb->max_frame_len) { - drop_oldest_frame(jb); + if (switch_test_flag(jb, SJB_QUEUE_ONLY) && jb->max_packet_len + && jb->allocated_nodes > jb->max_frame_len * 2 - 1) { + while ((jb->max_frame_len * 2 - jb->visible_nodes) < jb->max_packet_len) { + drop_oldest_frame(jb); + } } switch_mutex_unlock(jb->mutex); diff --git a/src/switch_loadable_module.c b/src/switch_loadable_module.c index b3ec9d4ebb..38de325d2c 100644 --- a/src/switch_loadable_module.c +++ b/src/switch_loadable_module.c @@ -1628,7 +1628,7 @@ SWITCH_DECLARE(switch_status_t) switch_loadable_module_exists(const char *mod) return status; } -SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(char *dir, char *fname, switch_bool_t force, const char **err) +SWITCH_DECLARE(switch_status_t) switch_loadable_module_unload_module(const char *dir, const char *fname, switch_bool_t force, const char **err) { switch_loadable_module_t *module = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; diff --git a/src/switch_log.c b/src/switch_log.c index 09c2b49df2..e33b0421f3 100644 --- a/src/switch_log.c +++ b/src/switch_log.c @@ -108,15 +108,25 @@ SWITCH_DECLARE(switch_log_node_t *) switch_log_node_dup(const switch_log_node_t switch_log_node_t *newnode = switch_log_node_alloc(); *newnode = *node; + newnode->content = NULL; - if (!zstr(node->data)) { + if (node->data) { newnode->data = strdup(node->data); - switch_assert(node->data); + switch_assert(newnode->data); + + // content is a pointer inside data; need to calculate the new pointer + if (node->content && node->content >= node->data) { + newnode->content = newnode->data + (node->content - node->data); + } } - if (!zstr(node->userdata)) { + if (node->userdata) { newnode->userdata = strdup(node->userdata); - switch_assert(node->userdata); + switch_assert(newnode->userdata); + } + + if (node->tags) { + switch_event_dup(&newnode->tags, node->tags); } return newnode; @@ -135,6 +145,9 @@ SWITCH_DECLARE(void) switch_log_node_free(switch_log_node_t **pnode) if (node) { switch_safe_free(node->userdata); switch_safe_free(node->data); + if (node->tags) { + switch_event_destroy(&node->tags); + } #ifdef SWITCH_LOG_RECYCLE if (switch_queue_trypush(LOG_RECYCLE_QUEUE, node) != SWITCH_STATUS_SUCCESS) { free(node); @@ -484,9 +497,13 @@ SWITCH_DECLARE(void) switch_log_vprintf(switch_text_channel_t channel, const cha node->content = content; node->timestamp = now; node->channel = channel; + node->tags = NULL; if (channel == SWITCH_CHANNEL_ID_SESSION) { switch_core_session_t *session = (switch_core_session_t *) userdata; node->userdata = userdata ? strdup(switch_core_session_get_uuid(session)) : NULL; + if (session) { + switch_channel_get_log_tags(switch_core_session_get_channel(session), &node->tags); + } } else { node->userdata = !zstr(userdata) ? strdup(userdata) : NULL; } diff --git a/src/switch_resample.c b/src/switch_resample.c index c9e1dc9759..2c9529b8e2 100644 --- a/src/switch_resample.c +++ b/src/switch_resample.c @@ -279,14 +279,33 @@ SWITCH_DECLARE(void) switch_mux_channels(int16_t *data, switch_size_t samples, u switch_assert(channels < 11); if (orig_channels > channels) { - for (i = 0; i < samples; i++) { - int32_t z = 0; - for (j = 0; j < orig_channels; j++) { - z += data[i * orig_channels + j]; + if (channels == 1) { + for (i = 0; i < samples; i++) { + int32_t z = 0; + for (j = 0; j < orig_channels; j++) { + z += (int16_t) data[i * orig_channels + j]; + } switch_normalize_to_16bit(z); data[i] = (int16_t) z; } - } + } else if (channels == 2) { + int mark_buf = 0; + for (i = 0; i < samples; i++) { + int32_t z_left = 0, z_right = 0; + for (j = 0; j < orig_channels; j++) { + if (j % 2) { + z_left += (int16_t) data[i * orig_channels + j]; + } else { + z_right += (int16_t) data[i * orig_channels + j]; + } + } + /* mark_buf will always be smaller than the size of data in bytes because orig_channels > channels */ + switch_normalize_to_16bit(z_left); + data[mark_buf++] = (int16_t) z_left; + switch_normalize_to_16bit(z_right); + data[mark_buf++] = (int16_t) z_right; + } + } } else if (orig_channels < channels) { /* interesting problem... take a give buffer and double up every sample in the buffer without using any other buffer..... diff --git a/src/switch_rtp.c b/src/switch_rtp.c index 824e01b7ee..c63c94e8eb 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -445,6 +445,7 @@ struct switch_rtp { uint32_t cng_count; switch_rtp_bug_flag_t rtp_bugs; switch_rtp_stats_t stats; + switch_rtcp_video_stats_t rtcp_vstats; uint32_t clean_stream; uint32_t bad_stream; uint32_t recovering_stream; @@ -478,6 +479,7 @@ struct switch_rtp { uint8_t clean; uint32_t last_max_vb_frames; int skip_timer; + uint32_t prev_nacks_inflight; #ifdef ENABLE_ZRTP zrtp_session_t *zrtp_session; zrtp_profile_t *zrtp_profile; @@ -808,6 +810,11 @@ static switch_status_t ice_out(switch_rtp_t *rtp_session, switch_rtp_ice_t *ice) switch_socket_t *sock_output = rtp_session->sock_output; switch_time_t now = switch_micro_time_now(); + if (ice->type & ICE_LITE) { + // no connectivity checks for ICE-Lite + return SWITCH_STATUS_BREAK; + } + if (ice->next_run && ice->next_run > now) { return SWITCH_STATUS_BREAK; } @@ -1795,26 +1802,37 @@ static void rtcp_generate_sender_info(switch_rtp_t *rtp_session, struct switch_r ); } -//#define DEBUG_RTCP -static void rtcp_generate_report_block(switch_rtp_t *rtp_session, struct switch_rtcp_report_block *rtcp_report_block){ -#ifdef DEBUG_RTCP - switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); -#endif - switch_rtcp_numbers_t * stats=&rtp_session->stats.rtcp; +static inline uint32_t calc_local_lsr_now() +{ switch_time_t now; - uint32_t expected_pkt, dlsr; - int32_t pkt_lost; uint32_t ntp_sec, ntp_usec, lsr_now, sec; now = switch_micro_time_now(); sec = (uint32_t)(now/1000000); /* convert to seconds */ ntp_sec = sec+NTP_TIME_OFFSET; /* convert to NTP seconds */ - ntp_usec = (uint32_t)(now - (sec*1000000)); /* remove seconds to keep only the microseconds */ + ntp_usec = (uint32_t)(now - ((switch_time_t) sec*1000000)); /* remove seconds to keep only the microseconds */ + + lsr_now = (uint32_t)(ntp_usec*0.065536) | (ntp_sec&0x0000ffff)<<16; /* 0.065536 is used for convertion from useconds to fraction of 65536 (x65536/1000000) */ + + return lsr_now; +} + +//#define DEBUG_RTCP +/* extra param is for duplicates (received NACKed packets) */ +static void rtcp_generate_report_block(switch_rtp_t *rtp_session, struct switch_rtcp_report_block *rtcp_report_block, + int16_t extra_expected) +{ +#ifdef DEBUG_RTCP + switch_core_session_t *session = switch_core_memory_pool_get_data(rtp_session->pool, "__session"); +#endif + switch_rtcp_numbers_t * stats=&rtp_session->stats.rtcp; + uint32_t expected_pkt, dlsr = 0; + int32_t pkt_lost; /* Packet loss */ if (stats->rtcp_rtp_count == 0) { expected_pkt = stats->high_ext_seq_recv - stats->base_seq + 1; } else { - expected_pkt = stats->high_ext_seq_recv - stats->last_rpt_ext_seq; + expected_pkt = stats->high_ext_seq_recv - stats->last_rpt_ext_seq + extra_expected; } pkt_lost = expected_pkt - stats->period_pkt_count; @@ -1845,12 +1863,12 @@ static void rtcp_generate_report_block(switch_rtp_t *rtp_session, struct switch_ rtcp_report_block->jitter = htonl((uint32_t)stats->inter_jitter); /* Delay since Last Sender Report (DLSR) : 32bits, 1/65536 seconds */ - lsr_now = (uint32_t)(ntp_usec*0.065536) | (ntp_sec&0x0000ffff)<<16; /* 0.065536 is used for convertion from useconds to fraction of 65536 (x65536/1000000) */ - if (stats->last_recv_lsr_local) { - dlsr = lsr_now - stats->last_recv_lsr_local; - } else { - dlsr = 0; + uint32_t lsr_now = calc_local_lsr_now(); + /* check lsr_now: what we just read from clock may be in the past (race cond), don't send huge dlsr due to uint wrap around */ + if (lsr_now > stats->last_recv_lsr_local) { + dlsr = lsr_now - stats->last_recv_lsr_local; + } } rtcp_report_block->lsr = stats->last_recv_lsr_peer; rtcp_report_block->dlsr = htonl(dlsr); @@ -2020,9 +2038,9 @@ static int using_ice(switch_rtp_t *rtp_session) static int check_rtcp_and_ice(switch_rtp_t *rtp_session) { int ret = 0; - int rtcp_ok = 0, rtcp_fb = 0, send_rr = 0; + int rtcp_ok = 0, rtcp_cyclic = 0, rtcp_fb = 0, force_send_rr = 0; switch_time_t now = switch_micro_time_now(); - int rate = 0, nack_ttl = 0; + int rate = 0, nack_ttl = 0, nack_dup = 0; uint32_t cur_nack[MAX_NACK] = { 0 }; if (!rtp_session->flags[SWITCH_RTP_FLAG_UDPTL] && @@ -2056,6 +2074,10 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) cur_nack[nack_ttl++] = nack; } + if (nack_ttl) { + rtcp_ok = 1; + rtcp_fb = 1; + } } @@ -2063,7 +2085,7 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) if (rtp_session->rtcp_sent_packets < 4) { rate = 4000; } else { - if (rtp_session->pli_count || rtp_session->fir_count || nack_ttl || rtp_session->tmmbr || rtp_session->tmmbn) { + if (rtp_session->pli_count || rtp_session->fir_count || rtp_session->tmmbr || rtp_session->tmmbn) { //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "MARK BW/FIR ETC %d %d\n", rtp_session->pli_count, rtp_session->fir_count); rtcp_ok = 1; rtcp_fb = 1; @@ -2073,13 +2095,14 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) if (rtp_session->send_rr) { rtp_session->send_rr = 0; rtcp_ok = 1; - send_rr = 1; + force_send_rr = 1; } //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "TIME CHECK %d > %d\n", (int)((now - rtp_session->rtcp_last_sent) / 1000), rate); if (!rtcp_ok && (!rtp_session->rtcp_last_sent || (int)((now - rtp_session->rtcp_last_sent) / 1000) > rate)) { //switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "TIME UP\n"); + rtcp_cyclic = 1; rtcp_ok = 1; } @@ -2101,30 +2124,42 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) switch_rtcp_numbers_t * stats = &rtp_session->stats.rtcp; struct switch_rtcp_receiver_report *rr; struct switch_rtcp_sender_report *sr; - struct switch_rtcp_report_block *rtcp_report_block; + struct switch_rtcp_report_block *rtcp_report_block = NULL; switch_size_t rtcp_bytes = sizeof(struct switch_rtcp_hdr_s)+sizeof(uint32_t); /* add size of the packet header and the ssrc */ switch_rtcp_hdr_t *sdes; uint8_t *p; switch_size_t sdes_bytes = sizeof(struct switch_rtcp_hdr_s); uint32_t *ssrc; switch_rtcp_sdes_unit_t *unit; + switch_bool_t is_only_receiver = FALSE; if (!rtcp_fb) { rtp_session->rtcp_last_sent = now; rtp_session->rtcp_sent_packets++; } + if (rtp_session->flags[SWITCH_RTP_FLAG_VIDEO] && + rtp_session->vb && rtcp_cyclic) { + nack_dup = rtp_session->prev_nacks_inflight; + rtp_session->prev_nacks_inflight = 0; + } + rtp_session->rtcp_send_msg.header.version = 2; rtp_session->rtcp_send_msg.header.p = 0; - rtp_session->rtcp_send_msg.header.count = 1; - - if (!rtp_session->stats.rtcp.sent_pkt_count || send_rr) { + if ((switch_core_session_media_flow(rtp_session->session, SWITCH_MEDIA_TYPE_AUDIO) == SWITCH_MEDIA_FLOW_RECVONLY) || + switch_core_session_media_flow(rtp_session->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) { + is_only_receiver = TRUE; + } + if (!rtp_session->stats.rtcp.sent_pkt_count || is_only_receiver || force_send_rr) { rtp_session->rtcp_send_msg.header.type = _RTCP_PT_RR; /* Receiver report */ rr=(struct switch_rtcp_receiver_report*) rtp_session->rtcp_send_msg.body; rr->ssrc = htonl(rtp_session->ssrc); rtcp_report_block = &rr->report_block; rtcp_bytes += sizeof(struct switch_rtcp_report_block); + rtcp_generate_report_block(rtp_session, rtcp_report_block, nack_dup); + rtp_session->rtcp_send_msg.header.count = 1; /* reception report block count */ + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP RR"); } else { struct switch_rtcp_sender_info *rtcp_sender_info; rtp_session->rtcp_send_msg.header.type = _RTCP_PT_SR; /* Sender report */ @@ -2132,10 +2167,18 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) sr->ssrc = htonl(rtp_session->ssrc); rtcp_sender_info = &sr->sender_info; rtcp_generate_sender_info(rtp_session, rtcp_sender_info); - rtcp_report_block = &sr->report_block; - rtcp_bytes += sizeof(struct switch_rtcp_sender_info) + sizeof(struct switch_rtcp_report_block); + rtcp_bytes += sizeof(struct switch_rtcp_sender_info); + if (!rtcp_cyclic && rtcp_fb) { + /* rtcp-fb only, don't send receive report block */ + rtp_session->rtcp_send_msg.header.count = 0; + } else { + rtcp_report_block = &sr->report_block; + rtcp_bytes += sizeof(struct switch_rtcp_report_block); + rtcp_generate_report_block(rtp_session, rtcp_report_block, nack_dup); + rtp_session->rtcp_send_msg.header.count = 1; /* reception report block count */ + } + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP SR"); } - rtcp_generate_report_block(rtp_session, rtcp_report_block); rtp_session->rtcp_send_msg.header.length = htons((uint16_t)(rtcp_bytes / 4) - 1); @@ -2153,9 +2196,9 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) ext_hdr->send_ssrc = htonl(rtp_session->ssrc); ext_hdr->recv_ssrc = htonl(rtp_session->remote_ssrc); - - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP PLI %u %u\n", - rtp_session->ssrc, rtp_session->remote_ssrc); + rtp_session->rtcp_vstats.video_in.pli_count++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP PLI %u %u [%u]\n", + rtp_session->ssrc, rtp_session->remote_ssrc, rtp_session->rtcp_vstats.video_in.pli_count); ext_hdr->length = htons((uint8_t)(sizeof(switch_rtcp_ext_hdr_t) / 4) - 1); rtcp_bytes += sizeof(switch_rtcp_ext_hdr_t); @@ -2165,6 +2208,7 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) if (rtp_session->flags[SWITCH_RTP_FLAG_NACK] && nack_ttl > 0) { int n = 0; + rtp_session->rtcp_vstats.video_in.nack_count++; for (n = 0; n < nack_ttl; n++) { switch_rtcp_ext_hdr_t *ext_hdr; uint32_t *nack; @@ -2182,13 +2226,13 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) nack = (uint32_t *) p; *nack = cur_nack[n]; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP NACK %u\n", - ntohs(*nack & 0xFFFF)); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP NACK %u [%d]\n", + ntohs(*nack & 0xFFFF), rtp_session->rtcp_vstats.video_in.nack_count); rtcp_bytes += sizeof(switch_rtcp_ext_hdr_t) + sizeof(cur_nack[n]); cur_nack[n] = 0; } - + rtp_session->prev_nacks_inflight = n; nack_ttl = 0; } @@ -2218,13 +2262,14 @@ static int check_rtcp_and_ice(switch_rtp_t *rtp_session) ext_hdr->pt = _RTCP_PT_PSFB; ext_hdr->send_ssrc = htonl(rtp_session->ssrc); - ext_hdr->recv_ssrc = 0; + ext_hdr->recv_ssrc = htonl(rtp_session->remote_ssrc); fir->ssrc = htonl(rtp_session->remote_ssrc); fir->seq = rtp_session->fir_seq; fir->r1 = fir->r2 = fir->r3 = 0; - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP FIR SEQ %d\n", rtp_session->fir_seq); + rtp_session->rtcp_vstats.video_in.fir_count++; + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG1, "Sending RTCP FIR SEQ %d [%u]\n", rtp_session->fir_seq, rtp_session->rtcp_vstats.video_in.fir_count); rtp_session->fir_seq++; @@ -3196,7 +3241,7 @@ static int dtls_state_handshake(switch_rtp_t *rtp_session, switch_dtls_t *dtls) case SSL_ERROR_NONE: break; default: - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s Handshake failure %d\n", rtp_type(rtp_session), ret); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_ERROR, "%s Handshake failure %d. This may happen when you use legacy DTLS v1.0 (legacyDTLS channel var is set) but endpoint requires DTLS v1.2.\n", rtp_type(rtp_session), ret); dtls_set_state(dtls, DS_FAIL); return -1; } @@ -3629,7 +3674,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_del_dtls(switch_rtp_t *rtp_session, d return status; } -SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type) +SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, dtls_fingerprint_t *local_fp, dtls_fingerprint_t *remote_fp, dtls_type_t type, uint8_t want_DTLSv1_2) { switch_dtls_t *dtls; const char *var; @@ -3690,7 +3735,11 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d #if OPENSSL_VERSION_NUMBER >= 0x10100000 dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? DTLS_server_method() : DTLS_client_method()); #else - dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? DTLSv1_server_method() : DTLSv1_client_method()); + #ifdef HAVE_OPENSSL_DTLSv1_2_method + dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? (want_DTLSv1_2 ? DTLSv1_2_server_method() : DTLSv1_server_method()) : (want_DTLSv1_2 ? DTLSv1_2_client_method() : DTLSv1_client_method())); + #else + dtls->ssl_ctx = SSL_CTX_new((type & DTLS_TYPE_SERVER) ? DTLSv1_server_method() : DTLSv1_client_method()); + #endif // HAVE_OPENSSL_DTLSv1_2_method #endif switch_assert(dtls->ssl_ctx); @@ -5355,7 +5404,7 @@ static void do_2833(switch_rtp_t *rtp_session) return; } - if (rtp_session->write_timer.samplecount >= rtp_session->max_next_write_samplecount) { + if (rtp_session->timer.samplecount >= rtp_session->max_next_write_samplecount) { rtp_session->queue_delay = 0; } @@ -6104,6 +6153,10 @@ static switch_status_t read_rtp_packet(switch_rtp_t *rtp_session, switch_size_t stat = 0; sbytes = 0; *bytes = 0; + if (rtp_session->stats.rtcp.pkt_count) { + rtp_session->stats.rtcp.period_pkt_count--; + rtp_session->stats.rtcp.pkt_count--; + } switch_mutex_unlock(rtp_session->ice_mutex); goto more; } @@ -6454,7 +6507,6 @@ static void handle_nack(switch_rtp_t *rtp_session, uint32_t nack) static switch_status_t process_rtcp_report(switch_rtp_t *rtp_session, rtcp_msg_t *msg, switch_size_t bytes) { switch_status_t status = SWITCH_STATUS_FALSE; - int i; switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG3, "RTCP packet bytes %" SWITCH_SIZE_T_FMT " type %d pad %d\n", @@ -6514,9 +6566,11 @@ static switch_status_t process_rtcp_report(switch_rtp_t *rtp_session, rtcp_msg_t struct switch_rtcp_report_block *report; if (msg->header.type == _RTCP_PT_SR || msg->header.type == _RTCP_PT_RR) { - switch_time_t now; - switch_time_exp_t now_hr; - uint32_t sec, ntp_sec, ntp_usec, lsr_now; + int i; +#ifdef DEBUG_RTCP + switch_time_t now = switch_micro_time_now(); +#endif + uint32_t lsr_now; uint32_t lsr; uint32_t packet_ssrc; double rtt_now = 0; @@ -6527,11 +6581,7 @@ static switch_status_t process_rtcp_report(switch_rtp_t *rtp_session, rtcp_msg_t // rtp_session->send_rr = 1; //} - now = switch_micro_time_now(); /* number of microseconds since 00:00:00 january 1, 1970 UTC */ - sec = (uint32_t)(now/1000000); /* converted to second (NTP most significant bits) */ - ntp_sec = sec+NTP_TIME_OFFSET; /* 32bits most significant */ - ntp_usec = (uint32_t)(now - (((switch_time_t) sec) * 1000000)); /* micro seconds */ - lsr_now = (uint32_t)(ntp_usec*0.065536) | (ntp_sec&0x0000ffff)<<16; // 0.065536 is used for convertion from useconds + lsr_now = calc_local_lsr_now(); if (msg->header.type == _RTCP_PT_SR) { /* Sender report */ struct switch_rtcp_sender_report* sr = (struct switch_rtcp_sender_report*)msg->body; @@ -6611,30 +6661,31 @@ static switch_status_t process_rtcp_report(switch_rtp_t *rtp_session, rtcp_msg_t if (rtp_session->rtcp_frame.reports[i].lsr && !rtp_session->flags[SWITCH_RTP_FLAG_RTCP_PASSTHRU]) { - switch_time_exp_gmt(&now_hr,now); - /* Calculating RTT = A - DLSR - LSR */ rtt_now = ((double)(((int64_t)lsr_now) - rtp_session->rtcp_frame.reports[i].dlsr - rtp_session->rtcp_frame.reports[i].lsr))/65536; /* Only account RTT if it didn't overflow. */ if (lsr_now > rtp_session->rtcp_frame.reports[i].dlsr + rtp_session->rtcp_frame.reports[i].lsr) { - - rtt_valid = 1; - +#ifdef DEBUG_RTCP + switch_time_exp_t now_hr; + switch_time_exp_gmt(&now_hr,now); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_DEBUG3, "Receiving an RTCP packet\n[%04d-%02d-%02d %02d:%02d:%02d.%d] SSRC[0x%x]\n" "RTT[%f] = A[%u] - DLSR[%u] - LSR[%u]\n", 1900 + now_hr.tm_year, now_hr.tm_mday, now_hr.tm_mon, now_hr.tm_hour, now_hr.tm_min, now_hr.tm_sec, now_hr.tm_usec, rtp_session->rtcp_frame.reports[i].ssrc, rtt_now, lsr_now, rtp_session->rtcp_frame.reports[i].dlsr, rtp_session->rtcp_frame.reports[i].lsr); +#endif + rtt_valid = 1; if (!rtp_session->rtcp_frame.reports[i].rtt_avg) { rtp_session->rtcp_frame.reports[i].rtt_avg = rtt_now; } else { rtp_session->rtcp_frame.reports[i].rtt_avg = (double)((rtp_session->rtcp_frame.reports[i].rtt_avg * .7) + (rtt_now * .3 )); } } else { - #ifdef DEBUG_RTCP + switch_time_exp_t now_hr; + switch_time_exp_gmt(&now_hr,now); switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(rtp_session->session), SWITCH_LOG_WARNING, "Receiving RTCP packet\n[%04d-%02d-%02d %02d:%02d:%02d.%d] SSRC[0x%x]\n" "Ignoring erroneous RTT[%f] = A[%u] - DLSR[%u] - LSR[%u]\n", @@ -6799,6 +6850,9 @@ static switch_status_t process_rtcp_packet(switch_rtp_t *rtp_session, switch_siz switch_status_t status = SWITCH_STATUS_FALSE; rtcp_msg_t *msg = rtp_session->rtcp_recv_msg_p; + if (remain < sizeof(switch_rtcp_ext_hdr_t) || remain > sizeof(rtcp_msg_t)) { + return status; + } if (msg->header.version != 2) { if (msg->header.version == 0) { if (rtp_session->ice.ice_user) { @@ -8208,6 +8262,7 @@ static int rtp_common_write(switch_rtp_t *rtp_session, rtp_session->ts_norm.last_frame = ntohl(send_msg->header.ts); send_msg->header.ts = htonl(rtp_session->ts_norm.ts); + this_ts = rtp_session->ts_norm.ts; } send_msg->header.ssrc = htonl(rtp_session->ssrc); diff --git a/src/switch_stun.c b/src/switch_stun.c index f759a2607c..94ee890f78 100644 --- a/src/switch_stun.c +++ b/src/switch_stun.c @@ -331,8 +331,6 @@ SWITCH_DECLARE(switch_stun_packet_t *) switch_stun_packet_parse(uint8_t *buf, ui bytes_left -= alen; /* attribute value consumed, substract padded length */ - if (alen == 0) break; - xlen += 4 + alen; attr = (switch_stun_packet_attribute_t *) (attr->value + alen); diff --git a/src/switch_utils.c b/src/switch_utils.c index 52ec8f6327..2ac0a0e415 100644 --- a/src/switch_utils.c +++ b/src/switch_utils.c @@ -54,6 +54,7 @@ struct switch_network_node { switch_bool_t ok; char *token; char *str; + switch_network_port_range_t port_range; struct switch_network_node *next; }; typedef struct switch_network_node switch_network_node_t; @@ -467,7 +468,8 @@ SWITCH_DECLARE(switch_bool_t) switch_testv6_subnet(ip_t _ip, ip_t _net, ip_t _ma else return SWITCH_TRUE; } } -SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token) + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_port_token(switch_network_list_t *list, ip_t ip, int port, const char **token) { switch_network_node_t *node; switch_bool_t ok = list->default_type; @@ -494,7 +496,29 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_netw return ok; } -SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token) +SWITCH_DECLARE(switch_bool_t) is_port_in_node(int port, switch_network_node_t *node) +{ + if(port == 0) + return SWITCH_TRUE; + if(node->port_range.port != 0 && node->port_range.port != port) + return SWITCH_FALSE; + if(node->port_range.ports[0] != 0) { + int i; + for(i=0; i < MAX_NETWORK_PORTS && node->port_range.ports[i] != 0; i++) { + if(port == node->port_range.ports[i]) + return SWITCH_TRUE; + } + return SWITCH_FALSE; + } + if(node->port_range.min_port != 0 || node->port_range.max_port != 0) { + if(port >= node->port_range.min_port && port <= node->port_range.max_port) + return SWITCH_TRUE; + return SWITCH_FALSE; + } + return SWITCH_TRUE; +} + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_port_token(switch_network_list_t *list, uint32_t ip, int port, const char **token) { switch_network_node_t *node; switch_bool_t ok = list->default_type; @@ -502,7 +526,7 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo for (node = list->node_head; node; node = node->next) { if (node->family == AF_INET6) continue; /* want AF_INET */ - if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4)) { + if (node->bits >= bits && switch_test_subnet(ip, node->ip.v4, node->mask.v4) && is_port_in_node(port, node)) { if (node->ok) { ok = SWITCH_TRUE; } else { @@ -520,6 +544,16 @@ SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_netwo return ok; } +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip6_token(switch_network_list_t *list, ip_t ip, const char **token) +{ + return switch_network_list_validate_ip6_port_token(list, ip, 0, token); +} + +SWITCH_DECLARE(switch_bool_t) switch_network_list_validate_ip_token(switch_network_list_t *list, uint32_t ip, const char **token) +{ + return switch_network_list_validate_ip_port_token(list, ip, 0, token); +} + SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str) { /* ipv4 mapped ipv6 address */ @@ -531,22 +565,52 @@ SWITCH_DECLARE(char *) switch_network_ipv4_mapped_ipv6_addr(const char* ip_str) return strdup(ip_str + 7); } +SWITCH_DECLARE(char*) switch_network_port_range_to_string(switch_network_port_range_p port) +{ + if (!port) { + return NULL; + } + + if (port->port != 0) { + return switch_mprintf("port: %i ", port->port); + } + + if (port->ports[0] != 0) { + int i, written = 0; + char buf[MAX_NETWORK_PORTS * 6]; + for (i = 0; i < MAX_NETWORK_PORTS && port->ports[i] != 0; i++) { + written += snprintf(buf + written, sizeof(buf) - written, (i != 0 ? ", %u" : "%u"), port->ports[i]); + } + return switch_mprintf("ports: [%s] ", buf); + } + + if (port->min_port != 0 || port->max_port != 0) { + return switch_mprintf("port range: [%i-%i] ", port->min_port, port->max_port); + } + + return NULL; +} + SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, - const char *token) + const char *token, switch_network_port_range_p port) { ip_t ip, mask; uint32_t bits; switch_network_node_t *node; char *ipv4 = NULL; + char *ports = NULL; if ((ipv4 = switch_network_ipv4_mapped_ipv6_addr(cidr_str))) { cidr_str = ipv4; } + ports = switch_network_port_range_to_string(port); + if (switch_parse_cidr(cidr_str, &ip, &mask, &bits)) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", switch_str_nil(token), list->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Error Adding %s %s(%s) [%s] to list %s\n", + cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name); switch_safe_free(ipv4); + switch_safe_free(ports); return SWITCH_STATUS_GENERR; } @@ -557,6 +621,10 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switc node->ok = ok; node->bits = bits; node->str = switch_core_strdup(list->pool, cidr_str); + if(port) { + memcpy(&node->port_range, port, sizeof(switch_network_port_range_t)); + } + if (strchr(cidr_str,':')) { node->family = AF_INET6; @@ -571,14 +639,15 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_perform_add_cidr_token(switc node->next = list->node_head; list->node_head = node; - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s (%s) [%s] to list %s\n", - cidr_str, ok ? "allow" : "deny", switch_str_nil(token), list->name); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Adding %s %s(%s) [%s] to list %s\n", + cidr_str, ports ? ports : "", ok ? "allow" : "deny", switch_str_nil(token), list->name); switch_safe_free(ipv4); + switch_safe_free(ports); return SWITCH_STATUS_SUCCESS; } -SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token) +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_port_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token, switch_network_port_range_p port) { char *cidr_str_dup = NULL; switch_status_t status = SWITCH_STATUS_SUCCESS; @@ -592,20 +661,25 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_networ if ((argc = switch_separate_string(cidr_str_dup, ',', argv, (sizeof(argv) / sizeof(argv[0]))))) { for (i = 0; i < argc; i++) { switch_status_t this_status; - if ((this_status = switch_network_list_perform_add_cidr_token(list, argv[i], ok, token)) != SWITCH_STATUS_SUCCESS) { + if ((this_status = switch_network_list_perform_add_cidr_token(list, argv[i], ok, token, port)) != SWITCH_STATUS_SUCCESS) { status = this_status; } } } } else { - status = switch_network_list_perform_add_cidr_token(list, cidr_str, ok, token); + status = switch_network_list_perform_add_cidr_token(list, cidr_str, ok, token, port); } switch_safe_free(cidr_str_dup); return status; } -SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok) +SWITCH_DECLARE(switch_status_t) switch_network_list_add_cidr_token(switch_network_list_t *list, const char *cidr_str, switch_bool_t ok, const char *token) +{ + return switch_network_list_add_cidr_port_token(list, cidr_str, ok, token, NULL); +} + +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_port_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok, switch_network_port_range_p port) { ip_t ip, mask; switch_network_node_t *node; @@ -618,6 +692,9 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network node->ip.v4 = ntohl(ip.v4); node->mask.v4 = ntohl(mask.v4); node->ok = ok; + if(port) { + memcpy(&node->port_range, port, sizeof(switch_network_port_range_t)); + } /* http://graphics.stanford.edu/~seander/bithacks.html */ mask.v4 = mask.v4 - ((mask.v4 >> 1) & 0x55555555); @@ -632,6 +709,11 @@ SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network return SWITCH_STATUS_SUCCESS; } +SWITCH_DECLARE(switch_status_t) switch_network_list_add_host_mask(switch_network_list_t *list, const char *host, const char *mask_str, switch_bool_t ok) +{ + return switch_network_list_add_host_port_mask(list, host, mask_str, ok, NULL); +} + SWITCH_DECLARE(int) switch_parse_cidr(const char *string, ip_t *ip, ip_t *mask, uint32_t *bitp) { diff --git a/src/switch_xml.c b/src/switch_xml.c index 26e4481b53..58ec1fb411 100644 --- a/src/switch_xml.c +++ b/src/switch_xml.c @@ -3213,7 +3213,7 @@ SWITCH_DECLARE(int) switch_xml_std_datetime_check(switch_xml_t xcond, int *offse return time_match; } -SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) { +SWITCH_DECLARE(switch_status_t) switch_xml_locate_language_ex(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) { switch_status_t status = SWITCH_STATUS_FALSE; if (switch_xml_locate("languages", NULL, NULL, NULL, root, node, params, SWITCH_TRUE) != SWITCH_STATUS_SUCCESS) { @@ -3270,6 +3270,25 @@ done: return status; } +SWITCH_DECLARE(switch_status_t) switch_xml_locate_language(switch_xml_t *root, switch_xml_t *node, switch_event_t *params, switch_xml_t *language, switch_xml_t *phrases, switch_xml_t *macros, const char *str_language) { + switch_status_t status; + + if ((status = switch_xml_locate_language_ex(root, node, params, language, phrases, macros, str_language)) != SWITCH_STATUS_SUCCESS) { + char *str_language_dup = strdup(str_language); + char *secondary; + if ((secondary = strchr(str_language_dup, '-'))) { + *secondary++ = '\0'; + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, + "language %s not found. trying %s by removing %s\n", str_language, str_language_dup, secondary); + switch_event_add_header_string(params, SWITCH_STACK_BOTTOM, "lang", str_language_dup); + status = switch_xml_locate_language_ex(root, node, params, language, phrases, macros, str_language_dup); + } + switch_safe_free(str_language_dup); + } + + return status; +} + #ifdef WIN32 /* * globbing functions for windows, part of libc on unix, this code was cut and paste from diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/.gitignore b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/.gitignore new file mode 100644 index 0000000000..65a2612121 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/.gitignore @@ -0,0 +1,2 @@ +ICSharpCode.SharpZipLib.dll +bin/ \ No newline at end of file diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.config b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.config new file mode 100644 index 0000000000..c837a2cee3 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.config @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.cs b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.cs new file mode 100644 index 0000000000..fcab4445c4 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/CustomAction.cs @@ -0,0 +1,70 @@ +using System; +using System.Collections.Generic; +using System.Text; +using Microsoft.Deployment.WindowsInstaller; +using ICSharpCode.SharpZipLib.BZip2; +using System.IO; +using System.Net; + +namespace Setup.CA.DownloadOpenH264 +{ + public class CustomActions + { + [CustomAction] + public static ActionResult DownloadOpenH264(Session session) + { + session.Log("Begin DownloadOpenH264"); + + string filename = session.CustomActionData["location"] + @"openh264.dll"; + + try + { + WebRequest request = HttpWebRequest.Create("http://ciscobinary.openh264.org/openh264-1.8.0-win64.dll.bz2"); + + using (WebResponse response = request.GetResponse()) + { + Stream responseStream = response.GetResponseStream(); + BZip2InputStream zisUncompressed = new BZip2InputStream(responseStream); + using (var output = File.Create(filename)) + { + var buffer = new byte[2048]; + int n; + while ((n = zisUncompressed.Read(buffer, 0, buffer.Length)) > 0) + { + output.Write(buffer, 0, n); + } + } + } + } + catch { + session.Log("Unable to download openh264 codec."); + } + + return ActionResult.Success; + } + + [CustomAction] + public static ActionResult RemoveOpenH264Binary(Session session) + { + session.Log("Begin RemoveOpenH264Binary"); + string filename = session.CustomActionData["location"] + @"openh264.dll"; + + try + { + // Check if file exists with its full path + if (File.Exists(filename)) + { + // If file found, delete it + File.Delete(filename); + session.Log("RemoveOpenH264Binary deleted openh264.dll"); + } + } + catch (IOException ioExp) + { + session.Log("RemoveOpenH264Binary can't delete openh264.dll"); + } + + return ActionResult.Success; + } + } +} diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/LICENSE.txt b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/LICENSE.txt new file mode 100644 index 0000000000..f7642317c9 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/LICENSE.txt @@ -0,0 +1,17 @@ +Copyright © 2000-2018 SharpZipLib Contributors + +Permission is hereby granted, free of charge, to any person obtaining a copy of this +software and associated documentation files (the "Software"), to deal in the Software +without restriction, including without limitation the rights to use, copy, modify, merge, +publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +to whom the Software is furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Properties/AssemblyInfo.cs b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Properties/AssemblyInfo.cs new file mode 100644 index 0000000000..751f52bb10 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("Setup.CA.DownloadOpenH264")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyProduct("Setup.CA.DownloadOpenH264")] +[assembly: AssemblyCopyright("Copyright © 2019")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("ebfdcfca-8095-4ecc-98be-b494bcb4e042")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Setup.CA.DownloadOpenH264.csproj b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Setup.CA.DownloadOpenH264.csproj new file mode 100644 index 0000000000..433a047be5 --- /dev/null +++ b/w32/Setup/CustomActions/Setup.CA.DownloadOpenH264/Setup.CA.DownloadOpenH264.csproj @@ -0,0 +1,58 @@ + + + + + Debug + x86 + 8.0.30703 + 2.0 + {EBFDCFCA-8095-4ECC-98BE-B494BCB4E042} + Library + Properties + Setup.CA.DownloadOpenH264 + Setup.CA.DownloadOpenH264 + v4.6.1 + 512 + + + true + full + false + bin\ + DEBUG;TRACE + prompt + 4 + + + pdbonly + true + bin\ + TRACE + prompt + 4 + + + + .\ICSharpCode.SharpZipLib.dll + + + + + + + + True + + + + + + + + + + + + + + \ No newline at end of file diff --git a/w32/Setup/Product.2017.wxs b/w32/Setup/Product.2017.wxs index 6b223612f6..7538971102 100644 --- a/w32/Setup/Product.2017.wxs +++ b/w32/Setup/Product.2017.wxs @@ -29,6 +29,7 @@ + @@ -42,15 +43,37 @@ + + + + + + + + + Downloading OpenH264 Video Codec provided by Cisco Systems, Inc. + + + + AND ((NOT (REMOVE="ALL")) OR (REINSTALL="ALL")) + + + + ( AND (Installed OR MaintenanceMode="Modify")) OR ((NOT UPGRADINGPRODUCTCODE) AND (REMOVE="ALL")) + + + + + @@ -121,6 +144,11 @@ + + + diff --git a/w32/Setup/Setup.2017.wixproj b/w32/Setup/Setup.2017.wixproj index cb65aa947c..db9b628d61 100644 --- a/w32/Setup/Setup.2017.wixproj +++ b/w32/Setup/Setup.2017.wixproj @@ -1,1064 +1,1083 @@ - - - - true - - - - - - - - {47213370-b933-487d-9f45-bca26d7e2b6f} - 2.0 - FreeSWITCH - Package - $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets - $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets - - - bin\x86\Debug\ - obj\X86\$(Configuration)\ - Debug;FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)Win32\$(Configuration); - - - - - bin\x86\release\ - obj\X86\$(Configuration)\ - FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)Win32\$(Configuration); - - - bin\x64\Debug\ - obj\X64\$(Configuration)\ - Debug;FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)$(Platform)\$(Configuration); - - - - - bin\x64\Release\ - obj\X64\$(Configuration)\ - FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)$(Platform)\$(Configuration); - - - - - - - - - - - - - - - $(WixExtDir)\WixUIExtension.dll - WixUIExtension - - - - - - - - fs_cli - {d2fb8043-d208-4aee-8f18-3b5857c871b9} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - 8khz - {7a8d8174-b355-4114-afc1-04777cb9de0a} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - 8khz music - {d1abe208-6442-4fb4-9aad-1677e41bc870} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_abstraction - {60c542ee-6882-4ea2-8c21-5ab6db1ba73f} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_avmd - {990baa76-89d3-4e38-8479-c7b28784efc8} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_blacklist - {50aac2ce-bfc9-4912-87cc-c6381850d735} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_callcenter - {47886a6c-cca6-4f9f-a7d4-f97d06fb2b1a} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cidlookup - {0a130a8b-3076-4619-badf-9e86f621aeec} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_commands - {30a5b29c-983e-4580-9fd0-d647ccdcc7eb} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_conference - {c24fb505-05d7-4319-8485-7540b44c8603} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_curl - {ef300386-a8df-4372-b6d8-fb9bffca9aed} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cv - {40c4e2a2-b49b-496c-96d6-c04b890f7f88} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_db - {f6a33240-8f29-48bd-98f0-826995911799} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_directory - {b889a18e-70a7-44b5-b2c9-47798d4f43b3} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_distributor - {5c2b4d88-3bea-4fe0-90df-fa9836099d5f} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_dptools - {b5881a85-fe70-4f64-8607-2caae52669c6} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_easyroute - {329fd5b0-ef28-4606-86d0-f6ea21cf8e36} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_enum - {71a967d5-0e99-4cef-a587-98836ee6f2ef} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_esf - {3850d93a-5f24-4922-bc1c-74d08c37c256} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_expr - {65a6273d-fcab-4c55-b09e-65100141a5d4} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_fifo - {75df7f29-2fbf-47f7-b5af-5b4952dc1abd} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_fsv - {e3246d17-e29b-4ab5-962a-c69b0c5837bb} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_hash - {2e250296-0c08-4342-9c8a-bcbdd0e7df65} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_httapi - {4748ff56-ca85-4809-97d6-a94c0fac1d77} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_http_cache - {87933c2d-0159-46f7-b326-e1b6e982c21e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_lcr - {1a3793d1-05d1-4b57-9b0f-5af3e79dc439} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_nibblebill - {3c977801-fe88-48f2-83d3-fa2ebff6688e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_redis - {886b5e9d-f2c2-4af2-98c8-ef98c4c770e6} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_rss - {b69247fa-ecd6-40ed-8e44-5ca6c3baf9a4} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_signalwire - {b19ae6fc-bfff-428d-b483-3bbeaeccc618} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_sms - {2469b306-b027-4ff2-8815-c9c1ea2cae79} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_snom - {2a3d00c6-588d-4e86-81ac-9ef5ede86e03} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_spandsp - {1e21afe0-6fdb-41d2-942d-863607c24b91} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_spy - {a61d7cb4-75a5-4a55-8ca1-be5af615d921} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_valet_parking - {432db165-1eb2-4781-a9c0-71e62610b20a} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_vmd - {14e4a972-9cfb-436d-b0a5-4943f3f80d47} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_voicemail - {d7f1e3f2-a3f4-474c-8555-15122571af52} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_flite - {66444aee-554c-11dd-a9f0-8c5d56d89593} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_pocketsphinx - {2286da73-9fc5-45bc-a508-85994c3317ab} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_unimrcp - {d07c378a-f5f7-438f-adf3-4ac4fb1883cd} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_amr - {8deb383c-4091-4f42-a56f-c9e46d552d79} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_bv - {d5c87b19-150d-4ef3-a671-96589bd2d14a} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_codec2 - {cb4e68a1-8d19-4b5e-87b9-97a895e1ba17} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_g723_1 - {fea1eef7-876f-48de-88bf-c0e3e606d758} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_g729 - {1d95cd95-0de2-48c3-ac23-d5c7d1c9c0f0} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_h26x - {2c3c2423-234b-4772-8899-d3b137e5ca35} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_ilbc - {d3ec0aff-76fc-4210-a825-9a17410660a3} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_iSAC - {7f1610f1-dd5a-4cf7-8610-30ab12c60add} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_opus - {64e99cca-3c6f-4aeb-9fa3-cfac711257bb} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_silk - {afa983d6-4569-4f88-ba94-555ed00fd9a8} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_siren - {0b6c905b-142e-4999-b39d-92ff7951e921} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_dialplan_asterisk - {e7bc026c-7cc5-45a3-bc7c-3b88eef01f24} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_dialplan_directory - {a27cca23-1541-4337-81a4-f0a6413078a0} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_dialplan_xml - {07113b25-d3af-4e04-ba77-4cd1171f022c} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_ldap - {ec3e5c7f-ee09-47e2-80fe-546363d14a98} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_dingaling - {ffaa4c52-3a53-4f99-90c1-d59d1f0427f3} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_gsmopen - {74b120ff-6935-4dfe-a142-cdb6bea99c90} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_loopback - {b3f424ec-3d8f-417c-b244-3919d5e1a577} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_PortAudio - {5fd31a25-5d83-4794-8bee-904dad84ce71} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_rtc - {3884add2-91d0-4cd6-86d3-d5fb2d4aab9e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_rtmp - {48414740-c693-4968-9846-ee058020c64f} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_skinny - {cc1dd008-9406-448d-a0ad-33c3186cfadb} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_sofia - {0df3abd0-ddc0-4265-b778-07c66780979b} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_verto - {5b2bace4-0f5a-4a21-930d-c0f4b1f58fa6} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_amqp - {7ac7ab4f-5ef3-40a0-ad2b-cf4d9720fac3} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cdr_csv - {44d7deaf-fda5-495e-8b9d-1439e4f4c21e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cdr_mongodb - {4dff29b4-2976-447d-a8b3-43476451517c} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cdr_pg_csv - {411f6d43-9f09-47d0-8b04-e1eb6b67c5bf} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_cdr_sqlite - {2ca661a7-01dd-4532-bf88-b6629dfb544a} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_event_multicast - {784113ef-44d9-4949-835d-7065d3c7ad08} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_event_socket - {05515420-16de-4e63-be73-85be85ba5142} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_odbc_cdr - {096c9a84-55b2-4f9b-97e5-0fdf116fd25f} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_local_stream - {2ca40887-1622-46a1-a7f9-17fd7e7e545b} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_native_file - {9254c4b0-6f60-42b6-bb3a-36d63fc001c7} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_png - {fbc7e2a4-b989-4289-ba7f-68f440e9ef8b} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_shout - {38fe0559-9910-43a8-9e45-3e5004c27692} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_sndfile - {afac0568-7548-42d5-9f6a-8d3400a1e4f6} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_tone_stream - {6ff941ac-82c5-429f-aa4c-ad2fb9e5da52} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_lua - {7b077e7f-1be7-4291-ab86-55e527b25cac} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_managed - {7b42bda1-72c0-4378-a9b6-5c530f8cd61e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_v8 - {9b9d2551-d6bd-4f20-8be5-de30e154a064} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_console - {1c453396-d912-4213-89fd-9b489162b7b5} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_logfile - {d0bcac02-d94b-46b8-9b49-cddcc2bd7909} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_de - {5bc072db-3826-48ea-af34-fe32aa01e83b} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_en - {988cacf7-3fcb-4992-be69-77872ae67dc8} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_es - {fa429e98-8b03-45e6-a096-a4bc5e821de4} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_es_ar - {ceee31e6-8a08-42c7-bebd-5ec12072c136} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_fa - {0e469f3a-ddd0-43ba-a94f-7d93c02219f3} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_fr - {06e3a538-ab32-44f2-b477-755ff9cb5d37} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_he - {a3d7c6cf-aeb1-4159-b741-160eb4b37345} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_hr - {da7addf1-da33-4194-83a5-b48db714d35b} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_hu - {af675478-995a-4115-90c4-b2b0d6470688} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_it - {6d1bec70-4dcd-4fe9-adbd-4a43a67e4d05} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_ja - {07ea6e5a-d181-4abb-becf-67a906867d04} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_nl - {a4b122cf-5196-476b-8c0e-d8bd59ac3c14} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_pl - {20b15650-f910-4211-8729-aab0f520c805} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_pt - {7c22bdff-cc09-400c-8a09-660733980028} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_ru - {0382e8fd-cfdc-41c0-8b03-792c7c84fc31} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_sv - {8cda2b34-fa44-49cc-9ec2-b8f35856cd15} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_th - {c955e1a9-c12c-4bad-ac32-8d53d9268af7} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_say_zh - {b6a9fb7a-1cc4-442b-812d-ec33e4e4a36e} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_xml_cdr - {08dad348-9e0a-4a2e-97f1-f1e7e24a7836} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_xml_curl - {ab91a099-7690-4ecf-8994-e458f4ea1ed4} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - mod_xml_rpc - {cbec7225-0c21-4da8-978e-1f158f8ad950} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - FreeSwitchConsole - {1af3a893-f7be-43dd-b697-8ab2397c0d67} - True - True - Binaries;Content;Satellites - INSTALLFOLDER - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + true + + + + + + + + {47213370-b933-487d-9f45-bca26d7e2b6f} + 2.0 + FreeSWITCH + Package + $(MSBuildExtensionsPath32)\Microsoft\WiX\v3.x\Wix.targets + $(MSBuildExtensionsPath)\Microsoft\WiX\v3.x\Wix.targets + + + bin\x86\Debug\ + obj\X86\$(Configuration)\ + Debug;FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)Win32\$(Configuration); + + + + + bin\x86\release\ + obj\X86\$(Configuration)\ + FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)Win32\$(Configuration); + + + bin\x64\Debug\ + obj\X64\$(Configuration)\ + Debug;FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)$(Platform)\$(Configuration); + + + + + bin\x64\Release\ + obj\X64\$(Configuration)\ + FreeSWITCHConfFilesDir=$(ProjectDir)..\..\conf\vanilla;FreeSWITCHBaseDir=$(SolutionDir)$(Platform)\$(Configuration); + + + + + + + + + + + + + + + $(WixExtDir)\WixUIExtension.dll + WixUIExtension + + + + + + + + fs_cli + {d2fb8043-d208-4aee-8f18-3b5857c871b9} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + 8khz + {7a8d8174-b355-4114-afc1-04777cb9de0a} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + 8khz music + {d1abe208-6442-4fb4-9aad-1677e41bc870} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_abstraction + {60c542ee-6882-4ea2-8c21-5ab6db1ba73f} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_avmd + {990baa76-89d3-4e38-8479-c7b28784efc8} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_av + {7aee504b-23b6-4b05-829e-7cd34855f146} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_blacklist + {50aac2ce-bfc9-4912-87cc-c6381850d735} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_callcenter + {47886a6c-cca6-4f9f-a7d4-f97d06fb2b1a} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cidlookup + {0a130a8b-3076-4619-badf-9e86f621aeec} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_commands + {30a5b29c-983e-4580-9fd0-d647ccdcc7eb} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_conference + {c24fb505-05d7-4319-8485-7540b44c8603} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_curl + {ef300386-a8df-4372-b6d8-fb9bffca9aed} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cv + {40c4e2a2-b49b-496c-96d6-c04b890f7f88} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_db + {f6a33240-8f29-48bd-98f0-826995911799} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_directory + {b889a18e-70a7-44b5-b2c9-47798d4f43b3} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_distributor + {5c2b4d88-3bea-4fe0-90df-fa9836099d5f} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_dptools + {b5881a85-fe70-4f64-8607-2caae52669c6} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_easyroute + {329fd5b0-ef28-4606-86d0-f6ea21cf8e36} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_enum + {71a967d5-0e99-4cef-a587-98836ee6f2ef} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_esf + {3850d93a-5f24-4922-bc1c-74d08c37c256} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_expr + {65a6273d-fcab-4c55-b09e-65100141a5d4} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_fifo + {75df7f29-2fbf-47f7-b5af-5b4952dc1abd} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_fsv + {e3246d17-e29b-4ab5-962a-c69b0c5837bb} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_hash + {2e250296-0c08-4342-9c8a-bcbdd0e7df65} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_httapi + {4748ff56-ca85-4809-97d6-a94c0fac1d77} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_http_cache + {87933c2d-0159-46f7-b326-e1b6e982c21e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_lcr + {1a3793d1-05d1-4b57-9b0f-5af3e79dc439} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_nibblebill + {3c977801-fe88-48f2-83d3-fa2ebff6688e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_redis + {886b5e9d-f2c2-4af2-98c8-ef98c4c770e6} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_rss + {b69247fa-ecd6-40ed-8e44-5ca6c3baf9a4} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_signalwire + {b19ae6fc-bfff-428d-b483-3bbeaeccc618} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_sms + {2469b306-b027-4ff2-8815-c9c1ea2cae79} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_snom + {2a3d00c6-588d-4e86-81ac-9ef5ede86e03} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_spandsp + {1e21afe0-6fdb-41d2-942d-863607c24b91} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_spy + {a61d7cb4-75a5-4a55-8ca1-be5af615d921} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_valet_parking + {432db165-1eb2-4781-a9c0-71e62610b20a} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_vmd + {14e4a972-9cfb-436d-b0a5-4943f3f80d47} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_voicemail + {d7f1e3f2-a3f4-474c-8555-15122571af52} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_flite + {66444aee-554c-11dd-a9f0-8c5d56d89593} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_pocketsphinx + {2286da73-9fc5-45bc-a508-85994c3317ab} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_unimrcp + {d07c378a-f5f7-438f-adf3-4ac4fb1883cd} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_amr + {8deb383c-4091-4f42-a56f-c9e46d552d79} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_bv + {d5c87b19-150d-4ef3-a671-96589bd2d14a} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_codec2 + {cb4e68a1-8d19-4b5e-87b9-97a895e1ba17} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_g723_1 + {fea1eef7-876f-48de-88bf-c0e3e606d758} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_g729 + {1d95cd95-0de2-48c3-ac23-d5c7d1c9c0f0} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_h26x + {2c3c2423-234b-4772-8899-d3b137e5ca35} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_ilbc + {d3ec0aff-76fc-4210-a825-9a17410660a3} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_iSAC + {7f1610f1-dd5a-4cf7-8610-30ab12c60add} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_opus + {64e99cca-3c6f-4aeb-9fa3-cfac711257bb} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_silk + {afa983d6-4569-4f88-ba94-555ed00fd9a8} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_siren + {0b6c905b-142e-4999-b39d-92ff7951e921} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_dialplan_asterisk + {e7bc026c-7cc5-45a3-bc7c-3b88eef01f24} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_dialplan_directory + {a27cca23-1541-4337-81a4-f0a6413078a0} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_dialplan_xml + {07113b25-d3af-4e04-ba77-4cd1171f022c} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_ldap + {ec3e5c7f-ee09-47e2-80fe-546363d14a98} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_dingaling + {ffaa4c52-3a53-4f99-90c1-d59d1f0427f3} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_gsmopen + {74b120ff-6935-4dfe-a142-cdb6bea99c90} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_loopback + {b3f424ec-3d8f-417c-b244-3919d5e1a577} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_PortAudio + {5fd31a25-5d83-4794-8bee-904dad84ce71} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_rtc + {3884add2-91d0-4cd6-86d3-d5fb2d4aab9e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_rtmp + {48414740-c693-4968-9846-ee058020c64f} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_skinny + {cc1dd008-9406-448d-a0ad-33c3186cfadb} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_sofia + {0df3abd0-ddc0-4265-b778-07c66780979b} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_verto + {5b2bace4-0f5a-4a21-930d-c0f4b1f58fa6} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_amqp + {7ac7ab4f-5ef3-40a0-ad2b-cf4d9720fac3} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cdr_csv + {44d7deaf-fda5-495e-8b9d-1439e4f4c21e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cdr_mongodb + {4dff29b4-2976-447d-a8b3-43476451517c} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cdr_pg_csv + {411f6d43-9f09-47d0-8b04-e1eb6b67c5bf} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_cdr_sqlite + {2ca661a7-01dd-4532-bf88-b6629dfb544a} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_event_multicast + {784113ef-44d9-4949-835d-7065d3c7ad08} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_event_socket + {05515420-16de-4e63-be73-85be85ba5142} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_odbc_cdr + {096c9a84-55b2-4f9b-97e5-0fdf116fd25f} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_local_stream + {2ca40887-1622-46a1-a7f9-17fd7e7e545b} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_native_file + {9254c4b0-6f60-42b6-bb3a-36d63fc001c7} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_png + {fbc7e2a4-b989-4289-ba7f-68f440e9ef8b} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_shout + {38fe0559-9910-43a8-9e45-3e5004c27692} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_sndfile + {afac0568-7548-42d5-9f6a-8d3400a1e4f6} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_tone_stream + {6ff941ac-82c5-429f-aa4c-ad2fb9e5da52} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_lua + {7b077e7f-1be7-4291-ab86-55e527b25cac} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_managed + {7b42bda1-72c0-4378-a9b6-5c530f8cd61e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_v8 + {9b9d2551-d6bd-4f20-8be5-de30e154a064} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_console + {1c453396-d912-4213-89fd-9b489162b7b5} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_logfile + {d0bcac02-d94b-46b8-9b49-cddcc2bd7909} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_de + {5bc072db-3826-48ea-af34-fe32aa01e83b} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_en + {988cacf7-3fcb-4992-be69-77872ae67dc8} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_es + {fa429e98-8b03-45e6-a096-a4bc5e821de4} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_es_ar + {ceee31e6-8a08-42c7-bebd-5ec12072c136} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_fa + {0e469f3a-ddd0-43ba-a94f-7d93c02219f3} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_fr + {06e3a538-ab32-44f2-b477-755ff9cb5d37} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_he + {a3d7c6cf-aeb1-4159-b741-160eb4b37345} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_hr + {da7addf1-da33-4194-83a5-b48db714d35b} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_hu + {af675478-995a-4115-90c4-b2b0d6470688} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_it + {6d1bec70-4dcd-4fe9-adbd-4a43a67e4d05} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_ja + {07ea6e5a-d181-4abb-becf-67a906867d04} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_nl + {a4b122cf-5196-476b-8c0e-d8bd59ac3c14} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_pl + {20b15650-f910-4211-8729-aab0f520c805} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_pt + {7c22bdff-cc09-400c-8a09-660733980028} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_ru + {0382e8fd-cfdc-41c0-8b03-792c7c84fc31} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_sv + {8cda2b34-fa44-49cc-9ec2-b8f35856cd15} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_th + {c955e1a9-c12c-4bad-ac32-8d53d9268af7} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_say_zh + {b6a9fb7a-1cc4-442b-812d-ec33e4e4a36e} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_xml_cdr + {08dad348-9e0a-4a2e-97f1-f1e7e24a7836} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_xml_curl + {ab91a099-7690-4ecf-8994-e458f4ea1ed4} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + mod_xml_rpc + {cbec7225-0c21-4da8-978e-1f158f8ad950} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + FreeSwitchConsole + {1af3a893-f7be-43dd-b697-8ab2397c0d67} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + Setup.CA.DownloadOpenH264 + {ebfdcfca-8095-4ecc-98be-b494bcb4e042} + True + True + Binaries;Content;Satellites + INSTALLFOLDER + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + - - - - - - - - - - - - - - - - - - - - - - - - - - - - + --> + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/w32/Setup/filter.xslt b/w32/Setup/filter.xslt index 11a102885d..42bfd8502f 100644 --- a/w32/Setup/filter.xslt +++ b/w32/Setup/filter.xslt @@ -6,6 +6,7 @@ + @@ -20,6 +21,8 @@ + + @@ -33,5 +36,6 @@ + diff --git a/w32/download_openh264.props b/w32/download_openh264.props new file mode 100644 index 0000000000..1e5d7d7e19 --- /dev/null +++ b/w32/download_openh264.props @@ -0,0 +1,45 @@ + + + + + + + + true + + + + + + + + + diff --git a/w32/download_sharpziplib.props b/w32/download_sharpziplib.props new file mode 100644 index 0000000000..7a87d49d37 --- /dev/null +++ b/w32/download_sharpziplib.props @@ -0,0 +1,44 @@ + + + + + + + true + + + + + + + + + diff --git a/w32/downloadpackage.task b/w32/downloadpackage.task index 9c7471659f..0c7081a0fb 100644 --- a/w32/downloadpackage.task +++ b/w32/downloadpackage.task @@ -14,6 +14,7 @@ + @@ -56,6 +57,7 @@ using System.Diagnostics; public string outputfilename { get; set; } public string extractto { get; set; } public string moveafter { get; set; } + public string archivecontains { get; set; } internal static bool FileOrDirectoryExists(string name) { @@ -148,7 +150,10 @@ using System.Diagnostics; Log.LogMessage(MessageImportance.High, "Filename \"" + filename + "\"."); - if (File.Exists(filename)) + if (archivecontains == null || archivecontains.Trim() == "") + archivecontains = "tarball"; + + if (File.Exists(filename) && archivecontains.ToLower() == "tarball") { Extract(filename, extracttofolder); File.Delete(filename); diff --git a/w32/ffmpeg.props b/w32/ffmpeg.props index 4963a9e668..fe039de408 100644 --- a/w32/ffmpeg.props +++ b/w32/ffmpeg.props @@ -15,11 +15,14 @@ $(ffmpegDir);$(ffmpegDir)\compat\atomics\win32;%(AdditionalIncludeDirectories) - $(ffmpegDir)\include_x64;%(AdditionalIncludeDirectories) + $(ffmpegDir)\include_x64;%(AdditionalIncludeDirectories) + $(ffmpegDir)\include_openh264_x64;%(AdditionalIncludeDirectories) HAVE_FFMPEG;FFMPEG_STATICLIB;HAVE_AV_CONFIG_H;_ISOC99_SOURCE;_FILE_OFFSET_BITS=64;_LARGEFILE_SOURCE;_USE_MATH_DEFINES;_CRT_SECURE_NO_WARNINGS;_CRT_NONSTDC_NO_WARNINGS;_WIN32_WINNT=0x0502;%(PreprocessorDefinitions) + $(ffmpegDir);%(AdditionalLibraryDirectories) Bcrypt.lib;Secur32.lib;%(AdditionalDependencies) + openh264.lib;%(AdditionalDependencies) diff --git a/w32/libks-version.props b/w32/libks-version.props index 3b9fe4b776..db4eb626b8 100644 --- a/w32/libks-version.props +++ b/w32/libks-version.props @@ -4,7 +4,7 @@ - 0.1.1 + 1.3.0 true diff --git a/w32/modules.props b/w32/modules.props index 80aa16563a..ee73237441 100644 --- a/w32/modules.props +++ b/w32/modules.props @@ -2,10 +2,11 @@ + - $(SolutionDir)$(PlatformName)\$(Configuration)\mod\ - $(PlatformName)\$(Configuration)\ + $(SolutionDir)$(PlatformName)\$(SolutionConfiguration)\mod\ + $(PlatformName)\$(SolutionConfiguration)\ diff --git a/w32/signalwire-client-c-version.props b/w32/signalwire-client-c-version.props index 0b0de97606..c62174b6a7 100644 --- a/w32/signalwire-client-c-version.props +++ b/w32/signalwire-client-c-version.props @@ -4,7 +4,7 @@ - 1.0.0 + 1.2.0 true diff --git a/w32/solution_configuration.props b/w32/solution_configuration.props new file mode 100644 index 0000000000..d2553ce6bc --- /dev/null +++ b/w32/solution_configuration.props @@ -0,0 +1,13 @@ + + + + true + + + $(Configuration) + Debug + Release + Debug + Release + + \ No newline at end of file