mirror of
https://github.com/signalwire/freeswitch.git
synced 2025-04-15 00:22:35 +00:00
Merge branch 'master' into v1.6
This commit is contained in:
commit
684235116d
build
conf
testing
vanilla
debian
htdocs/portal/assets/bootstrap/css
html5/verto
js/src
verto_communicator
bower.json
js/3rd-party
package.jsonsrc
css
index.htmlpartials
storageService/services
vertoApp
vertoControllers/controllers
ChatController.jsDialPadController.jsInCallController.jsMainController.jsMenuController.jsModalSettingsController.jsPreviewController.jsSplashScreenController.js
vertoService/services
video_demo
libs
src
include
mod
applications
mod_av
mod_conference
conference_api.cconference_event.cconference_file.cconference_member.cconference_video.cmod_conference.cmod_conference.h
mod_hiredis
mod_http_cache
codecs
endpoints
mod_rtmp
mod_skypopen
mod_sofia
mod_verto
event_handlers/mod_format_cdr
formats
languages/mod_lua
xml_int/mod_xml_radius
@ -1,5 +1,6 @@
|
||||
MK=`echo $(MAKE) | $(AWK) '{printf "%5s\n", $$0}' `
|
||||
|
||||
|
||||
all:
|
||||
@echo " +---------- FreeSWITCH Build Complete ----------+"
|
||||
@echo " + FreeSWITCH has been successfully built. +"
|
||||
@ -54,6 +55,13 @@ install:
|
||||
@echo " + Install/Re-install default config: +"
|
||||
@echo " + ---------------------------------- +"
|
||||
@echo " + $(MK) samples +"
|
||||
if SYSTEMD_INIT
|
||||
@echo " + +"
|
||||
@echo " + Install systemd startup scripts: +"
|
||||
@echo " + -------------------------------- +"
|
||||
@echo " + +"
|
||||
@echo " + build/startup/install_systemd.sh +"
|
||||
endif
|
||||
@echo " + +"
|
||||
@echo " + +"
|
||||
@echo " + Additional resources: +"
|
||||
|
@ -1 +0,0 @@
|
||||
d /run/freeswitch 0750 freeswitch daemon -
|
@ -1,17 +0,0 @@
|
||||
[Unit]
|
||||
Description=FreeSWITCH
|
||||
After=syslog.target network.target
|
||||
After=postgresql.service postgresql-9.3.service postgresql-9.4.service mysqld.service httpd.service
|
||||
|
||||
[Service]
|
||||
User=freeswitch
|
||||
EnvironmentFile=-/etc/sysconfig/freeswitch
|
||||
# RuntimeDirectory is not yet supported in CentOS 7. A workaround is to use /etc/tmpfiles.d/freeswitch.conf
|
||||
#RuntimeDirectory=/run/freeswitch
|
||||
#RuntimeDirectoryMode=0750
|
||||
WorkingDirectory=/run/freeswitch
|
||||
ExecStart=/usr/bin/freeswitch -nc -nf $FREESWITCH_PARAMS
|
||||
ExecReload=/usr/bin/kill -HUP $MAINPID
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
@ -23,6 +23,7 @@ applications/mod_fifo
|
||||
applications/mod_fsk
|
||||
applications/mod_fsv
|
||||
applications/mod_hash
|
||||
applications/mod_hiredis
|
||||
applications/mod_httapi
|
||||
applications/mod_http_cache
|
||||
#applications/mod_ladspa
|
||||
@ -101,7 +102,6 @@ event_handlers/mod_erlang_event
|
||||
event_handlers/mod_event_multicast
|
||||
event_handlers/mod_event_socket
|
||||
event_handlers/mod_format_cdr
|
||||
event_handlers/mod_hiredis
|
||||
event_handlers/mod_json_cdr
|
||||
#event_handlers/mod_radius_cdr
|
||||
event_handlers/mod_odbc_cdr
|
||||
|
2
build/startup/freeswitch.default
Normal file
2
build/startup/freeswitch.default
Normal file
@ -0,0 +1,2 @@
|
||||
# /etc/default/freeswitch
|
||||
DAEMON_OPTS="-nonat"
|
32
build/startup/freeswitch.service.in
Normal file
32
build/startup/freeswitch.service.in
Normal file
@ -0,0 +1,32 @@
|
||||
[Unit]
|
||||
Description=freeswitch
|
||||
After=syslog.target network.target local-fs.target
|
||||
|
||||
[Service]
|
||||
; service
|
||||
Type=forking
|
||||
PIDFile=@runtimedir@/freeswitch.pid
|
||||
PermissionsStartOnly=true
|
||||
Environment="DAEMON_OPTS=-nonat"
|
||||
EnvironmentFile=-/etc/sysconfig/freeswitch
|
||||
EnvironmentFile=-/etc/default/freeswitch
|
||||
ExecStart=@bindir_expanded@/freeswitch -u freeswitch -g freeswitch -ncwait -rp ${DAEMON_OPTS}
|
||||
TimeoutSec=20s
|
||||
Restart=on-failure
|
||||
; exec
|
||||
User=root
|
||||
Group=daemon
|
||||
LimitCORE=infinity
|
||||
LimitNOFILE=100000
|
||||
LimitNPROC=60000
|
||||
;LimitSTACK=240
|
||||
LimitRTPRIO=infinity
|
||||
LimitRTTIME=7000000
|
||||
IOSchedulingClass=realtime
|
||||
IOSchedulingPriority=2
|
||||
CPUSchedulingPolicy=rr
|
||||
CPUSchedulingPriority=89
|
||||
UMask=0007
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
1
build/startup/freeswitch.tmpfile
Normal file
1
build/startup/freeswitch.tmpfile
Normal file
@ -0,0 +1 @@
|
||||
d /var/run/freeswitch 0755 freeswitch freeswitch - -
|
59
build/startup/install_systemd.sh.in
Normal file
59
build/startup/install_systemd.sh.in
Normal file
@ -0,0 +1,59 @@
|
||||
#!/bin/bash
|
||||
# Niek Vlessert
|
||||
|
||||
USER=`whoami`
|
||||
DISTRO=$(source /etc/os-release && echo $PRETTY_NAME)
|
||||
if [ $USER != "root" ] ; then
|
||||
SUDO=`which sudo | awk -F"/" '{print $NF}'`
|
||||
if [ -z $SUDO ] ; then
|
||||
echo "No root and no sudo... please run this as root or install sudo and make sure your user has permissions to use it."
|
||||
exit
|
||||
else
|
||||
read -p "The currently active user is not root but sudo is available... do you want to install using sudo? (y/n) " -n 1 -r
|
||||
if ! [[ $REPLY =~ ^[yY]$ ]]
|
||||
then
|
||||
echo
|
||||
exit
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
echo
|
||||
echo "This will do several things on your $DISTRO installation:"
|
||||
echo "- Create user freeswitch and add it to group freeswitch"
|
||||
FSPATH=@prefix@
|
||||
if [[ $FSPATH == *"freeswitch"* ]]
|
||||
then
|
||||
echo "- Set permissions on @prefix@ and files in @bindir_expanded@"
|
||||
fi
|
||||
echo "- Install systemd unit file and other required files"
|
||||
echo
|
||||
read -p "Do you want to continue? (y/n) " -n 1 -r
|
||||
if [[ $REPLY =~ ^[yY]$ ]]
|
||||
then
|
||||
echo
|
||||
echo "Installing..."
|
||||
$SUDO useradd -d @confdir@ -r -U -s /bin/false -c "FreeSWITCH open source softswitch" freeswitch
|
||||
if [[ $FSPATH == *"freeswitch"* ]]
|
||||
then
|
||||
$SUDO chown -R freeswitch:freeswitch @prefix@
|
||||
$SUDO chmod -R ug=rwX,o= @prefix@
|
||||
$SUDO chmod -R u=rwx,g=rx @bindir_expanded@/*
|
||||
fi
|
||||
$SUDO cp build/startup/freeswitch.service /etc/systemd/system/
|
||||
$SUDO cp build/startup/freeswitch.tmpfile /etc/tmpfiles.d/freeswitch.conf
|
||||
if [ -d /etc/sysconfig ]; then
|
||||
$SUDO cp build/startup/freeswitch.default /etc/sysconfig/freeswitch
|
||||
else
|
||||
$SUDO cp build/startup/freeswitch.default /etc/default/freeswitch
|
||||
fi
|
||||
$SUDO systemd-tmpfiles --clean --create
|
||||
$SUDO systemctl daemon-reload
|
||||
echo
|
||||
if [ -f @confdir@/vars.xml ] ; then
|
||||
echo "You may now start Freeswitch using 'systemctl start freeswitch'"
|
||||
else
|
||||
echo "Make sure your config files are in place in @confdir@, if they are you can start Freeswitch using 'systemctl start freeswitch'"
|
||||
fi
|
||||
echo "Then start fs_cli by running @bindir_expanded@/fs_cli"
|
||||
fi
|
@ -281,6 +281,41 @@
|
||||
<param name="video-fps" value="15"/>
|
||||
</profile>
|
||||
|
||||
<profile name="video-mcu-stereo-personal">
|
||||
<param name="domain" value="$${domain}"/>
|
||||
<param name="rate" value="48000"/>
|
||||
<param name="channels" value="2"/>
|
||||
<param name="interval" value="20"/>
|
||||
<param name="energy-level" value="200"/>
|
||||
<!-- <param name="tts-engine" value="flite"/> -->
|
||||
<!-- <param name="tts-voice" value="kal16"/> -->
|
||||
<param name="caller-controls" value="defaultvideo"/>
|
||||
<param name="muted-sound" value="conference/conf-muted.wav"/>
|
||||
<param name="unmuted-sound" value="conference/conf-unmuted.wav"/>
|
||||
<param name="alone-sound" value="conference/conf-alone.wav"/>
|
||||
<param name="moh-sound" value="local_stream://video"/>
|
||||
<param name="enter-sound" value="tone_stream://%(200,0,500,600,700)"/>
|
||||
<param name="exit-sound" value="tone_stream://%(500,0,300,200,100,50,25)"/>
|
||||
<param name="kicked-sound" value="conference/conf-kicked.wav"/>
|
||||
<param name="locked-sound" value="conference/conf-locked.wav"/>
|
||||
<param name="is-locked-sound" value="conference/conf-is-locked.wav"/>
|
||||
<param name="is-unlocked-sound" value="conference/conf-is-unlocked.wav"/>
|
||||
<param name="pin-sound" value="conference/conf-pin.wav"/>
|
||||
<param name="bad-pin-sound" value="conference/conf-bad-pin.wav"/>
|
||||
<param name="caller-id-name" value="$${outbound_caller_name}"/>
|
||||
<param name="caller-id-number" value="$${outbound_caller_id}"/>
|
||||
<param name="comfort-noise" value="false"/>
|
||||
<param name="conference-flags" value="video-muxing-personal-canvas|livearray-json-status|json-events|video-floor-only|livearray-sync|minimize-video-encoding|video-required-for-canvas"/>
|
||||
<param name="video-mode" value="mux"/>
|
||||
<param name="video-layout-name" value="3x3"/>
|
||||
<param name="video-layout-name" value="group:grid"/>
|
||||
<param name="video-canvas-size" value="1920x1080"/>
|
||||
<param name="video-canvas-bgcolor" value="#333333"/>
|
||||
<param name="video-layout-bgcolor" value="#000000"/>
|
||||
<param name="video-codec-bandwidth" value="3mb"/>
|
||||
<param name="video-fps" value="15"/>
|
||||
</profile>
|
||||
|
||||
<profile name="test_res_id">
|
||||
<param name="domain" value="$${domain}"/>
|
||||
<param name="rate" value="48000"/>
|
||||
|
@ -7,6 +7,15 @@
|
||||
<action application="conference" data="6070@video-mcu-stereo"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
<extension name="conf">
|
||||
<condition field="destination_number" expression="^6070-personal$">
|
||||
<!--<action application="answer" data="is_conference"/> -->
|
||||
|
||||
<action application="push" data="conference_member_flags=moderator"/>
|
||||
<action application="conference" data="6070@video-mcu-stereo-personal"/>
|
||||
</condition>
|
||||
</extension>
|
||||
<extension name="cdquality_stereo_conferences">
|
||||
<condition field="destination_number" expression="^(6070).*?-screen$">
|
||||
<action application="answer"/>
|
||||
@ -16,6 +25,13 @@
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
<extension name="conference-canvases" continue="true">
|
||||
<condition field="destination_number" expression="(.*?)-canvas-(\d+)">
|
||||
<action application="push" data="conference_member_flags=second-screen"/>
|
||||
<action application="set" data="video_initial_watching_canvas=$2"/>
|
||||
<action application="transfer" data="$1"/>
|
||||
</condition>
|
||||
</extension>
|
||||
|
||||
<extension name="conf">
|
||||
<condition field="destination_number" expression="^6070-moderator$">
|
||||
|
@ -78,5 +78,6 @@
|
||||
<!-- Stock Video Avatars -->
|
||||
<X-PRE-PROCESS cmd="set" data="video_mute_png=$${images_dir}/default-mute.png"/>
|
||||
<X-PRE-PROCESS cmd="set" data="video_no_avatar_png=$${images_dir}/default-avatar.png"/>
|
||||
|
||||
<X-PRE-PROCESS cmd="set" data="api_on_startup=fsctl recover"/>
|
||||
|
||||
</include>
|
||||
|
@ -152,6 +152,12 @@
|
||||
|
||||
<param name="rtp-enable-zrtp" value="false"/>
|
||||
|
||||
<!--
|
||||
Store encryption keys for secure media in channel variables and call CDRs. Default: false.
|
||||
WARNING: If true, anyone with CDR access can decrypt secure media!
|
||||
-->
|
||||
<!-- <param name="rtp-retain-crypto-keys" value="true"/> -->
|
||||
|
||||
<!-- <param name="core-db-dsn" value="pgsql://hostaddr=127.0.0.1 dbname=freeswitch user=freeswitch password='' options='-c client_min_messages=NOTICE'" /> -->
|
||||
<!-- <param name="core-db-dsn" value="dsn:username:password" /> -->
|
||||
<!--
|
||||
|
@ -21,7 +21,7 @@
|
||||
<!--the domain or ip (the right hand side of the @ in the addr-->
|
||||
<domain name="$${domain}">
|
||||
<params>
|
||||
<param name="dial-string" value="{^^:sip_invite_domain=${dialed_domain}:presence_id=${dialed_user}@${dialed_domain}}${sofia_contact(*/${dialed_user}@${dialed_domain})}"/>
|
||||
<param name="dial-string" value="{^^:sip_invite_domain=${dialed_domain}:presence_id=${dialed_user}@${dialed_domain}}${sofia_contact(*/${dialed_user}@${dialed_domain})},${verto_contact(${dialed_user}@${dialed_domain})}"/>
|
||||
<!-- These are required for Verto to function properly -->
|
||||
<param name="jsonrpc-allowed-methods" value="verto"/>
|
||||
<!-- <param name="jsonrpc-allowed-event-channels" value="demo,conference,presence"/> -->
|
||||
|
10
configure.ac
10
configure.ac
@ -83,6 +83,8 @@ default_certsdir="$prefix/certs"
|
||||
default_fontsdir="$prefix/fonts"
|
||||
default_imagesdir="$prefix/images"
|
||||
|
||||
eval bindir_expanded="${bindir}"
|
||||
|
||||
if test "${enable_fhs}" = "yes"; then
|
||||
eval full_datadir="${datadir}/freeswitch"
|
||||
eval datadir=$full_datadir
|
||||
@ -771,6 +773,14 @@ case "$host" in
|
||||
;;
|
||||
*linux*)
|
||||
APR_ADDTO([PLATFORM_CORE_LIBS], [-ldl -lcrypt -lrt])
|
||||
systemdinit=false
|
||||
if test -d /run/systemd/system; then
|
||||
systemdinit=true
|
||||
AC_SUBST(bindir_expanded)
|
||||
AC_CONFIG_FILES([build/startup/install_systemd.sh], [chmod +x build/startup/install_systemd.sh])
|
||||
AC_CONFIG_FILES([build/startup/freeswitch.service])
|
||||
fi
|
||||
AM_CONDITIONAL([SYSTEMD_INIT], [test x$systemdinit = xtrue])
|
||||
;;
|
||||
esac
|
||||
|
||||
|
3
debian/bootstrap.sh
vendored
3
debian/bootstrap.sh
vendored
@ -70,13 +70,14 @@ avoid_mods_wheezy=(
|
||||
languages/mod_managed
|
||||
applications/mod_av
|
||||
applications/mod_cv
|
||||
applications/mod_hiredis
|
||||
applications/mod_hiredis
|
||||
formats/mod_shout
|
||||
applications/mod_sonar
|
||||
applications/mod_soundtouch
|
||||
formats/mod_vlc
|
||||
)
|
||||
avoid_mods_trusty=(
|
||||
event_handlers/mod_amqp
|
||||
)
|
||||
avoid_mods_utopic=(
|
||||
directories/mod_ldap
|
||||
|
4
debian/freeswitch-mod-perl.install.tmpl
vendored
4
debian/freeswitch-mod-perl.install.tmpl
vendored
@ -1,2 +1,2 @@
|
||||
debian/tmp/usr/perl/freeswitch.pm /usr/lib/perl5
|
||||
debian/tmp/usr/perl/freeswitch.so /usr/lib/perl5/auto/freeswitch
|
||||
debian/tmp/usr/perl/freeswitch.pm /usr/share/perl5
|
||||
debian/tmp/usr/perl/freeswitch.so /usr/share/perl5/auto/freeswitch
|
||||
|
@ -223,7 +223,7 @@ textarea {
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-family: verdana, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 14px;
|
||||
line-height: 20px;
|
||||
color: #333333;
|
||||
@ -1065,7 +1065,7 @@ input,
|
||||
button,
|
||||
select,
|
||||
textarea {
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-family: verdana, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
}
|
||||
|
||||
label {
|
||||
@ -4510,7 +4510,7 @@ input[type="submit"].btn.btn-mini {
|
||||
.navbar-search .search-query {
|
||||
padding: 4px 14px;
|
||||
margin-bottom: 0;
|
||||
font-family: "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-family: verdana, "Helvetica Neue", Helvetica, Arial, sans-serif;
|
||||
font-size: 13px;
|
||||
font-weight: normal;
|
||||
line-height: 1;
|
||||
@ -5624,7 +5624,6 @@ a.thumbnail:focus {
|
||||
display: inline-block;
|
||||
padding: 2px 4px;
|
||||
font-size: 11.844px;
|
||||
font-weight: bold;
|
||||
line-height: 14px;
|
||||
color: #ffffff;
|
||||
text-shadow: 0 -1px 0 rgba(0, 0, 0, 0.25);
|
||||
|
@ -90,7 +90,8 @@
|
||||
},
|
||||
}, options);
|
||||
|
||||
this.enabled = true;
|
||||
this.audioEnabled = true;
|
||||
this.videoEnabled = true;
|
||||
|
||||
|
||||
this.mediaData = {
|
||||
@ -360,7 +361,7 @@
|
||||
|
||||
$.FSRTC.prototype.getMute = function() {
|
||||
var self = this;
|
||||
return self.enabled;
|
||||
return self.audioEnabled;
|
||||
}
|
||||
|
||||
$.FSRTC.prototype.setMute = function(what) {
|
||||
@ -381,10 +382,39 @@
|
||||
break;
|
||||
}
|
||||
|
||||
self.enabled = audioTracks[i].enabled;
|
||||
self.audioEnabled = audioTracks[i].enabled;
|
||||
}
|
||||
|
||||
return !self.enabled;
|
||||
return !self.audioEnabled;
|
||||
}
|
||||
|
||||
$.FSRTC.prototype.getVideoMute = function() {
|
||||
var self = this;
|
||||
return self.videoEnabled;
|
||||
}
|
||||
|
||||
$.FSRTC.prototype.setVideoMute = function(what) {
|
||||
var self = this;
|
||||
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) {
|
||||
|
@ -91,6 +91,32 @@
|
||||
/// 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
|
||||
@ -382,6 +408,26 @@
|
||||
$.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);
|
||||
this.speedCB(event, { upDur: this.up_dur, downDur: this.down_dur, upKPS: up_kps, downKPS: down_kps });
|
||||
this.speedCB = null;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
try {
|
||||
response = $.parseJSON(event.data);
|
||||
|
||||
|
@ -1075,6 +1075,27 @@
|
||||
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;
|
||||
@ -1122,7 +1143,7 @@
|
||||
return;
|
||||
}
|
||||
dt.fnClearTable();
|
||||
dt.fnAddData(obj.asArray());
|
||||
dt.fnAddData(genArray(obj));
|
||||
dt.fnAdjustColumnSizing();
|
||||
break;
|
||||
case "add":
|
||||
@ -1133,9 +1154,9 @@
|
||||
if (args.redraw > -1) {
|
||||
// specific position, more costly
|
||||
dt.fnClearTable();
|
||||
dt.fnAddData(obj.asArray());
|
||||
dt.fnAddData(genArray(obj));
|
||||
} else {
|
||||
dt.fnAddData(args.data);
|
||||
dt.fnAddData(genRow(args.data));
|
||||
}
|
||||
dt.fnAdjustColumnSizing();
|
||||
break;
|
||||
@ -1144,7 +1165,7 @@
|
||||
return;
|
||||
}
|
||||
//console.debug(args, index);
|
||||
dt.fnUpdate(args.data, index);
|
||||
dt.fnUpdate(genRow(args.data), index);
|
||||
dt.fnAdjustColumnSizing();
|
||||
break;
|
||||
case "del":
|
||||
@ -1157,7 +1178,7 @@
|
||||
case "reorder":
|
||||
// specific position, more costly
|
||||
dt.fnClearTable();
|
||||
dt.fnAddData(obj.asArray());
|
||||
dt.fnAddData(genArray(obj));
|
||||
break;
|
||||
case "hide":
|
||||
jq.hide();
|
||||
@ -2022,6 +2043,53 @@
|
||||
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;
|
||||
|
||||
@ -2061,11 +2129,9 @@
|
||||
console.info("Using Speaker: ", speaker);
|
||||
|
||||
if (speaker && speaker !== "any") {
|
||||
var videoElement = dialog.audioStream;
|
||||
|
||||
setTimeout(function() {
|
||||
console.info("Setting speaker:", videoElement, speaker);
|
||||
attachSinkId(videoElement, speaker);}, 500);
|
||||
dialog.setAudioPlaybackDevice(speaker);
|
||||
}, 500);
|
||||
}
|
||||
|
||||
break;
|
||||
@ -2226,6 +2292,16 @@
|
||||
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;
|
||||
|
||||
|
@ -42,7 +42,7 @@
|
||||
"jquery-cookie": "~1.4.1",
|
||||
"jquery-json": "~2.5.1",
|
||||
"datatables": "~1.10.8",
|
||||
"angular-bootstrap": "~0.13.3",
|
||||
"angular-bootstrap": "~0.14.3",
|
||||
"bootstrap-material-design": "~0.3.0"
|
||||
},
|
||||
"resolutions": {
|
||||
|
@ -1,10 +1,10 @@
|
||||
// Last time updated at Sep 07, 2014, 08:32:23
|
||||
// Last time updated at Oct 24, 2015, 08:32:23
|
||||
|
||||
// Latest file can be found here: https://cdn.webrtc-experiment.com/getScreenId.js
|
||||
|
||||
// Muaz Khan - www.MuazKhan.com
|
||||
// MIT License - www.WebRTC-Experiment.com/licence
|
||||
// Documentation - https://github.com/muaz-khan/WebRTC-Experiment/tree/master/getScreenId.js
|
||||
// Documentation - https://github.com/muaz-khan/getScreenId.
|
||||
|
||||
// ______________
|
||||
// getScreenId.js
|
||||
@ -13,7 +13,7 @@
|
||||
getScreenId(function (error, sourceId, screen_constraints) {
|
||||
// error == null || 'permission-denied' || 'not-installed' || 'installed-disabled' || 'not-chrome'
|
||||
// sourceId == null || 'string' || 'firefox'
|
||||
|
||||
|
||||
if(sourceId == 'firefox') {
|
||||
navigator.mozGetUserMedia(screen_constraints, onSuccess, onFailure);
|
||||
}
|
||||
@ -79,6 +79,11 @@ getScreenId(function (error, sourceId, screen_constraints) {
|
||||
}
|
||||
|
||||
function postMessage() {
|
||||
if (!iframe) {
|
||||
loadIFrame(postMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iframe.isLoaded) {
|
||||
setTimeout(postMessage, 100);
|
||||
return;
|
||||
@ -89,11 +94,137 @@ getScreenId(function (error, sourceId, screen_constraints) {
|
||||
}, '*');
|
||||
}
|
||||
|
||||
var iframe = document.createElement('iframe');
|
||||
iframe.onload = function() {
|
||||
iframe.isLoaded = true;
|
||||
function loadIFrame(loadCallback) {
|
||||
if (iframe) {
|
||||
loadCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.onload = function() {
|
||||
iframe.isLoaded = true;
|
||||
|
||||
loadCallback();
|
||||
};
|
||||
iframe.src = 'https://www.webrtc-experiment.com/getSourceId/'; // https://wwww.yourdomain.com/getScreenId.html
|
||||
iframe.style.display = 'none';
|
||||
(document.body || document.documentElement).appendChild(iframe);
|
||||
}
|
||||
|
||||
var iframe;
|
||||
|
||||
// this function is used in v3.0
|
||||
window.getScreenConstraints = function(callback) {
|
||||
loadIFrame(function() {
|
||||
getScreenId(function(error, sourceId, screen_constraints) {
|
||||
callback(error, screen_constraints.video);
|
||||
});
|
||||
});
|
||||
};
|
||||
})();
|
||||
|
||||
(function() {
|
||||
if(document.domain.indexOf('webrtc-experiment.com') === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
window.getScreenId = function(callback) {
|
||||
// for Firefox:
|
||||
// sourceId == 'firefox'
|
||||
// screen_constraints = {...}
|
||||
if (!!navigator.mozGetUserMedia) {
|
||||
callback(null, 'firefox', {
|
||||
video: {
|
||||
mozMediaSource: 'window',
|
||||
mediaSource: 'window'
|
||||
}
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
postMessage();
|
||||
|
||||
window.addEventListener('message', onIFrameCallback);
|
||||
|
||||
function onIFrameCallback(event) {
|
||||
if (!event.data) return;
|
||||
|
||||
if (event.data.chromeMediaSourceId) {
|
||||
if (event.data.chromeMediaSourceId === 'PermissionDeniedError') {
|
||||
callback('permission-denied');
|
||||
} else callback(null, event.data.chromeMediaSourceId, getScreenConstraints(null, event.data.chromeMediaSourceId));
|
||||
}
|
||||
|
||||
if (event.data.chromeExtensionStatus) {
|
||||
callback(event.data.chromeExtensionStatus, null, getScreenConstraints(event.data.chromeExtensionStatus));
|
||||
}
|
||||
|
||||
// this event listener is no more needed
|
||||
window.removeEventListener('message', onIFrameCallback);
|
||||
}
|
||||
};
|
||||
|
||||
function getScreenConstraints(error, sourceId) {
|
||||
var screen_constraints = {
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: error ? 'screen' : 'desktop',
|
||||
maxWidth: window.screen.width > 1920 ? window.screen.width : 1920,
|
||||
maxHeight: window.screen.height > 1080 ? window.screen.height : 1080
|
||||
},
|
||||
optional: []
|
||||
}
|
||||
};
|
||||
|
||||
if (sourceId) {
|
||||
screen_constraints.video.mandatory.chromeMediaSourceId = sourceId;
|
||||
}
|
||||
|
||||
return screen_constraints;
|
||||
}
|
||||
|
||||
function postMessage() {
|
||||
if (!iframe) {
|
||||
loadIFrame(postMessage);
|
||||
return;
|
||||
}
|
||||
|
||||
if (!iframe.isLoaded) {
|
||||
setTimeout(postMessage, 100);
|
||||
return;
|
||||
}
|
||||
|
||||
iframe.contentWindow.postMessage({
|
||||
captureSourceId: true
|
||||
}, '*');
|
||||
}
|
||||
|
||||
function loadIFrame(loadCallback) {
|
||||
if (iframe) {
|
||||
loadCallback();
|
||||
return;
|
||||
}
|
||||
|
||||
iframe = document.createElement('iframe');
|
||||
iframe.onload = function() {
|
||||
iframe.isLoaded = true;
|
||||
|
||||
loadCallback();
|
||||
};
|
||||
iframe.src = 'https://www.webrtc-experiment.com/getSourceId/'; // https://wwww.yourdomain.com/getScreenId.html
|
||||
iframe.style.display = 'none';
|
||||
(document.body || document.documentElement).appendChild(iframe);
|
||||
}
|
||||
|
||||
var iframe;
|
||||
|
||||
// this function is used in v3.0
|
||||
window.getScreenConstraints = function(callback) {
|
||||
loadIFrame(function() {
|
||||
getScreenId(function(error, sourceId, screen_constraints) {
|
||||
callback(error, screen_constraints.video);
|
||||
});
|
||||
});
|
||||
};
|
||||
iframe.src = 'https://www.webrtc-experiment.com/getSourceId/';
|
||||
iframe.style.display = 'none';
|
||||
(document.body || document.documentElement).appendChild(iframe);
|
||||
})();
|
||||
|
96
html5/verto/verto_communicator/js/3rd-party/volume-meter.js
vendored
Normal file
96
html5/verto/verto_communicator/js/3rd-party/volume-meter.js
vendored
Normal file
@ -0,0 +1,96 @@
|
||||
/*
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2014 Chris Wilson
|
||||
|
||||
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.
|
||||
*/
|
||||
|
||||
/*
|
||||
|
||||
Usage:
|
||||
audioNode = createAudioMeter(audioContext,clipLevel,averaging,clipLag);
|
||||
|
||||
audioContext: the AudioContext you're using.
|
||||
clipLevel: the level (0 to 1) that you would consider "clipping".
|
||||
Defaults to 0.98.
|
||||
averaging: how "smoothed" you would like the meter to be over time.
|
||||
Should be between 0 and less than 1. Defaults to 0.95.
|
||||
clipLag: how long you would like the "clipping" indicator to show
|
||||
after clipping has occured, in milliseconds. Defaults to 750ms.
|
||||
|
||||
Access the clipping through node.checkClipping(); use node.shutdown to get rid of it.
|
||||
*/
|
||||
|
||||
function createAudioMeter(audioContext,clipLevel,averaging,clipLag) {
|
||||
var processor = audioContext.createScriptProcessor(512);
|
||||
processor.onaudioprocess = volumeAudioProcess;
|
||||
processor.clipping = false;
|
||||
processor.lastClip = 0;
|
||||
processor.volume = 0;
|
||||
processor.clipLevel = clipLevel || 0.98;
|
||||
processor.averaging = averaging || 0.95;
|
||||
processor.clipLag = clipLag || 750;
|
||||
|
||||
// this will have no effect, since we don't copy the input to the output,
|
||||
// but works around a current Chrome bug.
|
||||
processor.connect(audioContext.destination);
|
||||
|
||||
processor.checkClipping =
|
||||
function(){
|
||||
if (!this.clipping)
|
||||
return false;
|
||||
if ((this.lastClip + this.clipLag) < window.performance.now())
|
||||
this.clipping = false;
|
||||
return this.clipping;
|
||||
};
|
||||
|
||||
processor.shutdown =
|
||||
function(){
|
||||
this.disconnect();
|
||||
this.onaudioprocess = null;
|
||||
};
|
||||
|
||||
return processor;
|
||||
}
|
||||
|
||||
function volumeAudioProcess( event ) {
|
||||
var buf = event.inputBuffer.getChannelData(0);
|
||||
var bufLength = buf.length;
|
||||
var sum = 0;
|
||||
var x;
|
||||
|
||||
// Do a root-mean-square on the samples: sum up the squares...
|
||||
for (var i=0; i<bufLength; i++) {
|
||||
x = buf[i];
|
||||
if (Math.abs(x)>=this.clipLevel) {
|
||||
this.clipping = true;
|
||||
this.lastClip = window.performance.now();
|
||||
}
|
||||
sum += x * x;
|
||||
}
|
||||
|
||||
// ... then take the square root of the sum.
|
||||
var rms = Math.sqrt(sum / bufLength);
|
||||
|
||||
// Now smooth this out with the averaging factor applied
|
||||
// to the previous sample - take the max here because we
|
||||
// want "fast attack, slow release."
|
||||
this.volume = Math.max(rms, this.volume*this.averaging);
|
||||
}
|
@ -15,7 +15,7 @@
|
||||
"grunt-contrib-copy": "^0.7.0",
|
||||
"grunt-contrib-cssmin": "^0.12.0",
|
||||
"grunt-contrib-htmlmin": "^0.4.0",
|
||||
"grunt-contrib-imagemin": "^0.9.2",
|
||||
"grunt-contrib-imagemin": "^1.0.0",
|
||||
"grunt-contrib-jshint": "^0.11.0",
|
||||
"grunt-contrib-uglify": "^0.7.0",
|
||||
"grunt-contrib-watch": "latest",
|
||||
|
@ -8,6 +8,15 @@ body {
|
||||
padding-top: 60px;
|
||||
}
|
||||
|
||||
.panel.panel-material-blue-900 .panel-heading {
|
||||
background-color: #0d47a1;
|
||||
}
|
||||
|
||||
.install {
|
||||
color: white;
|
||||
text-decoration: underline;
|
||||
}
|
||||
|
||||
.ellipsis {
|
||||
text-overflow: ellipsis;
|
||||
overflow: hidden;
|
||||
@ -595,12 +604,8 @@ body .modal-body .btn-group .btn.active {
|
||||
transition-delay:0s;
|
||||
}
|
||||
|
||||
#incall .video-hover-buttons .btn-group {
|
||||
margin: 0;
|
||||
}
|
||||
|
||||
#incall .video-hover-buttons .btn-group .dropdown-menu {
|
||||
height: 200px;
|
||||
max-height: 200px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
@ -766,6 +771,10 @@ body .modal-body .btn-group .btn.active {
|
||||
transition: all 0.5s ease;
|
||||
}
|
||||
|
||||
.tooltip-inner {
|
||||
padding: 8px 8px;
|
||||
background-color: #000;
|
||||
}
|
||||
|
||||
#sidebar-wrapper {
|
||||
right: 360px;
|
||||
@ -909,7 +918,6 @@ body .modal-body .btn-group .btn.active {
|
||||
|
||||
.members-badges {
|
||||
font-size: 10px;
|
||||
text-transform: uppercase;
|
||||
margin-top: -2px;
|
||||
}
|
||||
|
||||
@ -1464,3 +1472,76 @@ body:-webkit-full-screen #incall .video-footer {
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
.preview-wrapper {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.preview-wrapper video {
|
||||
transform: scaleX(-1);
|
||||
}
|
||||
|
||||
.drop-net-info {
|
||||
padding-top: 0px;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.drop-net-info .title {
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
font-weight: bold;
|
||||
padding: 8px 14px;
|
||||
margin: 0;
|
||||
font-size: 14px;
|
||||
background-color: #f7f7f7;
|
||||
border-bottom: 1px solid #ebebeb;
|
||||
}
|
||||
|
||||
.drop-net-info .title:hover {
|
||||
background-color: #f7f7f7;
|
||||
}
|
||||
|
||||
.drop-net-info a:hover {
|
||||
color: #333 !important;
|
||||
}
|
||||
|
||||
.net-info .yellow {
|
||||
color: #e3d95b;
|
||||
}
|
||||
|
||||
.net-info .green {
|
||||
color: #00ae00;
|
||||
}
|
||||
|
||||
.net-info .red {
|
||||
color: #ae0000;
|
||||
}
|
||||
|
||||
#mic-meter {
|
||||
position: absolute;
|
||||
bottom: 5px;
|
||||
left: 10px;
|
||||
}
|
||||
#mic-meter .icon {
|
||||
margin-left: 3px;
|
||||
color: #CCC;
|
||||
}
|
||||
#mic-meter .volumes {
|
||||
width: 30px;
|
||||
}
|
||||
#mic-meter .volumes .volume-segment {
|
||||
height: 10px;
|
||||
width: 100%;
|
||||
border-radius: 5px;
|
||||
border: 2px solid #CCC;
|
||||
display: block;
|
||||
margin-top: 1.5px;
|
||||
}
|
||||
|
||||
#mic-meter .volumes .volume-segment.active {
|
||||
background-color: #CCC;
|
||||
}
|
||||
|
||||
#preview .refresh {
|
||||
margin: 15px 0px 0px 0px;
|
||||
}
|
||||
|
@ -95,6 +95,7 @@
|
||||
|
||||
<script type="text/javascript" src="js/3rd-party/getScreenId.js"></script>
|
||||
<script type="text/javascript" src="js/3rd-party/md5.min.js"></script>
|
||||
<script type="text/javascript" src="js/3rd-party/volume-meter.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoApp/vertoApp.module.js"></script>
|
||||
|
||||
@ -113,6 +114,7 @@
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalWsReconnectController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalLoginInformationController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/ModalSettingsController.js"></script>
|
||||
<script type="text/javascript" src="src/vertoControllers/controllers/PreviewController.js"></script>
|
||||
|
||||
<script type="text/javascript" src="src/vertoDirectives/vertoDirectives.module.js"></script>
|
||||
<script type="text/javascript" src="src/vertoDirectives/directives/autofocus.js"></script>
|
||||
|
@ -28,7 +28,8 @@
|
||||
|
||||
<div class="members-badges">
|
||||
<div ng-if="member.status.video.floor" class="label badge-floor" ng-class="{'label-danger': member.status.video.floorLocked, 'label-info': !member.status.video.floorLocked}"><i class="mdi mdi-action-https lock-floor" ng-if="member.status.video.floorLocked"></i> <span>Floor</span></div>
|
||||
<div ng-if="member.status.video.reservationID == 'presenter'" class="label label-warning">Presenter</div>
|
||||
<div ng-if="member.status.video.reservationID == 'presenter'" class="label label-info">Presenter</div>
|
||||
<div ng-if="member.status.video.screenShare" class="label label-info">Screen Share</div>
|
||||
</div>
|
||||
</h4>
|
||||
|
||||
|
@ -1,4 +1,10 @@
|
||||
<div class="centered-block-frame" id="dialpad">
|
||||
<div ng-show="loading">
|
||||
<h3 style="margin-top: 4%;" class="text-center">Calling to {{ dialpadNumber }}...</h3>
|
||||
<svg class="spinner" width="65px" height="65px" viewBox="0 0 66 66" xmlns="http://www.w3.org/2000/svg">
|
||||
<circle class="path" fill="none" stroke-width="6" stroke-linecap="round" cx="33" cy="33" r="30"></circle>
|
||||
</svg>
|
||||
</div>
|
||||
<div class="centered-block-frame" id="dialpad" ng-show="!loading">
|
||||
<div id="call-history-wrapper">
|
||||
<div id="call_history" class="shadow-z-2 panel">
|
||||
<div class="panel-heading">
|
||||
|
@ -19,9 +19,21 @@
|
||||
</div>
|
||||
<div id="navbar" class="navbar-collapse collapse">
|
||||
<ul class="nav navbar-nav navbar-right">
|
||||
<li class="navbar-item-icon net-info" ng-show="(bandUp || bandDown) && storage.data.autoBand">
|
||||
<a href="" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false">
|
||||
<i ng-class="iconClass"></i>
|
||||
<span class="caret"></span>
|
||||
</a>
|
||||
<ul class="dropdown-menu drop-net-info" role="menu" ng-click="$event.stopPropagation()">
|
||||
<li><a class="title">Bandwidth Info</a></li>
|
||||
<li><a>Outgoing: {{bandUp}} Kbps</a></li>
|
||||
<li><a>Incoming: {{bandDown}} Kbps</a></li>
|
||||
<li><a>Video Resolution: {{vidRes}}</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li>
|
||||
<a href="">
|
||||
<i class="mdi-toggle-radio-button-on" user-status condition="storage.data.userStatus"></i>
|
||||
<i class="mdi-toggle-radio-button-on" user-status condition="storage.data.userStatus"></i>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
@ -29,7 +41,6 @@
|
||||
{{ storage.data.called_number && storage.data.userStatus == 'connecting' ? 'Last Call: ' : 'In Call: ' }} {{ storage.data.called_number }}
|
||||
</a>
|
||||
</li>
|
||||
|
||||
<li class="navbar-item-icon" ng-show="verto.data.connected">
|
||||
<a href="" ng-click="openModal('partials/modal_settings.html', 'ModalSettingsController')">
|
||||
<i class="mdi-action-settings"></i>
|
||||
|
@ -22,10 +22,17 @@
|
||||
<select name="microphone" id="settings-microphone" class="form-control"
|
||||
ng-model="mydata.selectedAudio" ng-options="item.id as item.label for item in verto.data.audioDevices">
|
||||
</select>
|
||||
|
||||
<a class="btn btn-primary" href="" ng-click="refreshDeviceList()">Refresh device list</a>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">Speaker:</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control"
|
||||
ng-model="mydata.selectedSpeaker" ng-options="item.id as item.label for item in verto.data.speakerDevices">
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<a class="btn btn-primary" href="" ng-click="refreshDeviceList()">Refresh device list</a>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="settings-microphone">General settings:</label>
|
||||
<div class="checkbox">
|
||||
@ -84,35 +91,52 @@
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="video-quality">Video quality:</label>
|
||||
<select name="video_quality" id="video-quality" class="form-control"
|
||||
ng-model="mydata.vidQual"
|
||||
ng-options="item.id as item.label for item in verto.videoQuality"></select>
|
||||
</div>
|
||||
<label>Video settings:</label> <br>
|
||||
<input type="hidden" name="use_dedenc" ng-value="mydata.useDedenc" ng-model="mydata.useDedenc">
|
||||
|
||||
<input type="hidden" name="use_dedenc" ng-value="mydata.useDedenc" ng-model="mydata.useDedenc">
|
||||
|
||||
<h4>Dedicated Remote Encoder</h4>
|
||||
<h5>Select a non default bandwidth to use a dedicated remote encoder.</h5>
|
||||
<div ng-show="mydata.useDedenc" class="dedicated_encoder">
|
||||
<p>Dedicated Remote Encoder enabled.</b>
|
||||
</div>
|
||||
|
||||
<div ng-show="mydata.useDedenc" class="dedicated_encoder">
|
||||
<p>Dedicated Remote Encoder enabled.</b>
|
||||
</div>
|
||||
<div class="checkbox">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.autoBand" ng-change="checkAutoBand(mydata.autoBand)">
|
||||
Automatically determine speed and resolution settings
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="outgoing-bandwidth">Max outgoing bandwidth:</label>
|
||||
<select name="outgoing_bandwidth" id="outgoing-bandwidth" class="form-control"
|
||||
ng-model="mydata.outgoingBandwidth"
|
||||
ng-change="checkUseDedRemoteEncoder(mydata.outgoingBandwidth)"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
<div class="checkbox" ng-show="mydata.autoBand">
|
||||
<label>
|
||||
<input type="checkbox" ng-model="mydata.testSpeedJoin">
|
||||
Recheck bandwidth before each outgoing call
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-group">
|
||||
<label for="incoming-bandwidth">Max incoming bandwidth:</label>
|
||||
<select name="incoming_bandwidth" id="incoming-bandwidth" class="form-control"
|
||||
ng-model="mydata.incomingBandwidth"
|
||||
ng-change="checkUseDedRemoteEncoder(mydata.incomingBandwidth)"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
<a ng-show="mydata.autoBand" class="btn btn-primary" href="" ng-click="testSpeed()">Check Network Speed</a> <span ng-bind="speedMsg"></span>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="video-quality">Video quality:</label>
|
||||
<select name="video_quality" id="video-quality" class="form-control"
|
||||
ng-disabled="mydata.autoBand"
|
||||
ng-model="mydata.vidQual"
|
||||
ng-options="item.id as item.label for item in verto.videoQuality"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="incoming-bandwidth">Max incoming bandwidth:</label>
|
||||
<select name="incoming_bandwidth" id="incoming-bandwidth" class="form-control"
|
||||
ng-model="mydata.incomingBandwidth"
|
||||
ng-change="checkUseDedRemoteEncoder(mydata.incomingBandwidth)"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
|
||||
<div ng-show="!mydata.autoBand">
|
||||
<label for="outgoing-bandwidth">Max outgoing bandwidth:</label>
|
||||
<select name="outgoing_bandwidth" id="outgoing-bandwidth" class="form-control"
|
||||
ng-model="mydata.outgoingBandwidth"
|
||||
ng-options="item.id as item.label for item in verto.bandwidth"></select>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
47
html5/verto/verto_communicator/src/partials/preview.html
Normal file
47
html5/verto/verto_communicator/src/partials/preview.html
Normal file
@ -0,0 +1,47 @@
|
||||
<div class="centered-block-frame" id="preview">
|
||||
<div class="col-md-4 col-sm-12 col-xs-12 centered-block">
|
||||
<div class="panel panel-material-blue-900 shadow-z-2 ">
|
||||
<div class="panel-heading">
|
||||
<h3 class="panel-title text-center">Setup your camera and microphone settings</h3>
|
||||
</div>
|
||||
<div class="panel-body">
|
||||
<div class="preview-wrapper">
|
||||
<video id="videopreview" muted autoplay style="width: 100%;"></video>
|
||||
<div id="mic-meter">
|
||||
<div class="volumes">
|
||||
<div class="volume-segment"></div>
|
||||
<div class="volume-segment"></div>
|
||||
<div class="volume-segment"></div>
|
||||
<div class="volume-segment"></div>
|
||||
<div class="volume-segment"></div>
|
||||
</div>
|
||||
<i class="icon mdi-hardware-keyboard-voice"></i>
|
||||
</div>
|
||||
</div>
|
||||
<form name="form">
|
||||
<div class="form-group col-md-5 col-sm-12 col-xs-12" ng-show="true">
|
||||
<label for="settings-camera">Camera:</label>
|
||||
<select name="camera" id="settings-camera" class="form-control" ng-model="storage.data.selectedVideo"
|
||||
ng-options="item.id as item.label for item in verto.data.videoDevices" ng-change="localVideo()" >
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group col-md-5 col-sm-12 col-xs-12" ng-show="true">
|
||||
<label for="settings-microphone">Microphone:</label>
|
||||
<select name="microphone" id="settings-microphone" class="form-control" ng-model="storage.data.selectedAudio"
|
||||
ng-options="item.id as item.label for item in verto.data.audioDevices" ng-change="localVideo()">
|
||||
</select>
|
||||
</div>
|
||||
<a class="btn btn-primary btn-sm col-md-2 refresh" ng-click="refreshDeviceList()">
|
||||
<i class="icon mdi-action-autorenew"></i>
|
||||
</a>
|
||||
|
||||
<div class="form-group text-center">
|
||||
<button type="submit" class="btn btn-success" ng-click="endPreview()" title="Save">
|
||||
Save
|
||||
</button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
@ -2,23 +2,30 @@
|
||||
<div class="video-wrapper">
|
||||
<div class="video-hover-buttons" ng-show="verto.data.callState == 'active'">
|
||||
<div id="moderator-tools" ng-show="verto.data.confRole == 'moderator'">
|
||||
<button tooltips="" tooltip-title="Play" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="play()">
|
||||
<button tooltip-placement="bottom" tooltip-title="Play" uib-tooltip="Play"
|
||||
class="btn btn-material-blue-900" ng-click="play()">
|
||||
<i class="mdi-av-play-circle-outline"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Stop" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="stop()">
|
||||
<button tooltip-placement="bottom" tooltip-title="Stop" uib-tooltip="Stop"
|
||||
class="btn btn-material-blue-900" ng-click="stop()">
|
||||
<i class="mdi-av-stop"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Record" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="record()">
|
||||
<button tooltip-placement="bottom" tooltip-title="Record" uib-tooltip="Record"
|
||||
class="btn btn-material-blue-900" ng-click="record()">
|
||||
<i class="mdi-toggle-radio-button-on"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Stop Record" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="stopRecord()">
|
||||
<button tooltip-placement="bottom" tooltip-title="Stop Record" uib-tooltip="Stop Record"
|
||||
class="btn btn-material-blue-900" ng-click="stopRecord()">
|
||||
<i class="mdi-image-switch-camera"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Snapshot" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="snapshot()">
|
||||
<button tooltip-placement="bottom" tooltip-title="Snapshot" uib-tooltip="Snapshot"
|
||||
tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="snapshot()">
|
||||
<i class="mdi-image-photo-camera"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button tooltips="" tooltip-title="Video Mode" tooltip-side="bottom" tooltip-lazy="false" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<button tooltip-placement="bottom" tooltip-title="Video Mode" uib-tooltip="Video Mode"
|
||||
type="button" class="btn btn-material-blue-900 dropdown-toggle"
|
||||
data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-action-view-module"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
@ -29,22 +36,39 @@
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<br/>
|
||||
<button tooltips="" tooltip-title="(un)Mute Mic" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="muteMic(cbMuteMic)">
|
||||
<i class="" ng-class="{'mdi-av-mic': !verto.data.mutedMic, 'mdi-av-mic-off': verto.data.mutedMic}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="(un)Mute Video" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="muteVideo(cbMuteVideo)" ng-if="verto.data.canVideo">
|
||||
<i class="" ng-class="{'mdi-av-videocam': !verto.data.mutedVideo, 'mdi-av-videocam-off': verto.data.mutedVideo}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Toggle Fullscreen Mode" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="goFullscreen()">
|
||||
<i class="" ng-class="{'mdi-navigation-fullscreen': !fullscreenEnabled, 'mdi-navigation-fullscreen-exit': fullscreenEnabled}"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Screenshare" tooltip-side="bottom" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="screenshare()">
|
||||
<i class="mdi-hardware-desktop-windows"></i>
|
||||
</button>
|
||||
<button tooltips="" tooltip-title="Open/Close Chat" tooltip-side="right" tooltip-lazy="false" class="btn btn-material-blue-900" ng-click="toggleChat()" ng-show="fullscreenEnabled">
|
||||
<i class="mdi-communication-chat"></i>
|
||||
</button>
|
||||
<div class="user-tools">
|
||||
<button tooltip-placement="bottom" tooltip-title="(un)Mute Mic" uib-tooltip="(un)Mute Mic"
|
||||
class="btn btn-material-blue-900" ng-click="muteMic(cbMuteMic)">
|
||||
<i class="" ng-class="{'mdi-av-mic': !verto.data.mutedMic, 'mdi-av-mic-off': verto.data.mutedMic}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="(un)Mute Video" uib-tooltip="(un)Mute Video"
|
||||
class="btn btn-material-blue-900" ng-click="muteVideo(cbMuteVideo)" ng-if="verto.data.canVideo">
|
||||
<i class="" ng-class="{'mdi-av-videocam': !verto.data.mutedVideo, 'mdi-av-videocam-off': verto.data.mutedVideo}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Toggle Fullscreen Mode" uib-tooltip="Toggle Fullscreen Mode"
|
||||
class="btn btn-material-blue-900" ng-click="goFullscreen()">
|
||||
<i class="" ng-class="{'mdi-navigation-fullscreen': !fullscreenEnabled, 'mdi-navigation-fullscreen-exit': fullscreenEnabled}"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Screenshare" uib-tooltip="Screenshare"
|
||||
class="btn btn-material-blue-900" ng-click="screenshare()">
|
||||
<i class="mdi-hardware-desktop-windows"></i>
|
||||
</button>
|
||||
<button tooltip-placement="bottom" tooltip-title="Open/Close Chat" uib-tooltip="Open/Close Chat"
|
||||
class="btn btn-material-blue-900" ng-click="toggleChat()" ng-show="fullscreenEnabled">
|
||||
<i class="mdi-communication-chat"></i>
|
||||
</button>
|
||||
<div class="btn-group">
|
||||
<button tooltip-placement="bottom" tooltip-title="Speaker" uib-tooltips="Speaker" type="button" class="btn btn-material-blue-900 dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false">
|
||||
<i class="mdi-hardware-headset"></i>
|
||||
<span class="caret"></span>
|
||||
</button>
|
||||
<ul class="dropdown-menu">
|
||||
<li ng-repeat="speaker in verto.data.speakerDevices">
|
||||
<a ng-click="confChangeSpeaker(speaker.id)">{{ speaker.label }}</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="video-tag-wrapper" id="video-tag-wrapper" ng-dblclick="goFullscreen()" show-controls>
|
||||
<video-tag ng-class="{'invisible': (verto.data.callState != 'active')}"></video-tag>
|
||||
@ -69,4 +93,3 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
@ -4,7 +4,7 @@
|
||||
.module('storageService')
|
||||
.service('splashscreen', ['$rootScope', '$q', 'storage', 'config', 'verto',
|
||||
function($rootScope, $q, storage, config, verto) {
|
||||
|
||||
|
||||
var checkBrowser = function() {
|
||||
return $q(function(resolve, reject) {
|
||||
var activity = 'browser-upgrade';
|
||||
@ -22,10 +22,10 @@
|
||||
if (!navigator.getUserMedia) {
|
||||
result['status'] = 'error';
|
||||
result['message'] = 'Error: browser doesn\'t support WebRTC.';
|
||||
reject(result);
|
||||
reject(result);
|
||||
}
|
||||
|
||||
resolve(result);
|
||||
resolve(result);
|
||||
|
||||
});
|
||||
};
|
||||
@ -48,7 +48,7 @@
|
||||
reject(result);
|
||||
}
|
||||
verto.data.mediaPerm = true;
|
||||
resolve(result);
|
||||
resolve(result);
|
||||
});
|
||||
});
|
||||
};
|
||||
@ -62,7 +62,7 @@
|
||||
'activity': activity,
|
||||
'message': 'Refresh Media Devices.'
|
||||
};
|
||||
|
||||
|
||||
verto.refreshDevices(function(status) {
|
||||
verto.refreshDevicesCallback(function() {
|
||||
resolve(result);
|
||||
@ -72,6 +72,28 @@
|
||||
});
|
||||
};
|
||||
|
||||
var checkConnectionSpeed = function() {
|
||||
return $q(function(resolve, reject) {
|
||||
var activity = 'check-connection-speed';
|
||||
var result = {
|
||||
'status': 'success',
|
||||
'soft': true,
|
||||
'activity': activity,
|
||||
'message': 'Check Connection Speed.'
|
||||
};
|
||||
|
||||
if (storage.data.autoBand && verto.data.instance) {
|
||||
verto.testSpeed(cb);
|
||||
} else {
|
||||
resolve(result);
|
||||
}
|
||||
|
||||
function cb(data) {
|
||||
resolve(result);
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
var provisionConfig = function() {
|
||||
return $q(function(resolve, reject) {
|
||||
var activity = 'provision-config';
|
||||
@ -100,7 +122,7 @@
|
||||
});
|
||||
|
||||
result['promise'] = configPromise;
|
||||
|
||||
|
||||
resolve(result);
|
||||
});
|
||||
};
|
||||
@ -136,13 +158,13 @@
|
||||
verto.data.connecting = false;
|
||||
resolve(result);
|
||||
});
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
if(storage.data.ui_connected && storage.data.ws_connected) {
|
||||
checkUserStored();
|
||||
checkUserStored();
|
||||
} else {
|
||||
resolve(result);
|
||||
resolve(result);
|
||||
};
|
||||
});
|
||||
};
|
||||
@ -152,7 +174,8 @@
|
||||
checkMediaPerm,
|
||||
refreshMediaDevices,
|
||||
provisionConfig,
|
||||
checkLogin
|
||||
checkLogin,
|
||||
checkConnectionSpeed
|
||||
];
|
||||
|
||||
var progress_message = [
|
||||
@ -160,12 +183,13 @@
|
||||
'Checking media permissions',
|
||||
'Refresh Media Devices.',
|
||||
'Provisioning configuration.',
|
||||
'Checking login.'
|
||||
'Checking login.',
|
||||
'Check Connection Speed.'
|
||||
];
|
||||
|
||||
|
||||
var getProgressMessage = function(current_progress) {
|
||||
if(progress_message[current_progress] != undefined) {
|
||||
return progress_message[current_progress];
|
||||
return progress_message[current_progress];
|
||||
} else {
|
||||
return 'Please wait...';
|
||||
}
|
||||
@ -176,7 +200,7 @@
|
||||
|
||||
var calculateProgress = function(index) {
|
||||
var _progress;
|
||||
|
||||
|
||||
_progress = index + 1;
|
||||
progress_percentage = (_progress / progress.length) * 100;
|
||||
return progress_percentage;
|
||||
@ -186,12 +210,12 @@
|
||||
var fn, fn_return, status, interrupt, activity, soft, message, promise;
|
||||
interrupt = false;
|
||||
current_progress++;
|
||||
|
||||
|
||||
if(current_progress >= progress.length) {
|
||||
$rootScope.$emit('progress.complete', current_progress);
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
fn = progress[current_progress];
|
||||
fn_return = fn();
|
||||
|
||||
@ -221,7 +245,7 @@
|
||||
emitNextProgress(fn_return);
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
};
|
||||
|
||||
return {
|
||||
@ -232,4 +256,3 @@
|
||||
};
|
||||
|
||||
}]);
|
||||
|
||||
|
@ -21,9 +21,11 @@
|
||||
userStatus: 'disconnected',
|
||||
mutedVideo: false,
|
||||
mutedMic: false,
|
||||
preview: true,
|
||||
selectedVideo: null,
|
||||
selectedAudio: null,
|
||||
selectedShare: null,
|
||||
selectedSpeaker: null,
|
||||
useStereo: true,
|
||||
useSTUN: true,
|
||||
useDedenc: false,
|
||||
@ -34,7 +36,9 @@
|
||||
askRecoverCall: false,
|
||||
googNoiseSuppression: true,
|
||||
googHighpassFilter: true,
|
||||
googEchoCancellation: true
|
||||
googEchoCancellation: true,
|
||||
autoBand: true,
|
||||
testSpeedJoin: true
|
||||
};
|
||||
|
||||
data.$default(defaultSettings);
|
||||
|
@ -15,6 +15,7 @@
|
||||
'cgPrompt',
|
||||
'720kb.tooltips',
|
||||
'ui.gravatar',
|
||||
'ui.bootstrap',
|
||||
'directive.g+signin',
|
||||
]);
|
||||
|
||||
@ -41,6 +42,11 @@
|
||||
templateUrl: 'partials/incall.html',
|
||||
controller: 'InCallController'
|
||||
}).
|
||||
when('/preview', {
|
||||
title: 'Preview Video',
|
||||
templateUrl: 'partials/preview.html',
|
||||
controller: 'PreviewController'
|
||||
}).
|
||||
when('/browser-upgrade', {
|
||||
title: '',
|
||||
templateUrl: 'partials/browser_upgrade.html',
|
||||
|
@ -120,6 +120,8 @@
|
||||
if (parseInt(member.id) == parseInt(verto.data.conferenceMemberID)) {
|
||||
verto.data.mutedMic = member.status.audio.muted;
|
||||
verto.data.mutedVideo = member.status.video.muted;
|
||||
verto.data.call.setMute(member.status.audio.muted ? "off" : "on");
|
||||
verto.data.call.setVideoMute(member.status.video.muted ? "off" : "on");
|
||||
}
|
||||
angular.extend($scope.members[memberIdx], member);
|
||||
});
|
||||
|
@ -7,9 +7,9 @@
|
||||
'$http', '$location', 'toastr', 'verto', 'storage', 'CallHistory', 'eventQueue',
|
||||
function($rootScope, $scope, $http, $location, toastr, verto, storage, CallHistory, eventQueue) {
|
||||
console.debug('Executing DialPadController.');
|
||||
|
||||
|
||||
eventQueue.process();
|
||||
|
||||
|
||||
$scope.call_history = CallHistory.all();
|
||||
$scope.history_control = CallHistory.all_control();
|
||||
$scope.has_history = Object.keys($scope.call_history).length;
|
||||
@ -55,6 +55,10 @@
|
||||
$rootScope.dialpadNumber = number;
|
||||
};
|
||||
|
||||
$scope.preview = function() {
|
||||
$location.path('/preview');
|
||||
};
|
||||
|
||||
$rootScope.transfer = function() {
|
||||
if (!$rootScope.dialpadNumber) {
|
||||
return false;
|
||||
@ -93,8 +97,17 @@
|
||||
/**
|
||||
* Call to the number in the $rootScope.dialpadNumber.
|
||||
*/
|
||||
$scope.loading = false;
|
||||
$rootScope.call = function(extension) {
|
||||
return call(extension);
|
||||
if (!storage.data.testSpeedJoin || !$rootScope.dialpadNumber) {
|
||||
return call(extension);
|
||||
}
|
||||
$scope.loading = true;
|
||||
|
||||
verto.testSpeed(function() {
|
||||
$scope.loading = false;
|
||||
call(extension);
|
||||
});
|
||||
}
|
||||
}
|
||||
]);
|
||||
|
@ -5,7 +5,7 @@
|
||||
.module('vertoControllers')
|
||||
.controller('InCallController', ['$rootScope', '$scope',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen',
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toatr,
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toastr,
|
||||
verto, storage, prompt, Fullscreen) {
|
||||
|
||||
console.debug('Executing InCallController.');
|
||||
@ -19,7 +19,7 @@
|
||||
if (storage.data.videoCall) {
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
}
|
||||
|
||||
|
||||
$rootScope.$on('call.conference', function(event, data) {
|
||||
$timeout(function() {
|
||||
if($scope.chatStatus) {
|
||||
@ -75,9 +75,36 @@
|
||||
verto.data.conf.setVideoLayout(layout);
|
||||
};
|
||||
|
||||
$scope.confChangeSpeaker = function(speakerId) {
|
||||
storage.data.selectedSpeaker = speakerId;
|
||||
$rootScope.$emit('changedSpeaker', speakerId);
|
||||
};
|
||||
|
||||
$scope.screenshare = function() {
|
||||
if(verto.data.shareCall) {
|
||||
verto.screenshareHangup();
|
||||
return false;
|
||||
}
|
||||
verto.screenshare(storage.data.called_number);
|
||||
};
|
||||
|
||||
$scope.muteMic = verto.muteMic;
|
||||
$scope.muteVideo = verto.muteVideo;
|
||||
|
||||
$rootScope.$on('ScreenShareExtensionStatus', function(event, error) {
|
||||
var pluginUrl = 'https://chrome.google.com/webstore/detail/screen-capturing/ajhifddimkapgcifgcodmmfdlknahffk';
|
||||
switch(error) {
|
||||
case 'permission-denied':
|
||||
toastr.info('Please allow the plugin in order to use Screen Share', 'Error'); break;
|
||||
case 'not-installed':
|
||||
toastr.warning('Please <a target="_blank" class="install" href="'+ pluginUrl +'">install</a> the plugin in order to use Screen Share', 'Warning', { allowHtml: true }); break;
|
||||
case 'installed-disabled':
|
||||
toastr.info('Please enable the plugin in order to use Screen Share', 'Error'); break;
|
||||
// case 'not-chrome'
|
||||
// toastr.info('Chrome', 'Error');
|
||||
}
|
||||
});
|
||||
|
||||
$timeout(function() {
|
||||
console.log('broadcast time-start incall');
|
||||
$scope.$broadcast('timer-start');
|
||||
|
@ -24,16 +24,24 @@
|
||||
* @type {string}
|
||||
*/
|
||||
$rootScope.dialpadNumber = '';
|
||||
|
||||
|
||||
// If verto is not connected, redirects to login page.
|
||||
if (!verto.data.connected) {
|
||||
console.debug('MainController: WebSocket not connected. Redirecting to login.');
|
||||
$location.path('/');
|
||||
}
|
||||
|
||||
|
||||
$rootScope.$on('config.http.success', function(ev) {
|
||||
$scope.login(false);
|
||||
});
|
||||
|
||||
$rootScope.$on('changedSpeaker', function(event, speakerId) {
|
||||
// This should provide feedback
|
||||
//setAudioPlaybackDevice(<id>[,<callback>[,<callback arg>]]);
|
||||
// if callback is set it will be called as callback(<bool success/fail>, <device name>, <arg if you supplied it>)
|
||||
verto.data.call.setAudioPlaybackDevice(speakerId);
|
||||
});
|
||||
|
||||
/**
|
||||
* Login the user to verto server and
|
||||
* redirects him to dialpad page.
|
||||
@ -52,13 +60,19 @@
|
||||
storage.data.email = verto.data.email;
|
||||
storage.data.login = verto.data.login;
|
||||
storage.data.password = verto.data.password;
|
||||
if (redirect) {
|
||||
if (storage.data.autoBand) {
|
||||
verto.testSpeed();
|
||||
}
|
||||
|
||||
if (redirect && storage.data.preview) {
|
||||
$location.path('/preview');
|
||||
} else if (redirect) {
|
||||
$location.path('/dialpad');
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
|
||||
verto.data.connecting = true;
|
||||
verto.connect(connectCallback);
|
||||
};
|
||||
@ -135,7 +149,7 @@
|
||||
templateUrl: templateUrl,
|
||||
controller: controller,
|
||||
};
|
||||
|
||||
|
||||
angular.extend(options, _options);
|
||||
|
||||
var modalInstance = $modal.open(options);
|
||||
@ -154,7 +168,7 @@
|
||||
jQuery.material.init();
|
||||
}
|
||||
);
|
||||
|
||||
|
||||
return modalInstance;
|
||||
};
|
||||
|
||||
@ -177,6 +191,9 @@
|
||||
};
|
||||
|
||||
function onWSLogin(ev, data) {
|
||||
if(storage.data.autoBand) {
|
||||
verto.testSpeed();
|
||||
}
|
||||
if(!ws_modalInstance) {
|
||||
return;
|
||||
};
|
||||
@ -454,14 +471,6 @@
|
||||
$scope.incomingCall = false;
|
||||
};
|
||||
|
||||
$scope.screenshare = function() {
|
||||
if (verto.data.shareCall) {
|
||||
verto.screenshareHangup();
|
||||
return false;
|
||||
}
|
||||
verto.screenshare(storage.data.called_number);
|
||||
};
|
||||
|
||||
$scope.play = function() {
|
||||
var file = $scope.promptInput('Please, enter filename', '', 'File',
|
||||
function(file) {
|
||||
|
@ -4,10 +4,43 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('MenuController', ['$scope', '$http', '$location',
|
||||
'verto', 'storage',
|
||||
function($scope, $http, $location, verto, storage) {
|
||||
'verto', 'storage', '$rootScope',
|
||||
function($scope, $http, $location, verto, storage, $rootScope) {
|
||||
console.debug('Executing MenuController.');
|
||||
}
|
||||
$scope.storage = storage;
|
||||
|
||||
$rootScope.$on('testSpeed', function(e, data) {
|
||||
var vidQual = storage.data.vidQual;
|
||||
var bwp = 4;
|
||||
|
||||
$scope.bandDown = data.downKPS;
|
||||
$scope.bandUp = data.upKPS;
|
||||
|
||||
if (data.downKPS < 2000) {
|
||||
bwp--;
|
||||
}
|
||||
|
||||
if (data.upKPS < 2000) {
|
||||
bwp--;
|
||||
}
|
||||
|
||||
$scope.iconClass = 'mdi-device-signal-wifi-4-bar green';
|
||||
|
||||
if (bwp < 4) {
|
||||
$scope.iconClass = 'mdi-device-signal-wifi-3-bar yellow';
|
||||
} else if (bwp < 2) {
|
||||
$scope.iconClass = 'mdi-device-signal-wifi-1-bar red';
|
||||
}
|
||||
|
||||
verto.videoQuality.forEach(function(vid) {
|
||||
if (vid.id == vidQual){
|
||||
$scope.vidRes = vid.label;
|
||||
}
|
||||
});
|
||||
|
||||
$scope.$apply();
|
||||
});
|
||||
}
|
||||
]);
|
||||
|
||||
})();
|
||||
})();
|
||||
|
@ -4,8 +4,8 @@
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('ModalSettingsController', ['$scope', '$http',
|
||||
'$location', '$modalInstance', 'storage', 'verto',
|
||||
function($scope, $http, $location, $modalInstance, storage, verto) {
|
||||
'$location', '$modalInstance', '$rootScope', 'storage', 'verto',
|
||||
function($scope, $http, $location, $modalInstance, $rootScope, storage, verto) {
|
||||
console.debug('Executing ModalSettingsController.');
|
||||
|
||||
$scope.storage = storage;
|
||||
@ -13,8 +13,15 @@
|
||||
$scope.mydata = angular.copy(storage.data);
|
||||
|
||||
$scope.ok = function() {
|
||||
if ($scope.mydata.selectedSpeaker != storage.data.selectedSpeaker) {
|
||||
$rootScope.$emit('changedSpeaker', $scope.mydata.selectedSpeaker);
|
||||
}
|
||||
storage.changeData($scope.mydata);
|
||||
verto.data.instance.iceServers(storage.data.useSTUN);
|
||||
|
||||
if (storage.data.autoBand) {
|
||||
$scope.testSpeed();
|
||||
}
|
||||
$modalInstance.close('Ok.');
|
||||
};
|
||||
|
||||
@ -26,6 +33,16 @@
|
||||
return verto.refreshDevices();
|
||||
};
|
||||
|
||||
$scope.testSpeed = function() {
|
||||
return verto.testSpeed(cb);
|
||||
|
||||
function cb(data) {
|
||||
$scope.mydata.vidQual = storage.data.vidQual;
|
||||
$scope.speedMsg = 'Up: ' + data.upKPS + ' Down: ' + data.downKPS;
|
||||
$scope.$apply();
|
||||
}
|
||||
};
|
||||
|
||||
$scope.resetSettings = function() {
|
||||
if (confirm('Factory Reset Settings?')) {
|
||||
storage.factoryReset();
|
||||
@ -35,11 +52,22 @@
|
||||
};
|
||||
};
|
||||
|
||||
$scope.checkUseDedRemoteEncoder = function(option) {
|
||||
if ($scope.mydata.incomingBandwidth != 'default' || $scope.mydata.outgoingBandwidth != 'default') {
|
||||
$scope.mydata.useDedenc = true;
|
||||
$scope.checkAutoBand = function(option) {
|
||||
$scope.mydata.useDedenc = false;
|
||||
if (!option) {
|
||||
$scope.mydata.outgoingBandwidth = 'default';
|
||||
$scope.mydata.incomingBandwidth = 'default';
|
||||
$scope.mydata.vidQual = 'hd';
|
||||
} else {
|
||||
$scope.mydata.testSpeedJoin = true;
|
||||
}
|
||||
};
|
||||
|
||||
$scope.checkUseDedRemoteEncoder = function(option) {
|
||||
if (['0', 'default', '5120'].indexOf(option) != -1) {
|
||||
$scope.mydata.useDedenc = false;
|
||||
} else {
|
||||
$scope.mydata.useDedenc = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
122
html5/verto/verto_communicator/src/vertoControllers/controllers/PreviewController.js
Normal file
122
html5/verto/verto_communicator/src/vertoControllers/controllers/PreviewController.js
Normal file
@ -0,0 +1,122 @@
|
||||
(function() {
|
||||
'use strict';
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('PreviewController', ['$rootScope', '$scope',
|
||||
'$http', '$location', '$modal', '$timeout', 'toastr', 'verto', 'storage', 'prompt', 'Fullscreen',
|
||||
function($rootScope, $scope, $http, $location, $modal, $timeout, toastr,
|
||||
verto, storage, prompt, Fullscreen) {
|
||||
|
||||
$scope.storage = storage;
|
||||
console.debug('Executing PreviewController.');
|
||||
var localVideo = document.getElementById('videopreview');
|
||||
var volumes = document.querySelector('#mic-meter .volumes').children;
|
||||
|
||||
$scope.localVideo = function() {
|
||||
var constraints = {
|
||||
mirrored: true,
|
||||
audio: {
|
||||
optional: [{ sourceId: storage.data.selectedAudio }]
|
||||
}
|
||||
};
|
||||
|
||||
if (storage.data.selectedVideo !== 'none') {
|
||||
constraints.video = {
|
||||
optional: [{ sourceId: storage.data.selectedVideo }]
|
||||
};
|
||||
}
|
||||
|
||||
navigator.getUserMedia(constraints, handleMedia, function(err, data) {
|
||||
|
||||
});
|
||||
};
|
||||
|
||||
var audioContext = new AudioContext();
|
||||
var mediaStreamSource = null;
|
||||
var meter;
|
||||
var streamObj = {};
|
||||
|
||||
function stopMedia(stream) {
|
||||
if (typeof stream == 'function') {
|
||||
stream.stop();
|
||||
} else {
|
||||
if (stream.active) {
|
||||
var tracks = stream.getTracks();
|
||||
tracks.forEach(function(track, index) {
|
||||
track.stop();
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
function handleMedia(stream) {
|
||||
if (streamObj) {
|
||||
stopMedia(streamObj);
|
||||
}
|
||||
|
||||
streamObj = stream;
|
||||
localVideo.src = window.URL.createObjectURL(stream);
|
||||
|
||||
mediaStreamSource = audioContext.createMediaStreamSource(stream);
|
||||
meter = createAudioMeter(audioContext);
|
||||
mediaStreamSource.connect(meter);
|
||||
|
||||
renderMic();
|
||||
}
|
||||
|
||||
function renderMic() {
|
||||
// meter.volume;
|
||||
var n = Math.round(meter.volume * 25);
|
||||
for(var i = volumes.length -1, j = 0; i >= 0; i--, j++) {
|
||||
var el = angular.element(volumes[j]);
|
||||
if (i >= n) el.removeClass('active');
|
||||
else el.addClass('active');
|
||||
}
|
||||
|
||||
if(!verto.data.call) {
|
||||
window.requestAnimationFrame(renderMic);
|
||||
}
|
||||
}
|
||||
/**
|
||||
* TODO: useless?
|
||||
*/
|
||||
|
||||
$scope.refreshDeviceList = function() {
|
||||
return verto.refreshDevices();
|
||||
};
|
||||
|
||||
$scope.videoCall = function() {
|
||||
prompt({
|
||||
title: 'Would you like to activate video for this call?',
|
||||
message: 'Video will be active during the next calls.'
|
||||
}).then(function() {
|
||||
storage.data.videoCall = true;
|
||||
$scope.callTemplate = 'partials/video_call.html';
|
||||
});
|
||||
};
|
||||
|
||||
$scope.cbMuteVideo = function(event, data) {
|
||||
storage.data.mutedVideo = !storage.data.mutedVideo;
|
||||
}
|
||||
|
||||
$scope.cbMuteMic = function(event, data) {
|
||||
storage.data.mutedMic = !storage.data.mutedMic;
|
||||
}
|
||||
|
||||
$scope.confChangeVideoLayout = function(layout) {
|
||||
verto.data.conf.setVideoLayout(layout);
|
||||
};
|
||||
|
||||
$scope.endPreview = function() {
|
||||
localVideo.src = null;
|
||||
meter.shutdown();
|
||||
meter.onaudioprocess = null;
|
||||
stopMedia(streamObj);
|
||||
$location.path('/dialpad');
|
||||
storage.data.preview = false;
|
||||
};
|
||||
|
||||
$scope.localVideo();
|
||||
}
|
||||
]);
|
||||
})();
|
@ -3,10 +3,10 @@
|
||||
|
||||
angular
|
||||
.module('vertoControllers')
|
||||
.controller('SplashScreenController', ['$scope', '$rootScope', '$location', '$timeout', 'splashscreen', 'prompt', 'verto',
|
||||
function($scope, $rootScope, $location, $timeout, splashscreen, prompt, verto) {
|
||||
.controller('SplashScreenController', ['$scope', '$rootScope', '$location', '$timeout', 'storage', 'splashscreen', 'prompt', 'verto',
|
||||
function($scope, $rootScope, $location, $timeout, storage, splashscreen, prompt, verto) {
|
||||
console.debug('Executing SplashScreenController.');
|
||||
|
||||
|
||||
$scope.progress_percentage = splashscreen.progress_percentage;
|
||||
$scope.message = '';
|
||||
$scope.interrupt_next = false;
|
||||
@ -18,26 +18,26 @@
|
||||
link = activity;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
$location.path(link);
|
||||
}
|
||||
|
||||
var checkProgressState = function(current_progress, status, promise, activity, soft, interrupt, message) {
|
||||
$scope.progress_percentage = splashscreen.calculate(current_progress);
|
||||
$scope.progress_percentage = splashscreen.calculate(current_progress);
|
||||
$scope.message = message;
|
||||
|
||||
if(interrupt && status == 'error') {
|
||||
$scope.errors.push(message);
|
||||
if(!soft) {
|
||||
redirectTo('', activity);
|
||||
redirectTo('', activity);
|
||||
return;
|
||||
} else {
|
||||
message = message + '. Continue?';
|
||||
message = message + '. Continue?';
|
||||
};
|
||||
|
||||
if(!confirm(message)) {
|
||||
$scope.interrupt_next = true;
|
||||
};
|
||||
$scope.interrupt_next = true;
|
||||
};
|
||||
};
|
||||
|
||||
if($scope.interrupt_next) {
|
||||
@ -48,7 +48,7 @@
|
||||
|
||||
return true;
|
||||
};
|
||||
|
||||
|
||||
$rootScope.$on('progress.next', function(ev, current_progress, status, promise, activity, soft, interrupt, message) {
|
||||
$timeout(function() {
|
||||
if(promise) {
|
||||
@ -62,11 +62,11 @@
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
if(!checkProgressState(current_progress, status, promise, activity, soft, interrupt, message)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
splashscreen.next();
|
||||
}, 400);
|
||||
});
|
||||
@ -74,7 +74,12 @@
|
||||
$rootScope.$on('progress.complete', function(ev, current_progress) {
|
||||
$scope.message = 'Complete';
|
||||
if(verto.data.connected) {
|
||||
redirectTo('/dialpad');
|
||||
if (storage.data.preview) {
|
||||
$location.path('/preview');
|
||||
}
|
||||
else {
|
||||
$location.path('/dialpad');
|
||||
}
|
||||
} else {
|
||||
redirectTo('/login');
|
||||
$location.path('/login');
|
||||
|
@ -40,7 +40,7 @@ vertoService.service('config', ['$rootScope', '$http', '$location', 'storage', '
|
||||
verto.data.googlelogin = data.googlelogin;
|
||||
verto.data.googleclientid = data.googleclientid;
|
||||
}
|
||||
|
||||
|
||||
angular.extend(verto.data, data);
|
||||
|
||||
/**
|
||||
@ -62,13 +62,13 @@ vertoService.service('config', ['$rootScope', '$http', '$location', 'storage', '
|
||||
console.debug("auto login per config.json");
|
||||
verto.data.autologin_done = true;
|
||||
}
|
||||
|
||||
|
||||
if(verto.data.autologin && storage.data.name.length && storage.data.email.length && storage.data.login.length && storage.data.password.length) {
|
||||
$rootScope.$emit('config.http.success', data);
|
||||
$rootScope.$emit('config.http.success', data);
|
||||
};
|
||||
return response;
|
||||
}, function(response) {
|
||||
$rootScope.$emit('config.http.error', response);
|
||||
$rootScope.$emit('config.http.error', response);
|
||||
return response;
|
||||
});
|
||||
|
||||
@ -79,4 +79,3 @@ vertoService.service('config', ['$rootScope', '$http', '$location', 'storage', '
|
||||
'configure': configure
|
||||
};
|
||||
}]);
|
||||
|
||||
|
@ -76,6 +76,12 @@ var bandwidth = [{
|
||||
}, {
|
||||
id: '2048',
|
||||
label: '2mb'
|
||||
}, {
|
||||
id: '3196',
|
||||
label: '3mb'
|
||||
}, {
|
||||
id: '4192',
|
||||
label: '4mb'
|
||||
}, {
|
||||
id: '5120',
|
||||
label: '5mb'
|
||||
@ -169,7 +175,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
var height = res[1];
|
||||
|
||||
if(resolution.width == width && resolution.height == height) {
|
||||
videoQuality.push(resolution);
|
||||
videoQuality.push(resolution);
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -200,14 +206,15 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
|
||||
refreshDevicesCallback : function refreshDevicesCallback(callback) {
|
||||
data.videoDevices = [{
|
||||
id: 'none',
|
||||
label: 'No Camera'
|
||||
}];
|
||||
id: 'none',
|
||||
label: 'No Camera'
|
||||
}];
|
||||
data.shareDevices = [{
|
||||
id: 'screen',
|
||||
label: 'Screen'
|
||||
}];
|
||||
data.audioDevices = [];
|
||||
data.speakerDevices = [];
|
||||
|
||||
if(!storage.data.selectedShare) {
|
||||
storage.data.selectedShare = data.shareDevices[0]['id'];
|
||||
@ -265,6 +272,26 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
label: device.label || device.id
|
||||
});
|
||||
}
|
||||
|
||||
for (var i in jQuery.verto.audioOutDevices) {
|
||||
var device = jQuery.verto.audioOutDevices[i];
|
||||
// Selecting the first source.
|
||||
if (i == 0 && !storage.data.selectedSpeaker) {
|
||||
storage.data.selectedSpeaker = device.id;
|
||||
}
|
||||
|
||||
if (!device.label) {
|
||||
data.speakerDevices.push({
|
||||
id: 'Speaker ' + i,
|
||||
label: 'Speaker ' + i
|
||||
});
|
||||
continue;
|
||||
}
|
||||
data.speakerDevices.push({
|
||||
id: device.id,
|
||||
label: device.label || device.id
|
||||
});
|
||||
}
|
||||
console.debug('Devices were refreshed, checking that we have cameras.');
|
||||
|
||||
// This means that we cannot use video!
|
||||
@ -465,13 +492,17 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
if (params.pvtData) {
|
||||
switch (params.pvtData.action) {
|
||||
case "conference-liveArray-join":
|
||||
console.log("conference-liveArray-join");
|
||||
stopConference();
|
||||
startConference(v, dialog, params.pvtData);
|
||||
if (!params.pvtData.screenShare && !params.pvtData.videoOnly) {
|
||||
console.log("conference-liveArray-join");
|
||||
stopConference();
|
||||
startConference(v, dialog, params.pvtData);
|
||||
}
|
||||
break;
|
||||
case "conference-liveArray-part":
|
||||
console.log("conference-liveArray-part");
|
||||
stopConference();
|
||||
if (!params.pvtData.screenShare && !params.pvtData.videoOnly) {
|
||||
console.log("conference-liveArray-part");
|
||||
stopConference();
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -556,10 +587,10 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
// Checking if we have a failed connection attempt before
|
||||
// connecting again.
|
||||
if (data.instance && !data.instance.rpcClient.socketReady()) {
|
||||
clearTimeout(data.instance.rpcClient.to);
|
||||
data.instance.logout();
|
||||
data.instance.login();
|
||||
return;
|
||||
clearTimeout(data.instance.rpcClient.to);
|
||||
data.instance.logout();
|
||||
data.instance.login();
|
||||
return;
|
||||
};
|
||||
data.instance = new jQuery.verto({
|
||||
login: data.login + '@' + data.hostname,
|
||||
@ -583,22 +614,23 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
jQuery.verto.unloadJobs.push(function() {
|
||||
that.reloaded = true;
|
||||
});
|
||||
data.instance.deviceParams({
|
||||
useCamera: storage.data.selectedVideo,
|
||||
useMic: storage.data.selectedAudio,
|
||||
onResCheck: that.refreshVideoResolution
|
||||
});
|
||||
data.instance.deviceParams({
|
||||
useCamera: storage.data.selectedVideo,
|
||||
useSpeak: storage.data.selectedSpeaker,
|
||||
useMic: storage.data.selectedAudio,
|
||||
onResCheck: that.refreshVideoResolution
|
||||
});
|
||||
}
|
||||
|
||||
if (data.mediaPerm) {
|
||||
ourBootstrap();
|
||||
} else {
|
||||
$.FSRTC.checkPerms(ourBootstrap, true, true);
|
||||
$.FSRTC.checkPerms(ourBootstrap, true, true);
|
||||
}
|
||||
},
|
||||
|
||||
mediaPerm: function(callback) {
|
||||
$.FSRTC.checkPerms(callback, true, true);
|
||||
$.FSRTC.checkPerms(callback, true, true);
|
||||
},
|
||||
|
||||
/**
|
||||
@ -654,6 +686,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
useVideo: storage.data.useVideo,
|
||||
useStereo: storage.data.useStereo,
|
||||
useCamera: storage.data.selectedVideo,
|
||||
useSpeak: storage.data.selectedSpeaker,
|
||||
useMic: storage.data.selectedAudio,
|
||||
dedEnc: storage.data.useDedenc,
|
||||
mirrorInput: storage.data.mirrorInput,
|
||||
@ -681,6 +714,12 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
var that = this;
|
||||
|
||||
getScreenId(function(error, sourceId, screen_constraints) {
|
||||
|
||||
if(error) {
|
||||
$rootScope.$emit('ScreenShareExtensionStatus', error);
|
||||
return;
|
||||
}
|
||||
|
||||
var call = data.instance.newCall({
|
||||
destination_number: destination + '-screen',
|
||||
caller_id_name: data.name + ' (Screen)',
|
||||
@ -698,6 +737,24 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
}
|
||||
});
|
||||
|
||||
// Override onStream callback in $.FSRTC instance
|
||||
call.rtc.options.callbacks.onStream = function(rtc, stream) {
|
||||
if(stream) {
|
||||
var StreamTrack = stream.getVideoTracks()[0];
|
||||
StreamTrack.addEventListener('ended', stopSharing);
|
||||
// (stream.getVideoTracks()[0]).onended = stopSharing;
|
||||
}
|
||||
|
||||
console.log("screenshare started");
|
||||
|
||||
function stopSharing() {
|
||||
if(that.data.shareCall) {
|
||||
that.screenshareHangup();
|
||||
console.log("screenshare ended");
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
data.shareCall = call;
|
||||
|
||||
console.log('shareCall', data);
|
||||
@ -773,6 +830,39 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
* Do speed test.
|
||||
*
|
||||
* @param callback
|
||||
*/
|
||||
testSpeed: function(cb) {
|
||||
|
||||
data.instance.rpcClient.speedTest(1024 * 256, function(e, data) {
|
||||
var upBand = Math.ceil(data.upKPS * .75),
|
||||
downBand = Math.ceil(data.downKPS * .75);
|
||||
|
||||
|
||||
if (storage.data.autoBand) {
|
||||
storage.data.incomingBandwidth = downBand;
|
||||
storage.data.outgoingBandwidth = upBand;
|
||||
storage.data.useDedenc = false;
|
||||
storage.data.vidQual = 'hd';
|
||||
|
||||
if (upBand < 512) {
|
||||
storage.data.vidQual = 'qvga';
|
||||
}
|
||||
else if (upBand < 1024) {
|
||||
storage.data.vidQual = 'vga';
|
||||
}
|
||||
}
|
||||
|
||||
if(cb) {
|
||||
cb(data);
|
||||
}
|
||||
|
||||
$rootScope.$emit('testSpeed', data);
|
||||
});
|
||||
},
|
||||
/**
|
||||
* Mute the microphone for the current call.
|
||||
*
|
||||
|
@ -91,7 +91,7 @@ div#preload { display: none; }
|
||||
<body>
|
||||
<div data-role="page" id="page-login" align="center">
|
||||
<div data-role="header" class="page-header">
|
||||
FreeSWITCH Verto™ Video Transcoding Demo
|
||||
FreeSWITCH Verto™ Video Transcoding Demo
|
||||
</div>
|
||||
|
||||
</div>
|
||||
@ -108,6 +108,18 @@ div#preload { display: none; }
|
||||
</div>
|
||||
|
||||
|
||||
<div data-role="page" id="page-bwtest" align="center">
|
||||
<div data-role="header" class="page-header">
|
||||
FreeSWITCH Verto™ Testing Network Connection
|
||||
</div>
|
||||
|
||||
<h1>Testing Network Connection</h1>
|
||||
<img src="images/speed.gif"/>
|
||||
|
||||
|
||||
</div>
|
||||
|
||||
|
||||
<div data-role="page" id="page-incall" align="center">
|
||||
<div data-role="header" id="calltitle" class="pageheader">
|
||||
Verto™ IN CALL
|
||||
@ -135,6 +147,7 @@ div#preload { display: none; }
|
||||
<button data-inline="true" id="hupbtn">End Call</button>
|
||||
<button data-inline="true" id="mutebtn">Toggle Audio Mute</button>
|
||||
<button data-inline="true" id="localmutebtn">Toggle Local Audio Mute</button>
|
||||
<button data-inline="true" id="localvidmutebtn">Toggle Local Video Mute</button>
|
||||
<!-- <button data-inline="true" class="startxferbtn">Transfer</button>-->
|
||||
<span class="sharediv">
|
||||
<button data-inline="true" id="sharebtn">Share</button>
|
||||
@ -248,7 +261,7 @@ div#preload { display: none; }
|
||||
|
||||
<div data-role="page" id="page-main" align="center">
|
||||
<div data-role="header" class="pageheader">
|
||||
FreeSWITCH Verto™ Video Transcoding Demo
|
||||
FreeSWITCH Verto™ Video Transcoding Demo (<span id="bwinfo">*checking*</span>)
|
||||
</div>
|
||||
<br>
|
||||
<center> <table width="1024" border="0">
|
||||
@ -347,9 +360,9 @@ if ($('#devices').is(':visible')) {
|
||||
}
|
||||
|
||||
</script>
|
||||
|
||||
<!--<button data-inline="true" id="showdemo" onclick="toggle_demo();">View Demo Extensions</button>-->
|
||||
<button data-inline="true" id="showdevices" onclick="toggle_device();">View Device Settings</button>
|
||||
<button data-inline="true"id="speedbtn">Check Speed</button>
|
||||
<button data-inline="true"id="logoutbtn">Log Out</button>
|
||||
|
||||
<div id="devices" style="border-style:outset;border-width:2px">
|
||||
|
41
html5/verto/video_demo/js/verto-min.js
vendored
41
html5/verto/video_demo/js/verto-min.js
vendored
@ -6,7 +6,7 @@ function getCodecPayloadType(sdpLine){var pattern=new RegExp('a=rtpmap:(\\d+) \\
|
||||
function setDefaultCodec(mLine,payload){var elements=mLine.split(' ');var newLine=[];var index=0;for(var i=0;i<elements.length;i++){if(index===3){newLine[index++]=payload;}
|
||||
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(){}},},options);this.enabled=true;this.mediaData={SDP:null,profile:{},candidateList:[]};if(moz){this.constraints={offerToReceiveAudio:true,offerToReceiveVideo:this.options.useVideo?true:false,};}else{this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio:true,OfferToReceiveVideo:this.options.useVideo?true:false,}};}
|
||||
$.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(){}},},options);this.audioEnabled=true;this.videoEnabled=true;this.mediaData={SDP:null,profile:{},candidateList:[]};if(moz){this.constraints={offerToReceiveAudio:true,offerToReceiveVideo:this.options.useVideo?true:false,};}else{this.constraints={optional:[{'DtlsSrtpKeyAgreement':'true'}],mandatory:{OfferToReceiveAudio: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;if(moz){self.constraints.offerToReceiveVideo=true;}else{self.constraints.mandatory.OfferToReceiveVideo=true;}}else{self.options.useVideo=null;self.options.localVideo=null;if(moz){self.constraints.offerToReceiveVideo=false;}else{self.constraints.mandatory.OfferToReceiveVideo=false;}}
|
||||
if(self.options.useVideo){self.options.useVideo.style.display='none';}};$.FSRTC.prototype.useStereo=function(on){var self=this;self.options.useStereo=on;};$.FSRTC.prototype.stereoHack=function(sdp){var self=this;if(!self.options.useStereo){return sdp;}
|
||||
@ -34,10 +34,14 @@ if(self.localStream){if(typeof self.localStream.stop=='function'){self.localStre
|
||||
self.localStream=null;}
|
||||
if(self.options.localVideo){self.options.localVideo.style.display='none';if(moz){self.options.localVideo['mozSrcObject']=null;}else{self.options.localVideo['src']='';}}
|
||||
if(self.options.localVideoStream){if(typeof self.options.localVideoStream.stop=='function'){self.options.localVideoStream.stop();}else{if(self.localVideoStream.active){var tracks=self.localVideoStream.getTracks();console.error(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.enabled;}
|
||||
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;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.enabled=audioTracks[i].enabled;}
|
||||
return!self.enabled;}
|
||||
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;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=RTCPeerConnection({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}});onStreamSuccess(self);}
|
||||
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){getUserMedia({constraints:{audio:false,video:{mandatory:self.options.videoParams,optional:[]},},localVideo:self.options.localVideo,onsuccess:function(e){self.options.localVideoStream=e;console.log("local video ready");},onerror:function(e){console.error("local video error!");}});}
|
||||
@ -95,7 +99,9 @@ $.FSRTC.getValidRes=function(cam,func){var used=[];var cached=localStorage.getIt
|
||||
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.call=function(method,params,success_cb,error_cb){if(!params){params={};}
|
||||
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;i<loops;i++){socket.send("#SPB "+data);}
|
||||
if(rem){socket.send("#SPB "+data);}
|
||||
socket.send("#SPE");}};$.JsonRpcClient.prototype.call=function(method,params,success_cb,error_cb){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++};if(!success_cb){success_cb=function(e){console.log("Success: ",e);};}
|
||||
if(!error_cb){error_cb=function(e){console.log("Error: ",e);};}
|
||||
@ -113,7 +119,9 @@ console.error("Websocket Lost "+self.ws_cnt+" sleep: "+self.ws_sleep+"msec");sel
|
||||
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._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;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('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);this.speedCB(event,{upDur:this.up_dur,downDur:this.down_dur,upKPS:up_kps,downKPS:down_kps});this.speedCB=null;}
|
||||
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={};}
|
||||
@ -193,17 +201,21 @@ break;case"clear":la.clear();break;case"reorder":la.reorder(packet.wireSerno,pac
|
||||
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);};la.onChange=function(obj,args){var index=0;var iserr=0;if(!dt){if(!config.aoColumns){if(args.action!="init"){return;}
|
||||
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(obj.asArray());dt.fnAdjustColumnSizing();break;case"add":if(!args.data){console.error("missing data");return;}
|
||||
if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(obj.asArray());}else{dt.fnAddData(args.data);}
|
||||
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(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(obj.asArray());break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
|
||||
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.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);}};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.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){if(!this.params.hasVid){throw'Conference has no video';}
|
||||
@ -245,12 +257,17 @@ if(rtc.type=="offer"){if(dialog.state==$.verto.enum.state.active){dialog.setStat
|
||||
obj.dialogParams[i]=dialog.params[i];}
|
||||
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.setAudioDevice=function(sinkId,callback,arg){var dialog=this;var element=dialog.audioStream;if(typeof element.sinkId!=='undefined'){console.info("Dialog: "+dialog.callID+" Setting speaker:",element,find_name(sinkId));element.setSinkId(sinkId).then(function(){console.log("Dialog: "+dialog.callID+' Success, audio output device attached: '+sinkId);if(callback){callback(true,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,arg);}
|
||||
console.error(errorMessage);});}else{console.warn("Dialog: "+dialog.callID+' Browser does not support output device selection.');if(callback){callback(false,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.causeCode){dialog.causeCode=16;}
|
||||
if(!dialog.cause){dialog.cause="NORMAL CLEARING";}
|
||||
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"){var videoElement=dialog.audioStream;setTimeout(function(){console.info("Setting speaker:",videoElement,speaker);attachSinkId(videoElement,speaker);},500);}
|
||||
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"){setTimeout(function(){dialog.setAudioDevice(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:delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();}
|
||||
break;}
|
||||
@ -261,7 +278,7 @@ 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.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.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.transfer=function(dest,params){var dialog=this;if(dest){dialog.sendMethod("verto.modify",{action:"transfer",destination:dest,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++;}
|
||||
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.transfer=function(dest,params){var dialog=this;if(dest){dialog.sendMethod("verto.modify",{action:"transfer",destination:dest,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={};}
|
||||
|
@ -197,31 +197,43 @@ function check_vid() {
|
||||
return use_vid;
|
||||
}
|
||||
|
||||
// Attach audio output device to video element using device/sink ID.
|
||||
function attachSinkId(element, sinkId) {
|
||||
if (typeof element.sinkId !== 'undefined') {
|
||||
element.setSinkId(sinkId)
|
||||
.then(function() {
|
||||
console.log('Success, audio output device attached: ' + sinkId);
|
||||
})
|
||||
.catch(function(error) {
|
||||
var errorMessage = error;
|
||||
if (error.name === 'SecurityError') {
|
||||
errorMessage = 'You need to use HTTPS for selecting audio output ' +
|
||||
'device: ' + error;
|
||||
}
|
||||
console.error(errorMessage);
|
||||
// Jump back to first output device in the list as it's the default.
|
||||
//audioOutputSelect.selectedIndex = 0;
|
||||
});
|
||||
} else {
|
||||
console.warn('Browser does not support output device selection.');
|
||||
}
|
||||
function do_speed_test(fn)
|
||||
{
|
||||
goto_page("bwtest");
|
||||
|
||||
vertoHandle.rpcClient.speedTest(1024 * 256, function(e, obj) {
|
||||
//console.error("Up: " + obj.upKPS, "Down: ", obj.downKPS);
|
||||
var vid = "default";
|
||||
//if (outgoingBandwidth === "default") {
|
||||
outgoingBandwidth = Math.ceil(obj.upKPS * .75).toString();
|
||||
|
||||
$("#vqual_hd").prop("checked", true);
|
||||
vid = "1280x720";
|
||||
|
||||
if (outgoingBandwidth < 1024) {
|
||||
$("#vqual_vga").prop("checked", true);
|
||||
vid = "640x480";
|
||||
}
|
||||
if (outgoingBandwidth < 512) {
|
||||
$("#vqual_qvga").prop("checked", true);
|
||||
vid = "320x240";
|
||||
}
|
||||
//}
|
||||
|
||||
if (incomingBandwidth === "default") {
|
||||
incomingBandwidth = Math.ceil(obj.downKPS * .75).toString();
|
||||
}
|
||||
|
||||
console.info(outgoingBandwidth, incomingBandwidth);
|
||||
|
||||
$("#bwinfo").html("<b>Bandwidth: " + "Up: " + obj.upKPS + " Down: " + obj.downKPS + " Vid: " + vid + "</b>");
|
||||
|
||||
if (fn) {
|
||||
fn();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
function messageTextToJQ(body) {
|
||||
// Builds a jQuery collection from body text, linkifies http/https links, imageifies http/https links to images, and doesn't allow script injection
|
||||
|
||||
@ -559,24 +571,34 @@ var callbacks = {
|
||||
ringing = false;
|
||||
|
||||
if (success) {
|
||||
online(true);
|
||||
|
||||
/*
|
||||
verto.subscribe("presence", {
|
||||
handler: function(v, e) {
|
||||
console.error("PRESENCE:", e);
|
||||
}
|
||||
});
|
||||
*/
|
||||
do_speed_test(function() {
|
||||
|
||||
online(true);
|
||||
goto_page("main");
|
||||
|
||||
if (!window.location.hash) {
|
||||
goto_page("main");
|
||||
}
|
||||
$("input[type='radio']").checkboxradio("refresh");
|
||||
$("input[type='checkbox']").checkboxradio("refresh");
|
||||
|
||||
|
||||
/*
|
||||
verto.subscribe("presence", {
|
||||
handler: function(v, e) {
|
||||
console.error("PRESENCE:", e);
|
||||
}
|
||||
});
|
||||
*/
|
||||
|
||||
if (!window.location.hash) {
|
||||
goto_page("main");
|
||||
}
|
||||
|
||||
if (autocall) {
|
||||
autocall = false;
|
||||
docall();
|
||||
}
|
||||
});
|
||||
|
||||
if (autocall) {
|
||||
autocall = false;
|
||||
docall();
|
||||
}
|
||||
} else {
|
||||
goto_page("main");
|
||||
goto_dialog("login-error");
|
||||
@ -667,6 +689,17 @@ $("#localmutebtn").click(function() {
|
||||
|
||||
});
|
||||
|
||||
$("#localvidmutebtn").click(function() {
|
||||
var muted = cur_call.setVideoMute("toggle");
|
||||
|
||||
if (muted) {
|
||||
display("Talking to: " + cur_call.cidString() + " [VIDEO LOCALLY MUTED]");
|
||||
} else {
|
||||
display("Talking to: " + cur_call.cidString());
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
$("#vmutebtn").click(function() {
|
||||
cur_call.dtmf("*0");
|
||||
});
|
||||
@ -765,7 +798,7 @@ function docall() {
|
||||
$("#main_info").html("Trying");
|
||||
|
||||
check_vid_res();
|
||||
|
||||
console.error(outgoingBandwidth, incomingBandwidth);
|
||||
cur_call = vertoHandle.newCall({
|
||||
destination_number: $("#ext").val(),
|
||||
caller_id_name: $("#cidname").val(),
|
||||
@ -993,8 +1026,10 @@ function refresh_devices()
|
||||
$("#useshare").selectmenu('refresh', true);
|
||||
|
||||
//$("input[type='radio']).checkboxradio({});
|
||||
$("input[type='radio']").checkboxradio("refresh");
|
||||
$("input[type='checkbox']").checkboxradio("refresh");
|
||||
|
||||
|
||||
//$("input[type='radio']").checkboxradio("refresh");
|
||||
//$("input[type='checkbox']").checkboxradio("refresh");
|
||||
|
||||
//console.error($("#usecamera").find(":selected").val());
|
||||
//$.FSRTC.getValidRes($("#usecamera").find(":selected").val(), undefined);
|
||||
@ -1021,7 +1056,7 @@ function refresh_devices()
|
||||
|
||||
function init() {
|
||||
cur_call = null;
|
||||
goto_page("main");
|
||||
goto_page("bwtest");
|
||||
|
||||
$("#usecamera").selectmenu({});
|
||||
$("#usemic").selectmenu({});
|
||||
@ -1480,6 +1515,13 @@ function init() {
|
||||
$("#errordisplay").html("");
|
||||
});
|
||||
|
||||
$("#speedbtn").click(function() {
|
||||
do_speed_test(function() {
|
||||
goto_page("main");
|
||||
});
|
||||
$("#errordisplay").html("");
|
||||
});
|
||||
|
||||
$("#loginbtn").click(function() {
|
||||
online(false);
|
||||
vertoHandle.loginData({
|
||||
|
@ -1,6 +1,6 @@
|
||||
LOCAL_CFLAGS=`python ./python-config --includes`
|
||||
LOCAL_LDFLAGS=`python ./python-config --ldflags`
|
||||
SITE_DIR=$(DESTDIR)/`python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()"`
|
||||
SITE_DIR=$(DESTDIR)/`python -c "from distutils.sysconfig import get_python_lib; print get_python_lib(1)"`
|
||||
|
||||
all: _ESL.so
|
||||
|
||||
@ -14,6 +14,7 @@ _ESL.so: esl_wrap.o
|
||||
$(CXX) $(SOLINK) esl_wrap.o $(MYLIB) $(LOCAL_LDFLAGS) -o _ESL.so -L. $(LIBS)
|
||||
|
||||
install: _ESL.so
|
||||
mkdir -p $(SITE_DIR)
|
||||
install -m 755 _ESL.so $(SITE_DIR)
|
||||
install -m 755 ESL.py $(SITE_DIR)
|
||||
|
||||
|
@ -150,6 +150,13 @@ static char *print_number(cJSON *item)
|
||||
return str;
|
||||
}
|
||||
|
||||
#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
||||
static int scan_unicode(const char *ptr, unsigned int *uc)
|
||||
{
|
||||
if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1;
|
||||
return sscanf(ptr, "%4x", uc);
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
if (sscanf(ptr+1,"%4x",&uc) < 1) break;
|
||||
|
||||
if (scan_unicode(ptr+1, &uc) < 1) break;
|
||||
ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid.
|
||||
@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs.
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate.
|
||||
if (sscanf(ptr+3,"%4x",&uc2) < 1) break;
|
||||
if (scan_unicode(ptr+3,&uc2) < 1) break;
|
||||
ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate.
|
||||
uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
|
||||
|
@ -571,5 +571,63 @@ with the signaling protocols that you can run on top of your I/O interfaces.
|
||||
<param name="context" value="default"/>
|
||||
</span>
|
||||
</pritap_spans>
|
||||
|
||||
<!--
|
||||
GSM spans (libwat must be installed when configuring the freetdm build)
|
||||
-->
|
||||
<gsm_spans>
|
||||
<span name="gsm01">
|
||||
<!-- where to send inbound calls to -->
|
||||
<param name="dialplan" value="XML" />
|
||||
<param name="context" value="module1" />
|
||||
|
||||
<!--
|
||||
GSM module type
|
||||
Accepted values: "telit", "telit-gc864", "telit-he910", "telit-cc864", "telit-de910", "motorola"
|
||||
-->
|
||||
<param name="moduletype" value="telit-gc864" />
|
||||
|
||||
<!--
|
||||
Debug mask (accepted values: all, uart_raw, uart_raw, call_state, span_state, at_parse, at_handle, sms_encode, sms_decode, none)
|
||||
comma-separated values are accepted to combine those levels
|
||||
-->
|
||||
<param name="debug" value="all" />
|
||||
|
||||
<!--
|
||||
Whether to enable HW DTMF in the hardware module
|
||||
Accepted values: true, generate, detect, false
|
||||
-->
|
||||
<param name="hwdtmf" value="true" />
|
||||
|
||||
<!--
|
||||
This enables conditional forwarding on module startup
|
||||
-->
|
||||
<!-- <param name="conditional-forwarding-prefix" value="*71" /> -->
|
||||
<!-- <param name="conditional-forwarding-number" value="123456789" /> -->
|
||||
|
||||
<!--
|
||||
This enables immediate forwarding logic to simulate hunt groups
|
||||
The syntax for immediate-forwarding-numbers ia a comma-separated
|
||||
list of elements in the form [<span-name>:]<number>
|
||||
|
||||
if span-name is specified, the span will be checked for availability
|
||||
before enabling forwarding to that span number
|
||||
|
||||
The span-name must be a defined freetdm span name
|
||||
|
||||
If the span-name is not specified then only first number specified is used for
|
||||
forwarding whenever this span is busy
|
||||
-->
|
||||
<!-- <param name="immediate-forwarding-prefix" value="*72" /> -->
|
||||
<!-- <param name="immediate-forwarding-numbers" value="gsm02:123456789" /> -->
|
||||
|
||||
<!-- Number to dial to disable forwarding when the call ends (if immediate forwarding was enabled) -->
|
||||
<!-- <param name="disable-forwarding-number" value="*73" /> -->
|
||||
|
||||
<!-- Startup raw AT commands to run, you can repeat this parameter as many times as needed -->
|
||||
<!-- <param name="startup-command" value="AT$GPSP=1" /> -->
|
||||
<!-- <param name="startup-command" value="AT$GPSAT=1" /> -->
|
||||
</span>
|
||||
</gsm_spans>
|
||||
</configuration>
|
||||
|
||||
|
@ -4936,6 +4936,7 @@ FTDM_CLI_DECLARE(ftdm_cmd_trace)
|
||||
uint32_t chan_id = 0;
|
||||
uint32_t span_id = 0;
|
||||
uint32_t chan_count = 0;
|
||||
ftdm_status_t status;
|
||||
ftdm_span_t *span = NULL;
|
||||
ftdm_channel_t *chan = NULL;
|
||||
|
||||
@ -4964,17 +4965,39 @@ FTDM_CLI_DECLARE(ftdm_cmd_trace)
|
||||
|
||||
if (chan_id) {
|
||||
chan = ftdm_span_get_channel(span, chan_id);
|
||||
|
||||
snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, chan_id);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
|
||||
status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR failed to enable input trace at path %s\n", tracepath);
|
||||
goto end;
|
||||
}
|
||||
|
||||
snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, chan_id);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
|
||||
status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR failed to enable output trace at path %s\n", tracepath);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_END_ALL, NULL);
|
||||
goto end;
|
||||
}
|
||||
} else {
|
||||
for (i = 1; i <= chan_count; i++) {
|
||||
chan = ftdm_span_get_channel(span, i);
|
||||
|
||||
snprintf(tracepath, sizeof(tracepath), "%s-in-s%dc%d", argv[1], span_id, i);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
|
||||
status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_INPUT, tracepath);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR failed to enable input trace at path %s\n", tracepath);
|
||||
goto end;
|
||||
}
|
||||
|
||||
snprintf(tracepath, sizeof(tracepath), "%s-out-s%dc%d", argv[1], span_id, i);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
|
||||
status = ftdm_channel_command(chan, FTDM_COMMAND_TRACE_OUTPUT, tracepath);
|
||||
if (status != FTDM_SUCCESS) {
|
||||
stream->write_function(stream, "-ERR failed to enable output trace at path %s\n", tracepath);
|
||||
ftdm_channel_command(chan, FTDM_COMMAND_TRACE_END_ALL, NULL);
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
stream->write_function(stream, "+OK trace enabled with prefix path %s\n", argv[1]);
|
||||
|
@ -724,11 +724,22 @@ static ftdm_status_t ftdm_span_destroy(ftdm_span_t *span)
|
||||
ftdm_queue_destroy(&span->pendingchans);
|
||||
}
|
||||
if (span->pendingsignals) {
|
||||
ftdm_sigmsg_t *sigmsg = NULL;
|
||||
while ((sigmsg = ftdm_queue_dequeue(span->pendingsignals))) {
|
||||
ftdm_sigmsg_free(&sigmsg);
|
||||
}
|
||||
ftdm_queue_destroy(&span->pendingsignals);
|
||||
}
|
||||
ftdm_mutex_unlock(span->mutex);
|
||||
ftdm_mutex_destroy(&span->mutex);
|
||||
ftdm_safe_free(span->signal_data);
|
||||
|
||||
/* Give the span a chance to destroy its own signaling data */
|
||||
if (span->destroy) {
|
||||
span->destroy(span);
|
||||
} else if (span->signal_data) {
|
||||
/* We take care of their dirty business ... */
|
||||
ftdm_free(span->signal_data);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
@ -5520,7 +5531,8 @@ FT_DECLARE(ftdm_io_interface_t *) ftdm_global_get_io_interface(const char *iotyp
|
||||
FT_DECLARE(int) ftdm_load_module(const char *name)
|
||||
{
|
||||
ftdm_dso_lib_t lib;
|
||||
int count = 0, x = 0;
|
||||
int count = 0;
|
||||
ftdm_bool_t load_proceed = FTDM_TRUE;
|
||||
char path[512] = "";
|
||||
char *err;
|
||||
ftdm_module_t *mod;
|
||||
@ -5544,11 +5556,11 @@ FT_DECLARE(int) ftdm_load_module(const char *name)
|
||||
|
||||
if (mod->io_load(&interface1) != FTDM_SUCCESS || !interface1 || !interface1->name) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
|
||||
load_proceed = FTDM_FALSE;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_INFO, "Loading IO from %s [%s]\n", path, interface1->name);
|
||||
if (ftdm_global_add_io_interface(interface1) == FTDM_SUCCESS) {
|
||||
process_module_config(interface1);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -5556,13 +5568,13 @@ FT_DECLARE(int) ftdm_load_module(const char *name)
|
||||
if (mod->sig_load) {
|
||||
if (mod->sig_load() != FTDM_SUCCESS) {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Error loading %s\n", path);
|
||||
load_proceed = FTDM_FALSE;
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_INFO, "Loading SIG from %s\n", path);
|
||||
x++;
|
||||
}
|
||||
}
|
||||
|
||||
if (x) {
|
||||
if (load_proceed) {
|
||||
char *p;
|
||||
mod->lib = lib;
|
||||
ftdm_set_string(mod->path, path);
|
||||
@ -5583,7 +5595,7 @@ FT_DECLARE(int) ftdm_load_module(const char *name)
|
||||
}
|
||||
ftdm_mutex_unlock(globals.mutex);
|
||||
} else {
|
||||
ftdm_log(FTDM_LOG_ERROR, "Unloading %s\n", path);
|
||||
ftdm_log(FTDM_LOG_ERROR, "Errors during module load. Unloading %s\n", path);
|
||||
ftdm_dso_destroy(&lib);
|
||||
}
|
||||
|
||||
@ -6114,7 +6126,6 @@ FT_DECLARE(ftdm_status_t) ftdm_span_trigger_signals(const ftdm_span_t *span)
|
||||
return FTDM_SUCCESS;
|
||||
}
|
||||
|
||||
|
||||
static void execute_safety_hangup(void *data)
|
||||
{
|
||||
ftdm_channel_t *fchan = data;
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -1394,13 +1394,11 @@ static FIO_GET_ALARMS_FUNCTION(wanpipe_get_alarms)
|
||||
}
|
||||
|
||||
if (!ftdmchan->alarm_flags) {
|
||||
if (FTDM_IS_DIGITAL_CHANNEL(ftdmchan)) {
|
||||
ftdm_channel_hw_link_status_t sangoma_status = 0;
|
||||
/* there is a bug in wanpipe where alarms were not properly set when they should be
|
||||
* on at application startup, until that is fixed we check the link status here too */
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_LINK_STATUS, &sangoma_status);
|
||||
ftdmchan->alarm_flags = sangoma_status == FTDM_HW_LINK_DISCONNECTED ? FTDM_ALARM_RED : FTDM_ALARM_NONE;
|
||||
}
|
||||
/* there is a bug in wanpipe where alarms were not properly set when they should be
|
||||
* on at application startup, until that is fixed we check the link status here too */
|
||||
ftdm_channel_hw_link_status_t sangoma_status = 0;
|
||||
ftdm_channel_command(ftdmchan, FTDM_COMMAND_GET_LINK_STATUS, &sangoma_status);
|
||||
ftdmchan->alarm_flags = sangoma_status == FTDM_HW_LINK_DISCONNECTED ? FTDM_ALARM_RED : FTDM_ALARM_NONE;
|
||||
}
|
||||
|
||||
if (alarms) {
|
||||
@ -1425,33 +1423,33 @@ static __inline__ ftdm_status_t wanpipe_channel_process_event(ftdm_channel_t *fc
|
||||
case WP_API_EVENT_LINK_STATUS:
|
||||
{
|
||||
if (FTDM_IS_DIGITAL_CHANNEL(fchan)) {
|
||||
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
|
||||
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
|
||||
/* *event_id = FTDM_OOB_ALARM_CLEAR; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link connected event\n");
|
||||
break;
|
||||
default:
|
||||
/* *event_id = FTDM_OOB_ALARM_TRAP; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link disconnected event\n");
|
||||
break;
|
||||
};
|
||||
/* The WP_API_EVENT_ALARM event should be used to clear alarms */
|
||||
*event_id = FTDM_OOB_NOOP;
|
||||
} else {
|
||||
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
|
||||
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
|
||||
/* *event_id = FTDM_OOB_ALARM_CLEAR; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Using analog link connected event as alarm clear\n");
|
||||
*event_id = FTDM_OOB_ALARM_CLEAR;
|
||||
fchan->alarm_flags = FTDM_ALARM_NONE;
|
||||
break;
|
||||
default:
|
||||
/* *event_id = FTDM_OOB_ALARM_TRAP; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Using analog link disconnected event as alarm trap\n");
|
||||
*event_id = FTDM_OOB_ALARM_TRAP;
|
||||
fchan->alarm_flags = FTDM_ALARM_RED;
|
||||
break;
|
||||
};
|
||||
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
|
||||
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
|
||||
/* *event_id = FTDM_OOB_ALARM_CLEAR; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link connected event\n");
|
||||
break;
|
||||
default:
|
||||
/* *event_id = FTDM_OOB_ALARM_TRAP; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Ignoring wanpipe link disconnected event\n");
|
||||
break;
|
||||
}
|
||||
/* The WP_API_EVENT_ALARM event should be used to clear alarms */
|
||||
*event_id = FTDM_OOB_NOOP;
|
||||
} else {
|
||||
switch(tdm_api->wp_tdm_cmd.event.wp_tdm_api_event_link_status) {
|
||||
case WP_TDMAPI_EVENT_LINK_STATUS_CONNECTED:
|
||||
/* *event_id = FTDM_OOB_ALARM_CLEAR; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Using analog link connected event as alarm clear\n");
|
||||
*event_id = FTDM_OOB_ALARM_CLEAR;
|
||||
fchan->alarm_flags = FTDM_ALARM_NONE;
|
||||
break;
|
||||
default:
|
||||
/* *event_id = FTDM_OOB_ALARM_TRAP; */
|
||||
ftdm_log_chan_msg(fchan, FTDM_LOG_DEBUG, "Using analog link disconnected event as alarm trap\n");
|
||||
*event_id = FTDM_OOB_ALARM_TRAP;
|
||||
fchan->alarm_flags = FTDM_ALARM_RED;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
@ -512,6 +512,7 @@ struct ftdm_span {
|
||||
fio_channel_request_t channel_request;
|
||||
ftdm_span_start_t start;
|
||||
ftdm_span_stop_t stop;
|
||||
ftdm_span_destroy_t destroy;
|
||||
ftdm_channel_sig_read_t sig_read;
|
||||
ftdm_channel_sig_write_t sig_write;
|
||||
ftdm_channel_sig_dtmf_t sig_queue_dtmf;
|
||||
|
@ -348,6 +348,7 @@ typedef struct ftdm_bitstream ftdm_bitstream_t;
|
||||
typedef struct ftdm_fsk_modulator ftdm_fsk_modulator_t;
|
||||
typedef ftdm_status_t (*ftdm_span_start_t)(ftdm_span_t *span);
|
||||
typedef ftdm_status_t (*ftdm_span_stop_t)(ftdm_span_t *span);
|
||||
typedef ftdm_status_t (*ftdm_span_destroy_t)(ftdm_span_t *span);
|
||||
typedef ftdm_status_t (*ftdm_channel_sig_read_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size);
|
||||
typedef ftdm_status_t (*ftdm_channel_sig_write_t)(ftdm_channel_t *ftdmchan, void *data, ftdm_size_t size);
|
||||
typedef ftdm_status_t (*ftdm_channel_sig_dtmf_t)(ftdm_channel_t *ftdmchan, const char *dtmf);
|
||||
|
@ -150,6 +150,13 @@ static char *print_number(cJSON *item)
|
||||
return str;
|
||||
}
|
||||
|
||||
#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
||||
static int scan_unicode(const char *ptr, unsigned int *uc)
|
||||
{
|
||||
if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1;
|
||||
return sscanf(ptr, "%4x", uc);
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
if (sscanf(ptr+1,"%4x",&uc) < 1) break;
|
||||
|
||||
if (scan_unicode(ptr+1, &uc) < 1) break;
|
||||
ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid.
|
||||
@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs.
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate.
|
||||
if (sscanf(ptr+3,"%4x",&uc2) < 1) break;
|
||||
if (scan_unicode(ptr+3,&uc2) < 1) break;
|
||||
ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate.
|
||||
uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
|
||||
|
@ -220,6 +220,7 @@ struct switch_media_bug {
|
||||
uint32_t record_pre_buffer_count;
|
||||
uint32_t record_pre_buffer_max;
|
||||
switch_frame_t *ping_frame;
|
||||
switch_frame_t *video_ping_frame;
|
||||
switch_frame_t *read_demux_frame;
|
||||
switch_queue_t *read_video_queue;
|
||||
switch_queue_t *write_video_queue;
|
||||
|
@ -341,6 +341,7 @@ SWITCH_DECLARE(switch_status_t) switch_core_media_set_video_file(switch_core_ses
|
||||
SWITCH_DECLARE(switch_file_handle_t *) switch_core_media_get_video_file(switch_core_session_t *session, switch_rw_t rw);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_session_in_video_thread(switch_core_session_t *session);
|
||||
SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t *session, switch_media_type_t type);
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_set_outgoing_bitrate(switch_core_session_t *session, switch_media_type_t type, uint32_t bitrate);
|
||||
|
||||
SWITCH_END_EXTERN_C
|
||||
#endif
|
||||
|
@ -51,6 +51,7 @@ struct switch_rtcp_report_block_frame {
|
||||
uint32_t lsr; /* The middle 32 bits out of 64 in the NTP timestamp */
|
||||
uint32_t dlsr; /* The delay, expressed in units of 1/65536 seconds, between receiving the last SR packet from source SSRC_n and sending this reception report block */
|
||||
uint32_t loss_avg;
|
||||
double rtt_avg;
|
||||
};
|
||||
|
||||
/*! \brief An abstraction of a rtcp frame */
|
||||
|
@ -613,6 +613,14 @@ typedef enum {
|
||||
} switch_vad_flag_enum_t;
|
||||
typedef uint32_t switch_vad_flag_t;
|
||||
|
||||
|
||||
typedef struct error_period {
|
||||
int64_t start;
|
||||
int64_t stop;
|
||||
struct error_period *next;
|
||||
} switch_error_period_t;
|
||||
|
||||
|
||||
typedef struct {
|
||||
switch_size_t raw_bytes;
|
||||
switch_size_t media_bytes;
|
||||
@ -648,6 +656,7 @@ typedef struct {
|
||||
switch_size_t last_flaw;
|
||||
double R;
|
||||
double mos;
|
||||
struct error_period *error_log;
|
||||
} switch_rtp_numbers_t;
|
||||
|
||||
typedef struct {
|
||||
|
@ -859,7 +859,7 @@ static inline switch_bool_t switch_strstr(char *s, char *q)
|
||||
|
||||
S = strdup(s);
|
||||
|
||||
assert(S != NULL);
|
||||
switch_assert(S != NULL);
|
||||
|
||||
for (p = S; p && *p; p++) {
|
||||
*p = (char) switch_toupper(*p);
|
||||
@ -871,7 +871,7 @@ static inline switch_bool_t switch_strstr(char *s, char *q)
|
||||
}
|
||||
|
||||
Q = strdup(q);
|
||||
assert(Q != NULL);
|
||||
switch_assert(Q != NULL);
|
||||
|
||||
for (p = Q; p && *p; p++) {
|
||||
*p = (char) switch_toupper(*p);
|
||||
|
@ -25,6 +25,7 @@
|
||||
*
|
||||
* Seven Du <dujinfang@gmail.com>
|
||||
* Anthony Minessale <anthm@freeswitch.org>
|
||||
* Emmanuel Schmidbauer <eschmidbauer@gmail.com>
|
||||
*
|
||||
* mod_avcodec -- Codec with libav.org
|
||||
*
|
||||
@ -538,7 +539,7 @@ static void fs_rtp_parse_h263_rfc2190(h264_codec_context_t *context, AVPacket *p
|
||||
mb_info_pos++;
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"Unable to split H263 packet! mb_info_pos=%d mb_info_count=%d pos=%d max=%ld\n", mb_info_pos, mb_info_count, pos, end - buf_base);
|
||||
"Unable to split H263 packet! mb_info_pos=%d mb_info_count=%d pos=%d max=%"SWITCH_SIZE_T_FMT"\n", mb_info_pos, mb_info_count, pos, (switch_size_t)(end - buf_base));
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Should Not Happen!!! mb_info_pos=%d mb_info_count=%d mb_info_size=%d\n", mb_info_pos, mb_info_count, mb_info_size);
|
||||
@ -799,7 +800,8 @@ static switch_status_t consume_nalu(h264_codec_context_t *context, switch_frame_
|
||||
|
||||
static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t width, uint32_t height)
|
||||
{
|
||||
|
||||
int sane = 0;
|
||||
|
||||
if (!context->encoder) context->encoder = avcodec_find_encoder(context->av_codec_id);
|
||||
|
||||
if (!context->encoder) {
|
||||
@ -846,6 +848,11 @@ static switch_status_t open_encoder(h264_codec_context_t *context, uint32_t widt
|
||||
context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 0, 0) * 8;
|
||||
}
|
||||
|
||||
if (context->bandwidth > sane) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BITRATE TRUNCATED TO %d\n", sane);
|
||||
context->bandwidth = sane * 8;
|
||||
}
|
||||
|
||||
//context->encoder_ctx->bit_rate = context->bandwidth * 1024;
|
||||
context->encoder_ctx->width = context->codec_settings.video.width;
|
||||
context->encoder_ctx->height = context->codec_settings.video.height;
|
||||
@ -1493,7 +1500,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_avcodec_load)
|
||||
switch_h264_init, switch_h264_encode, switch_h264_decode, switch_h264_control, switch_h264_destroy);
|
||||
|
||||
SWITCH_ADD_CODEC(codec_interface, "H263+ Video");
|
||||
switch_core_codec_add_video_implementation(pool, codec_interface, 34, "H263-1998", NULL,
|
||||
switch_core_codec_add_video_implementation(pool, codec_interface, 115, "H263-1998", NULL,
|
||||
switch_h264_init, switch_h264_encode, switch_h264_decode, switch_h264_control, switch_h264_destroy);
|
||||
|
||||
SWITCH_ADD_API(api_interface, "av_codec", "av_codec information", av_codec_api_function, "");
|
||||
|
@ -330,7 +330,6 @@ static switch_status_t add_stream(MediaStream *mst, AVFormatContext *fc, AVCodec
|
||||
break;
|
||||
case SWITCH_VIDEO_ENCODE_SPEED_FAST:
|
||||
av_opt_set(c->priv_data, "preset", "veryfast", 0);
|
||||
av_opt_set(c->priv_data, "tune", "zerolatency", 0);
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
@ -513,7 +512,7 @@ static void *SWITCH_THREAD_FUNC video_thread_run(switch_thread_t *thread, void *
|
||||
record_helper_t *eh = (record_helper_t *) obj;
|
||||
void *pop = NULL;
|
||||
switch_image_t *img = NULL, *tmp_img = NULL;
|
||||
int d_w = 0, d_h = 0;
|
||||
int d_w = eh->video_st->width, d_h = eh->video_st->height;
|
||||
int size = 0, skip = 0, skip_freq = 0, skip_count = 0, skip_total = 0, skip_total_count = 0;
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "video thread start\n");
|
||||
|
@ -1213,15 +1213,18 @@ switch_status_t conference_api_sub_vid_layout(conference_obj_t *conference, swit
|
||||
|
||||
if (idx < 0 || idx > (int)(conference->canvas_count - 1)) idx = 0;
|
||||
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
|
||||
if (conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS)) {
|
||||
stream->write_function(stream, "Change personal canvas set to layout [%s]\n", vlayout->name);
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
conference->new_personal_vlayout = vlayout;
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
} else {
|
||||
stream->write_function(stream, "Change canvas %d to layout [%s]\n", idx + 1, vlayout->name);
|
||||
switch_mutex_lock(conference->canvases[idx]->mutex);
|
||||
conference->canvases[idx]->new_vlayout = vlayout;
|
||||
switch_mutex_unlock(conference->canvases[idx]->mutex);
|
||||
}
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@ -1579,8 +1582,6 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
|
||||
if (!strcasecmp(text, "clear") || (member->video_reservation_id && !strcasecmp(text, member->video_reservation_id))) {
|
||||
member->video_reservation_id = NULL;
|
||||
stream->write_function(stream, "+OK reservation_id cleared\n");
|
||||
@ -1591,8 +1592,6 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc
|
||||
|
||||
conference_video_detach_video_layer(member);
|
||||
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
|
||||
}
|
||||
|
@ -378,13 +378,10 @@ void conference_event_la_command_handler(switch_live_array_t *la, const char *cm
|
||||
void conference_event_adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join)
|
||||
{
|
||||
|
||||
//if (switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
switch_channel_set_flag(member->channel, CF_VIDEO_REFRESH_REQ);
|
||||
switch_core_media_gen_key_frame(member->session);
|
||||
//}
|
||||
|
||||
if (conference && conference->la && member->session &&
|
||||
!switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) {
|
||||
if (conference && conference->la && member->session) {
|
||||
cJSON *msg, *data;
|
||||
const char *uuid = switch_core_session_get_uuid(member->session);
|
||||
const char *cookie = switch_channel_get_variable(member->channel, "event_channel_cookie");
|
||||
@ -412,6 +409,14 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
|
||||
cJSON_AddItemToObject(data, "secondScreen", cJSON_CreateTrue());
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) {
|
||||
cJSON_AddItemToObject(data, "videoOnly", cJSON_CreateTrue());
|
||||
}
|
||||
|
||||
if (switch_true(switch_channel_get_variable_dup(member->channel, "video_screen_share", SWITCH_FALSE, -1))) {
|
||||
cJSON_AddItemToObject(data, "screenShare", cJSON_CreateTrue());
|
||||
}
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_MOD)) {
|
||||
cJSON_AddItemToObject(data, "modChannel", cJSON_CreateString(conference->mod_event_channel));
|
||||
}
|
||||
|
@ -410,6 +410,45 @@ switch_status_t conference_file_local_play(conference_obj_t *conference, switch_
|
||||
return status;
|
||||
}
|
||||
|
||||
switch_status_t conference_close_open_files(conference_obj_t *conference)
|
||||
{
|
||||
int x = 0;
|
||||
|
||||
switch_mutex_lock(conference->mutex);
|
||||
/* Close Unused Handles */
|
||||
if (conference->fnode) {
|
||||
conference_file_node_t *fnode, *cur;
|
||||
switch_memory_pool_t *pool;
|
||||
|
||||
fnode = conference->fnode;
|
||||
while (fnode) {
|
||||
cur = fnode;
|
||||
fnode = fnode->next;
|
||||
|
||||
if (cur->type != NODE_TYPE_SPEECH) {
|
||||
conference_file_close(conference, cur);
|
||||
}
|
||||
|
||||
pool = cur->pool;
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
x++;
|
||||
}
|
||||
conference->fnode = NULL;
|
||||
}
|
||||
|
||||
if (conference->async_fnode) {
|
||||
switch_memory_pool_t *pool;
|
||||
conference_file_close(conference, conference->async_fnode);
|
||||
pool = conference->async_fnode->pool;
|
||||
conference->async_fnode = NULL;
|
||||
switch_core_destroy_memory_pool(&pool);
|
||||
x++;
|
||||
}
|
||||
switch_mutex_unlock(conference->mutex);
|
||||
|
||||
return x ? SWITCH_STATUS_SUCCESS : SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
/* For Emacs:
|
||||
* Local Variables:
|
||||
* mode:c
|
||||
|
@ -150,13 +150,41 @@ void conference_member_update_status_field(conference_member_t *member)
|
||||
char *str, *vstr = "", display[128] = "", *json_display = NULL;
|
||||
cJSON *json, *audio, *video;
|
||||
|
||||
if (!member->conference->la || !member->json ||
|
||||
!member->status_field || switch_channel_test_flag(member->channel, CF_VIDEO_ONLY) || conference_utils_member_test_flag(member, MFLAG_SECOND_SCREEN)) {
|
||||
if (!member->conference->la || !member->json || !member->status_field || conference_utils_member_test_flag(member, MFLAG_SECOND_SCREEN)) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
switch_live_array_lock(member->conference->la);
|
||||
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
|
||||
str = "MUTE";
|
||||
} else if (switch_channel_test_flag(member->channel, CF_HOLD)) {
|
||||
str = "HOLD";
|
||||
} else if (member == member->conference->floor_holder) {
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
str = "TALKING (FLOOR)";
|
||||
} else {
|
||||
str = "FLOOR";
|
||||
}
|
||||
} else if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
str = "TALKING";
|
||||
} else {
|
||||
str = "ACTIVE";
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) {
|
||||
vstr = " VIDEO (BLIND)";
|
||||
} else {
|
||||
vstr = " VIDEO";
|
||||
if (member && member->id == member->conference->video_floor_holder) {
|
||||
vstr = " VIDEO (FLOOR)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_snprintf(display, sizeof(display), "%s%s", str, vstr);
|
||||
|
||||
if (conference_utils_test_flag(member->conference, CFLAG_JSON_STATUS)) {
|
||||
json = cJSON_CreateObject();
|
||||
audio = cJSON_CreateObject();
|
||||
@ -169,6 +197,19 @@ void conference_member_update_status_field(conference_member_t *member)
|
||||
|
||||
if (switch_channel_test_flag(member->channel, CF_VIDEO) || member->avatar_png_img) {
|
||||
video = cJSON_CreateObject();
|
||||
|
||||
if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) &&
|
||||
member->video_layer_id > -1 && switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
cJSON_AddItemToObject(video, "visible", cJSON_CreateTrue());
|
||||
} else {
|
||||
cJSON_AddItemToObject(video, "visible", cJSON_CreateFalse());
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(video, "videoOnly", cJSON_CreateBool(switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)));
|
||||
if (switch_true(switch_channel_get_variable_dup(member->channel, "video_screen_share", SWITCH_FALSE, -1))) {
|
||||
cJSON_AddItemToObject(video, "screenShare", cJSON_CreateTrue());
|
||||
}
|
||||
|
||||
cJSON_AddItemToObject(video, "avatarPresented", cJSON_CreateBool(!!member->avatar_png_img));
|
||||
cJSON_AddItemToObject(video, "mediaFlow", cJSON_CreateString(switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY ? "sendOnly" : "sendRecv"));
|
||||
cJSON_AddItemToObject(video, "muted", cJSON_CreateBool(!conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)));
|
||||
@ -186,43 +227,19 @@ void conference_member_update_status_field(conference_member_t *member)
|
||||
cJSON_AddItemToObject(json, "video", cJSON_CreateFalse());
|
||||
}
|
||||
|
||||
if (conference_utils_test_flag(member->conference, CFLAG_JSON_STATUS)) {
|
||||
cJSON_AddItemToObject(json, "oldStatus", cJSON_CreateString(display));
|
||||
}
|
||||
|
||||
json_display = cJSON_PrintUnformatted(json);
|
||||
cJSON_Delete(json);
|
||||
} else {
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) {
|
||||
str = "MUTE";
|
||||
} else if (switch_channel_test_flag(member->channel, CF_HOLD)) {
|
||||
str = "HOLD";
|
||||
} else if (member == member->conference->floor_holder) {
|
||||
if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
str = "TALKING (FLOOR)";
|
||||
} else {
|
||||
str = "FLOOR";
|
||||
}
|
||||
} else if (conference_utils_member_test_flag(member, MFLAG_TALKING)) {
|
||||
str = "TALKING";
|
||||
} else {
|
||||
str = "ACTIVE";
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) {
|
||||
vstr = " VIDEO (BLIND)";
|
||||
} else {
|
||||
vstr = " VIDEO";
|
||||
if (member && member->id == member->conference->video_floor_holder) {
|
||||
vstr = " VIDEO (FLOOR)";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
switch_snprintf(display, sizeof(display), "%s%s", str, vstr);
|
||||
}
|
||||
|
||||
switch_safe_free(member->status_field->valuestring);
|
||||
|
||||
if (json_display) {
|
||||
member->status_field->valuestring = json_display;
|
||||
} else {
|
||||
free(member->status_field->valuestring);
|
||||
member->status_field->valuestring = strdup(display);
|
||||
}
|
||||
|
||||
@ -694,12 +711,10 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
if (conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS)) {
|
||||
video_layout_t *vlayout = NULL;
|
||||
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
if ((vlayout = conference_video_get_layout(conference, conference->video_layout_name, conference->video_layout_group))) {
|
||||
conference_video_init_canvas(conference, vlayout, &member->canvas);
|
||||
conference_video_init_canvas_layers(conference, member->canvas, vlayout);
|
||||
}
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
}
|
||||
|
||||
conference->members = member;
|
||||
@ -767,6 +782,19 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
conference_utils_member_set_flag_locked(member, MFLAG_NO_MINIMIZE_ENCODING);
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(member->channel, "rtp_video_max_bandwidth_in"))) {
|
||||
member->max_bw_in = switch_parse_bandwidth_string(var);
|
||||
}
|
||||
|
||||
if ((var = switch_channel_get_variable(member->channel, "rtp_video_max_bandwidth_out"))) {
|
||||
member->max_bw_out = switch_parse_bandwidth_string(var);;
|
||||
|
||||
if (member->max_bw_out < conference->video_codec_settings.video.bandwidth) {
|
||||
conference_utils_member_set_flag_locked(member, MFLAG_NO_MINIMIZE_ENCODING);
|
||||
switch_core_media_set_outgoing_bitrate(member->session, SWITCH_MEDIA_TYPE_VIDEO, member->max_bw_out);
|
||||
}
|
||||
}
|
||||
|
||||
switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id);
|
||||
switch_channel_set_variable_printf(channel, "conference_moderator", "%s", conference_utils_member_test_flag(member, MFLAG_MOD) ? "true" : "false");
|
||||
switch_channel_set_variable_printf(channel, "conference_ghost", "%s", conference_utils_member_test_flag(member, MFLAG_GHOST) ? "true" : "false");
|
||||
@ -903,7 +931,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
switch_mutex_unlock(member->audio_out_mutex);
|
||||
switch_mutex_unlock(member->audio_in_mutex);
|
||||
|
||||
if (conference->la && member->channel && !switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) {
|
||||
if (conference->la && member->channel) {
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_SECOND_SCREEN)) {
|
||||
cJSON *dvars;
|
||||
switch_event_t *var_event;
|
||||
@ -918,7 +946,6 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
switch_channel_get_variable(member->channel, "original_read_codec"),
|
||||
switch_channel_get_variable(member->channel, "original_read_rate")
|
||||
));
|
||||
|
||||
member->status_field = cJSON_CreateString("");
|
||||
cJSON_AddItemToArray(member->json, member->status_field);
|
||||
|
||||
@ -953,6 +980,7 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m
|
||||
if (!conference_utils_member_test_flag(member, MFLAG_SECOND_SCREEN)) {
|
||||
switch_live_array_add(conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -1213,7 +1241,7 @@ switch_status_t conference_member_del(conference_obj_t *conference, conference_m
|
||||
switch_mutex_unlock(member->audio_in_mutex);
|
||||
|
||||
|
||||
if (conference->la && member->session && !switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) {
|
||||
if (conference->la && member->session) {
|
||||
switch_live_array_del(conference->la, switch_core_session_get_uuid(member->session));
|
||||
//switch_live_array_clear_alias(conference->la, switch_core_session_get_uuid(member->session), "conference");
|
||||
conference_event_adv_la(conference, member, SWITCH_FALSE);
|
||||
|
@ -337,8 +337,6 @@ void conference_video_clear_layer(mcu_layer_t *layer)
|
||||
|
||||
void conference_video_reset_layer(mcu_layer_t *layer)
|
||||
{
|
||||
layer->tagged = 0;
|
||||
|
||||
switch_img_free(&layer->banner_img);
|
||||
switch_img_free(&layer->logo_img);
|
||||
switch_img_free(&layer->logo_text_img);
|
||||
@ -553,28 +551,16 @@ mcu_layer_t *conference_video_get_layer_locked(conference_member_t *member)
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
if (!member || member->canvas_id < 0 || member->video_layer_id < 0) return NULL;
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
if ((canvas = conference_video_get_canvas_locked(member))) {
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
|
||||
if (!canvas) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
|
||||
if (!layer) {
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
if (!layer) {
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
}
|
||||
}
|
||||
|
||||
end:
|
||||
|
||||
if (!layer) {
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
}
|
||||
|
||||
return layer;
|
||||
}
|
||||
|
||||
@ -589,28 +575,50 @@ void conference_video_release_layer(mcu_layer_t **layer)
|
||||
if (!canvas) return;
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
|
||||
switch_assert(canvas->conference);
|
||||
|
||||
switch_mutex_unlock(canvas->conference->canvas_mutex);
|
||||
|
||||
conference_video_release_canvas(&canvas);
|
||||
|
||||
*layer = NULL;
|
||||
}
|
||||
|
||||
mcu_canvas_t *conference_video_get_canvas_locked(conference_member_t *member)
|
||||
{
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
if (!member || member->canvas_id < 0 || member->video_layer_id < 0) return NULL;
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
|
||||
if (!canvas) {
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
}
|
||||
|
||||
return canvas;
|
||||
}
|
||||
|
||||
void conference_video_release_canvas(mcu_canvas_t **canvasP)
|
||||
{
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
switch_assert(canvasP);
|
||||
|
||||
canvas = *canvasP;
|
||||
|
||||
if (!canvas) return;
|
||||
|
||||
switch_mutex_unlock(canvas->conference->canvas_mutex);
|
||||
*canvasP = NULL;
|
||||
}
|
||||
|
||||
void conference_video_detach_video_layer(conference_member_t *member)
|
||||
{
|
||||
mcu_layer_t *layer = NULL;
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
if (member->canvas_id < 0 || member->video_layer_id < 0) return;
|
||||
|
||||
if (member->canvas_id < 0) goto end;
|
||||
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
|
||||
if (!canvas || member->video_layer_id < 0) {
|
||||
goto end;
|
||||
if (!(canvas = conference_video_get_canvas_locked(member))) {
|
||||
return;
|
||||
}
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
@ -646,11 +654,8 @@ void conference_video_detach_video_layer(conference_member_t *member)
|
||||
}
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
|
||||
end:
|
||||
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
|
||||
conference_video_release_canvas(&canvas);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -892,8 +897,6 @@ switch_status_t conference_video_attach_video_layer(conference_member_t *member,
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
|
||||
layer = &canvas->layers[idx];
|
||||
@ -973,8 +976,6 @@ switch_status_t conference_video_attach_video_layer(conference_member_t *member,
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
@ -985,7 +986,6 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
|
||||
if (!canvas) return;
|
||||
|
||||
switch_thread_rwlock_wrlock(canvas->video_rwlock);
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
canvas->layout_floor_id = -1;
|
||||
|
||||
@ -996,7 +996,6 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
|
||||
|
||||
if (!vlayout) {
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
switch_thread_rwlock_unlock(canvas->video_rwlock);
|
||||
return;
|
||||
}
|
||||
@ -1072,7 +1071,6 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
|
||||
}
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
switch_thread_rwlock_unlock(canvas->video_rwlock);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id + 1, vlayout->name);
|
||||
@ -1265,7 +1263,6 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
|
||||
}
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
|
||||
switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY ||
|
||||
switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
@ -1274,6 +1271,11 @@ void conference_video_write_canvas_image_to_codec_group(conference_obj_t *confer
|
||||
switch_core_session_request_video_refresh(imember->session);
|
||||
}
|
||||
|
||||
if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) {
|
||||
switch_core_session_rwunlock(imember->session);
|
||||
continue;
|
||||
}
|
||||
|
||||
//switch_core_session_write_encoded_video_frame(imember->session, frame, 0, 0);
|
||||
switch_set_flag(frame, SFF_ENCODED);
|
||||
|
||||
@ -1322,7 +1324,7 @@ video_layout_t *conference_video_get_layout(conference_obj_t *conference, const
|
||||
} else {
|
||||
vlayout = switch_core_hash_find(conference->layout_hash, video_layout_name);
|
||||
}
|
||||
|
||||
|
||||
return vlayout;
|
||||
}
|
||||
|
||||
@ -1334,8 +1336,8 @@ void conference_video_vmute_snap(conference_member_t *member, switch_bool_t clea
|
||||
mcu_layer_t *layer = NULL;
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
|
||||
canvas = conference_video_get_canvas_locked(member);
|
||||
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
switch_img_free(&layer->mute_img);
|
||||
@ -1347,6 +1349,7 @@ void conference_video_vmute_snap(conference_member_t *member, switch_bool_t clea
|
||||
}
|
||||
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1491,7 +1494,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_
|
||||
switch_time_t now = switch_time_now();
|
||||
|
||||
if (last) {
|
||||
int delta = now - last;
|
||||
int delta = (int)(now - last);
|
||||
if (delta > member->conference->video_fps.ms * 5000) {
|
||||
switch_core_session_request_video_refresh(member->session);
|
||||
}
|
||||
@ -1505,26 +1508,25 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_thread_
|
||||
switch_frame_buffer_free(member->fb, &frame);
|
||||
}
|
||||
|
||||
canvas = NULL;
|
||||
layer = NULL;
|
||||
|
||||
switch_mutex_lock(member->conference->canvas_mutex);
|
||||
if (member->video_layer_id > -1 && member->canvas_id > -1) {
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
layer = &canvas->layers[member->video_layer_id];
|
||||
|
||||
if (layer->need_patch) {
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
} else {
|
||||
if (!layer->need_patch || switch_thread_rwlock_tryrdlock(canvas->video_rwlock) != SWITCH_STATUS_SUCCESS) {
|
||||
canvas = NULL;
|
||||
layer = NULL;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(member->conference->canvas_mutex);
|
||||
|
||||
if (canvas) {
|
||||
switch_thread_rwlock_rdlock(canvas->video_rwlock);
|
||||
if (canvas && layer && layer->need_patch) {
|
||||
conference_video_scale_and_patch(layer, NULL, SWITCH_FALSE);
|
||||
layer->need_patch = 0;
|
||||
switch_thread_rwlock_unlock(canvas->video_rwlock);
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1580,10 +1582,13 @@ void conference_video_check_avatar(conference_member_t *member, switch_bool_t fo
|
||||
return;
|
||||
}
|
||||
|
||||
canvas = member->conference->canvases[member->canvas_id];
|
||||
canvas = conference_video_get_canvas_locked(member);
|
||||
|
||||
if (conference_utils_test_flag(member->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS) &&
|
||||
(!switch_channel_test_flag(member->channel, CF_VIDEO) || switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY)) {
|
||||
if (canvas) {
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
@ -1621,6 +1626,7 @@ void conference_video_check_avatar(conference_member_t *member, switch_bool_t fo
|
||||
|
||||
if (canvas) {
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1713,7 +1719,7 @@ switch_status_t conference_video_find_layer(conference_obj_t *conference, mcu_ca
|
||||
mcu_layer_t *layer = NULL;
|
||||
int i;
|
||||
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
switch_mutex_lock(canvas->mutex);
|
||||
|
||||
for (i = 0; i < canvas->total_layers; i++) {
|
||||
mcu_layer_t *xlayer = &canvas->layers[i];
|
||||
@ -1759,7 +1765,7 @@ switch_status_t conference_video_find_layer(conference_obj_t *conference, mcu_ca
|
||||
}
|
||||
}
|
||||
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
switch_mutex_unlock(canvas->mutex);
|
||||
|
||||
if (layer) {
|
||||
*layerP = layer;
|
||||
@ -1836,14 +1842,67 @@ void conference_video_pop_next_image(conference_member_t *member, switch_image_t
|
||||
*imgP = img;
|
||||
}
|
||||
|
||||
void conference_video_set_incoming_bitrate(conference_member_t *member, int kps)
|
||||
{
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_BITRATE_REQ;
|
||||
msg.numeric_arg = kps * 1024;
|
||||
msg.from = __FILE__;
|
||||
|
||||
switch_core_session_receive_message(member->session, &msg);
|
||||
member->managed_kps = kps;
|
||||
}
|
||||
|
||||
void conference_video_set_max_incoming_bitrate_member(conference_member_t *member, int kps)
|
||||
{
|
||||
member->max_bw_in = kps;
|
||||
member->managed_kps = 0;
|
||||
}
|
||||
|
||||
void conference_video_set_absolute_incoming_bitrate_member(conference_member_t *member, int kps)
|
||||
{
|
||||
member->max_bw_in = 0;
|
||||
member->force_bw_in = kps;
|
||||
member->managed_kps = 0;
|
||||
if (!conference_utils_test_flag(member->conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE) && switch_channel_test_flag(member->channel, CF_VIDEO)) {
|
||||
conference_video_set_incoming_bitrate(member, kps);
|
||||
}
|
||||
}
|
||||
|
||||
void conference_video_set_max_incoming_bitrate(conference_obj_t *conference, int kps)
|
||||
{
|
||||
conference_member_t *imember;
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
if (imember->channel && switch_channel_ready(imember->channel) && conference_utils_member_test_flag(imember, MFLAG_RUNNING)) {
|
||||
conference_video_set_max_incoming_bitrate_member(imember, kps);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
}
|
||||
|
||||
void conference_video_set_absolute_incoming_bitrate(conference_obj_t *conference, int kps)
|
||||
{
|
||||
conference_member_t *imember;
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
if (imember->channel && switch_channel_ready(imember->channel) && conference_utils_member_test_flag(imember, MFLAG_RUNNING)) {
|
||||
conference_video_set_absolute_incoming_bitrate_member(imember, kps);
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(conference->member_mutex);
|
||||
}
|
||||
|
||||
void conference_video_check_auto_bitrate(conference_member_t *member, mcu_layer_t *layer)
|
||||
{
|
||||
|
||||
if (switch_channel_test_flag(member->channel, CF_VIDEO_BITRATE_UNMANAGABLE)) {
|
||||
member->managed_kps = 0;
|
||||
} else if (conference_utils_test_flag(member->conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE) && !member->managed_kps) {
|
||||
switch_core_session_message_t msg = { 0 };
|
||||
int kps;
|
||||
int kps = 256;
|
||||
int w = 320;
|
||||
int h = 240;
|
||||
|
||||
@ -1853,23 +1912,35 @@ void conference_video_check_auto_bitrate(conference_member_t *member, mcu_layer_
|
||||
h = layer->screen_h;
|
||||
}
|
||||
}
|
||||
|
||||
if (!layer || !conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) || member->avatar_png_img) {
|
||||
kps = 200;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s auto-setting bitrate to %dkps because user's image is not visible\n",
|
||||
|
||||
if (member->conference->force_bw_in || member->force_bw_in) {
|
||||
if (!(kps = member->conference->force_bw_in)) {
|
||||
kps = member->force_bw_in;
|
||||
}
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s setting bitrate to %dkps because it was forced.\n",
|
||||
switch_channel_get_name(member->channel), kps);
|
||||
} else {
|
||||
kps = switch_calc_bitrate(w, h, 2, (int)(member->conference->video_fps.fps));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s auto-setting bitrate to %dkps to accomodate %dx%d resolution\n",
|
||||
switch_channel_get_name(member->channel), kps, layer->screen_w, layer->screen_h);
|
||||
int max = 0;
|
||||
|
||||
if (layer) {
|
||||
kps = switch_calc_bitrate(w, h, 1, (int)(member->conference->video_fps.fps));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s auto-setting bitrate to %dkps to accomodate %dx%d resolution\n",
|
||||
switch_channel_get_name(member->channel), kps, layer->screen_w, layer->screen_h);
|
||||
}
|
||||
|
||||
if (member->conference->max_bw_in) {
|
||||
max = member->conference->max_bw_in;
|
||||
} else {
|
||||
max = member->max_bw_in;
|
||||
}
|
||||
|
||||
if (max && kps > max) {
|
||||
kps = max;
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s overriding bitrate setting to %dkps because it was the max allowed.\n",
|
||||
switch_channel_get_name(member->channel), kps);
|
||||
}
|
||||
}
|
||||
|
||||
msg.message_id = SWITCH_MESSAGE_INDICATE_BITRATE_REQ;
|
||||
msg.numeric_arg = kps * 1024;
|
||||
msg.from = __FILE__;
|
||||
|
||||
switch_core_session_receive_message(member->session, &msg);
|
||||
member->managed_kps = kps;
|
||||
conference_video_set_incoming_bitrate(member, kps);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1899,6 +1970,39 @@ static void wait_for_canvas(mcu_canvas_t *canvas)
|
||||
}
|
||||
}
|
||||
|
||||
static void personal_attach(mcu_layer_t *layer, conference_member_t *member)
|
||||
{
|
||||
layer->tagged = 1;
|
||||
|
||||
if (layer->member_id != (int)member->id) {
|
||||
const char *var = NULL;
|
||||
|
||||
layer->mute_patched = 0;
|
||||
layer->avatar_patched = 0;
|
||||
switch_img_free(&layer->banner_img);
|
||||
switch_img_free(&layer->logo_img);
|
||||
|
||||
if (layer->geometry.audio_position) {
|
||||
conference_api_sub_position(member, NULL, layer->geometry.audio_position);
|
||||
}
|
||||
|
||||
var = NULL;
|
||||
if (member->video_banner_text ||
|
||||
(var = switch_channel_get_variable_dup(member->channel, "video_banner_text", SWITCH_FALSE, -1))) {
|
||||
conference_video_layer_set_banner(member, layer, var);
|
||||
}
|
||||
|
||||
var = NULL;
|
||||
if (member->video_logo ||
|
||||
(var = switch_channel_get_variable_dup(member->channel, "video_logo_path", SWITCH_FALSE, -1))) {
|
||||
conference_video_layer_set_logo(member, layer, var);
|
||||
}
|
||||
}
|
||||
|
||||
layer->member_id = member->id;
|
||||
}
|
||||
|
||||
|
||||
void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
|
||||
{
|
||||
mcu_canvas_t *canvas = (mcu_canvas_t *) obj;
|
||||
@ -2113,7 +2217,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
}
|
||||
|
||||
//VIDFLOOR
|
||||
if (conference->canvas_count == 1 && canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder &&
|
||||
if (canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder &&
|
||||
imember->video_layer_id != canvas->layout_floor_id) {
|
||||
conference_video_attach_video_layer(imember, canvas, canvas->layout_floor_id);
|
||||
}
|
||||
@ -2128,7 +2232,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
//printf("MEMBER %d layer_id %d canvas: %d/%d\n", imember->id, imember->video_layer_id,
|
||||
// canvas->layers_used, canvas->total_layers);
|
||||
|
||||
switch_mutex_lock(conference->canvas_mutex);
|
||||
if (imember->video_layer_id > -1) {
|
||||
layer = &canvas->layers[imember->video_layer_id];
|
||||
if (layer->member_id != (int)imember->id) {
|
||||
@ -2137,8 +2240,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
imember->layer_timeout = DEFAULT_LAYER_TIMEOUT;
|
||||
}
|
||||
}
|
||||
switch_mutex_unlock(conference->canvas_mutex);
|
||||
|
||||
|
||||
if (imember->avatar_png_img) {
|
||||
if (layer) {
|
||||
@ -2285,6 +2386,10 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
|
||||
if (total < 1) total = 1;
|
||||
|
||||
if (conference->members_with_video == 1 && file_count) {
|
||||
total = 0;
|
||||
}
|
||||
|
||||
if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) {
|
||||
if ((vlayout = conference_video_find_best_layout(conference, lg, total + file_count))) {
|
||||
conference_video_init_canvas_layers(conference, imember->canvas, vlayout);
|
||||
@ -2322,52 +2427,69 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
int i = 0;
|
||||
|
||||
mcu_layer_t *floor_layer = NULL;
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) ||
|
||||
switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
|
||||
i = 0;
|
||||
while (i < imember->canvas->total_layers) {
|
||||
layer = &imember->canvas->layers[i++];
|
||||
switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &layer->canvas->bgcolor);
|
||||
}
|
||||
i = 0;
|
||||
|
||||
if (!file_count && imember->canvas->layout_floor_id > -1 && imember->conference->video_floor_holder &&
|
||||
imember->id != imember->conference->video_floor_holder) {
|
||||
|
||||
if ((omember = conference_member_get(imember->conference, imember->conference->video_floor_holder))) {
|
||||
if (conference->members_with_video + conference->members_with_avatar == 1 || imember != omember) {
|
||||
layer = &imember->canvas->layers[imember->canvas->layout_floor_id];
|
||||
floor_layer = layer;
|
||||
layer = NULL;
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(omember->rwlock);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
for (omember = conference->members; omember; omember = omember->next) {
|
||||
mcu_layer_t *layer = NULL;
|
||||
switch_image_t *use_img = NULL;
|
||||
|
||||
if (!omember->session || !switch_channel_test_flag(omember->channel, CF_VIDEO) || switch_core_session_media_flow(omember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
if (!omember->session || !switch_channel_test_flag(omember->channel, CF_VIDEO) ||
|
||||
switch_core_session_media_flow(omember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (conference->members_with_video + conference->members_with_avatar != 1 && imember == omember) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (i < imember->canvas->total_layers) {
|
||||
layer = &imember->canvas->layers[i++];
|
||||
if (layer->member_id != (int)omember->id) {
|
||||
const char *var = NULL;
|
||||
|
||||
layer->mute_patched = 0;
|
||||
layer->avatar_patched = 0;
|
||||
switch_img_free(&layer->banner_img);
|
||||
switch_img_free(&layer->logo_img);
|
||||
|
||||
if (layer->geometry.audio_position) {
|
||||
conference_api_sub_position(omember, NULL, layer->geometry.audio_position);
|
||||
}
|
||||
|
||||
var = NULL;
|
||||
if (omember->video_banner_text ||
|
||||
(var = switch_channel_get_variable_dup(omember->channel, "video_banner_text", SWITCH_FALSE, -1))) {
|
||||
conference_video_layer_set_banner(omember, layer, var);
|
||||
}
|
||||
|
||||
var = NULL;
|
||||
if (omember->video_logo ||
|
||||
(var = switch_channel_get_variable_dup(omember->channel, "video_logo_path", SWITCH_FALSE, -1))) {
|
||||
conference_video_layer_set_logo(omember, layer, var);
|
||||
if (file_count && (conference->members_with_video + conference->members_with_avatar == 1)) {
|
||||
floor_layer = NULL;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!file_count && floor_layer && omember->id == conference->video_floor_holder) {
|
||||
layer = floor_layer;
|
||||
} else {
|
||||
if (floor_layer || (file_count && i == imember->canvas->layout_floor_id)) {
|
||||
if ((i+1) < imember->canvas->total_layers) {
|
||||
i++;
|
||||
}
|
||||
}
|
||||
|
||||
if (i < imember->canvas->total_layers) {
|
||||
layer = &imember->canvas->layers[i++];
|
||||
}
|
||||
}
|
||||
|
||||
layer->member_id = omember->id;
|
||||
if (layer) {
|
||||
personal_attach(layer, omember);
|
||||
}
|
||||
|
||||
if (!layer && omember->al) {
|
||||
@ -2375,7 +2497,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
}
|
||||
|
||||
use_img = omember->pcanvas_img;
|
||||
|
||||
|
||||
if (layer) {
|
||||
|
||||
if (use_img && !omember->avatar_png_img) {
|
||||
@ -2418,12 +2540,15 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
for (j = 0; j < file_count; j++) {
|
||||
switch_image_t *img = file_imgs[j];
|
||||
|
||||
if (i < imember->canvas->total_layers) {
|
||||
if (j == 0 && imember->canvas->layout_floor_id > -1) {
|
||||
layer = &imember->canvas->layers[imember->canvas->layout_floor_id];
|
||||
conference_video_scale_and_patch(layer, img, SWITCH_FALSE);
|
||||
} else if (i < imember->canvas->total_layers) {
|
||||
layer = &imember->canvas->layers[i++];
|
||||
conference_video_scale_and_patch(layer, img, SWITCH_FALSE);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch_core_session_rwunlock(imember->session);
|
||||
}
|
||||
|
||||
@ -2601,7 +2726,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch_mutex_lock(conference->member_mutex);
|
||||
for (imember = conference->members; imember; imember = imember->next) {
|
||||
switch_frame_t *dupframe;
|
||||
@ -2613,7 +2738,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
}
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
|
||||
switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY ||
|
||||
switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
|
||||
continue;
|
||||
}
|
||||
@ -2622,6 +2746,12 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
switch_core_session_request_video_refresh(imember->session);
|
||||
}
|
||||
|
||||
if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) {
|
||||
switch_core_session_rwunlock(imember->session);
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (send_keyframe) {
|
||||
switch_core_media_gen_key_frame(imember->session);
|
||||
}
|
||||
@ -2678,6 +2808,8 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr
|
||||
}
|
||||
}
|
||||
|
||||
conference_close_open_files(conference);
|
||||
|
||||
switch_core_timer_destroy(&canvas->timer);
|
||||
conference_video_destroy_canvas(&canvas);
|
||||
|
||||
@ -2954,10 +3086,7 @@ void *SWITCH_THREAD_FUNC conference_video_super_muxing_thread_run(switch_thread_
|
||||
continue;
|
||||
}
|
||||
|
||||
if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) ||
|
||||
switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) {
|
||||
continue;
|
||||
@ -2967,6 +3096,11 @@ void *SWITCH_THREAD_FUNC conference_video_super_muxing_thread_run(switch_thread_
|
||||
switch_core_session_request_video_refresh(imember->session);
|
||||
}
|
||||
|
||||
if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_RECVONLY) {
|
||||
switch_core_session_rwunlock(imember->session);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (send_keyframe) {
|
||||
switch_core_media_gen_key_frame(imember->session);
|
||||
}
|
||||
@ -3099,6 +3233,11 @@ void conference_video_set_floor_holder(conference_obj_t *conference, conference_
|
||||
conference_utils_clear_flag(conference, CFLAG_VID_FLOOR_LOCK);
|
||||
}
|
||||
|
||||
if (member && member->video_reservation_id) {
|
||||
/* no video floor when a reservation id is set */
|
||||
return;
|
||||
}
|
||||
|
||||
if ((!force && conference_utils_test_flag(conference, CFLAG_VID_FLOOR_LOCK))) {
|
||||
return;
|
||||
}
|
||||
@ -3143,11 +3282,16 @@ void conference_video_set_floor_holder(conference_obj_t *conference, conference_
|
||||
}
|
||||
|
||||
//VIDFLOOR
|
||||
if (conference->canvas_count == 1 && member && conference->canvases[0] && conference->canvases[0]->layout_floor_id > -1) {
|
||||
conference_video_attach_video_layer(member, conference->canvases[0], conference->canvases[0]->layout_floor_id);
|
||||
}
|
||||
|
||||
if (member) {
|
||||
mcu_canvas_t *canvas = NULL;
|
||||
|
||||
if ((canvas = conference_video_get_canvas_locked(member))) {
|
||||
if (canvas->layout_floor_id > -1) {
|
||||
conference_video_attach_video_layer(member, canvas, canvas->layout_floor_id);
|
||||
}
|
||||
conference_video_release_canvas(&canvas);
|
||||
}
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Adding video floor %s\n",
|
||||
switch_channel_get_name(member->channel));
|
||||
|
||||
@ -3345,10 +3489,14 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session,
|
||||
if (conference_utils_test_flag(member->conference, CFLAG_VIDEO_MUXING)) {
|
||||
switch_image_t *img_copy = NULL;
|
||||
|
||||
if (frame->img && (member->video_layer_id > -1 || member->canvas) && conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) &&
|
||||
if (frame->img && (member->video_layer_id > -1 || member->canvas) &&
|
||||
conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) &&
|
||||
switch_queue_size(member->video_queue) < member->conference->video_fps.fps * 2 &&
|
||||
!member->conference->playing_video_file) {
|
||||
switch_img_copy(frame->img, &img_copy);
|
||||
switch_queue_push(member->video_queue, img_copy);
|
||||
if (switch_queue_trypush(member->video_queue, img_copy) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_img_free(&img_copy);
|
||||
}
|
||||
}
|
||||
|
||||
switch_thread_rwlock_unlock(member->conference->rwlock);
|
||||
@ -3389,7 +3537,8 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session,
|
||||
conference_member_t *fmember;
|
||||
|
||||
if ((fmember = conference_member_get(member->conference, member->conference->video_floor_holder))) {
|
||||
switch_core_session_write_video_frame(fmember->session, frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
if (!conference_utils_member_test_flag(fmember, MFLAG_RECEIVING_VIDEO))
|
||||
switch_core_session_write_video_frame(fmember->session, frame, SWITCH_IO_FLAG_NONE, 0);
|
||||
switch_thread_rwlock_unlock(fmember->rwlock);
|
||||
}
|
||||
}
|
||||
|
@ -1800,6 +1800,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
goto done;
|
||||
}
|
||||
|
||||
conference->flags[CFLAG_JSON_STATUS] = 1;
|
||||
conference_utils_set_cflags(cflags_str, conference->flags);
|
||||
|
||||
if (locked) {
|
||||
@ -1884,6 +1885,7 @@ SWITCH_STANDARD_APP(conference_function)
|
||||
goto done;
|
||||
}
|
||||
|
||||
conference->flags[CFLAG_JSON_STATUS] = 1;
|
||||
conference_utils_set_cflags(cflags_str, conference->flags);
|
||||
|
||||
if (locked) {
|
||||
@ -2862,7 +2864,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
|
||||
|
||||
if (video_codec_bandwidth) {
|
||||
if (!strcasecmp(video_codec_bandwidth, "auto")) {
|
||||
conference->video_codec_settings.video.bandwidth = switch_calc_bitrate(canvas_w, canvas_h, 2, (int)conference->video_fps.fps);
|
||||
conference->video_codec_settings.video.bandwidth = switch_calc_bitrate(canvas_w, canvas_h, 1, (int)conference->video_fps.fps);
|
||||
} else {
|
||||
conference->video_codec_settings.video.bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth);
|
||||
}
|
||||
|
@ -657,6 +657,8 @@ typedef struct conference_obj {
|
||||
int recording_members;
|
||||
uint32_t video_floor_packets;
|
||||
video_layout_t *new_personal_vlayout;
|
||||
int max_bw_in;
|
||||
int force_bw_in;
|
||||
} conference_obj_t;
|
||||
|
||||
/* Relationship with another member */
|
||||
@ -757,6 +759,9 @@ struct conference_member {
|
||||
switch_media_flow_t video_media_flow;
|
||||
mcu_canvas_t *canvas;
|
||||
switch_image_t *pcanvas_img;
|
||||
int max_bw_in;
|
||||
int force_bw_in;
|
||||
int max_bw_out;
|
||||
};
|
||||
|
||||
typedef enum {
|
||||
@ -860,7 +865,7 @@ void conference_member_add_file_data(conference_member_t *member, int16_t *data,
|
||||
void conference_send_notify(conference_obj_t *conference, const char *status, const char *call_id, switch_bool_t final);
|
||||
switch_status_t conference_file_close(conference_obj_t *conference, conference_file_node_t *node);
|
||||
void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *thread, void *obj);
|
||||
|
||||
switch_status_t conference_close_open_files(conference_obj_t *conference);
|
||||
void conference_al_gen_arc(conference_obj_t *conference, switch_stream_handle_t *stream);
|
||||
void conference_al_process(al_handle_t *al, void *data, switch_size_t datalen, int rate);
|
||||
|
||||
@ -882,7 +887,8 @@ switch_status_t conference_loop_dmachine_dispatcher(switch_ivr_dmachine_match_t
|
||||
|
||||
mcu_layer_t *conference_video_get_layer_locked(conference_member_t *member);
|
||||
void conference_video_release_layer(mcu_layer_t **layer);
|
||||
|
||||
mcu_canvas_t *conference_video_get_canvas_locked(conference_member_t *member);
|
||||
void conference_video_release_canvas(mcu_canvas_t **canvasP);
|
||||
int conference_member_setup_media(conference_member_t *member, conference_obj_t *conference);
|
||||
|
||||
al_handle_t *conference_al_create(switch_memory_pool_t *pool);
|
||||
|
@ -142,7 +142,7 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr)
|
||||
}
|
||||
|
||||
if ( interval ) {
|
||||
limit_key = switch_mprintf("%s_%d", resource, now % interval);
|
||||
limit_key = switch_mprintf("%s_%d", resource, now / interval);
|
||||
} else {
|
||||
limit_key = switch_mprintf("%s", resource);
|
||||
}
|
||||
@ -163,6 +163,7 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr)
|
||||
limit_pvt->resource = switch_core_strdup(session_pool, resource);
|
||||
limit_pvt->limit_key = switch_core_strdup(session_pool, limit_key);
|
||||
limit_pvt->inc = 1;
|
||||
limit_pvt->interval = interval;
|
||||
switch_channel_set_private(channel, "hiredis_limit_pvt", limit_pvt);
|
||||
|
||||
count = atoll(response);
|
||||
@ -184,30 +185,21 @@ SWITCH_LIMIT_INCR(hiredis_limit_incr)
|
||||
SWITCH_LIMIT_RELEASE(hiredis_limit_release)
|
||||
{
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
hiredis_profile_t *profile = switch_core_hash_find(mod_hiredis_globals.profiles, realm);
|
||||
hiredis_profile_t *profile = NULL;
|
||||
char *hashkey = NULL, *response = NULL;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
hiredis_limit_pvt_t *limit_pvt = switch_channel_get_private(channel, "hiredis_limit_pvt");
|
||||
|
||||
if ( !zstr(realm) ) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: realm must be defined\n");
|
||||
switch_goto_status(SWITCH_STATUS_GENERR, done);
|
||||
}
|
||||
|
||||
if ( !profile ) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: Unable to locate profile[%s]\n", realm);
|
||||
switch_goto_status(SWITCH_STATUS_GENERR, done);
|
||||
}
|
||||
|
||||
/* If realm and resource are NULL, then clear all of the limits */
|
||||
if ( !realm && !resource ) {
|
||||
hiredis_limit_pvt_t *tmp = limit_pvt;
|
||||
|
||||
while (tmp) {
|
||||
profile = switch_core_hash_find(mod_hiredis_globals.profiles, limit_pvt->realm);
|
||||
hashkey = switch_mprintf("decr %s", tmp->limit_key);
|
||||
limit_pvt = tmp->next;
|
||||
|
||||
if ( hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS) {
|
||||
if ( limit_pvt && (limit_pvt->interval > 0) && (hiredis_profile_execute_sync(profile, hashkey, &response) != SWITCH_STATUS_SUCCESS)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "hiredis: profile[%s] error executing [%s] because [%s]\n",
|
||||
tmp->realm, hashkey, response);
|
||||
}
|
||||
@ -217,6 +209,7 @@ SWITCH_LIMIT_RELEASE(hiredis_limit_release)
|
||||
switch_safe_free(hashkey);
|
||||
}
|
||||
} else {
|
||||
profile = switch_core_hash_find(mod_hiredis_globals.profiles, limit_pvt->realm);
|
||||
|
||||
hashkey = switch_mprintf("decr %s", limit_pvt->limit_key);
|
||||
|
||||
|
@ -37,6 +37,7 @@ typedef struct hiredis_limit_pvt_s {
|
||||
char *resource;
|
||||
char *limit_key;
|
||||
int inc;
|
||||
int interval;
|
||||
struct hiredis_limit_pvt_s *next;
|
||||
} hiredis_limit_pvt_t;
|
||||
|
||||
|
@ -14,9 +14,9 @@
|
||||
<profile name="s3">
|
||||
<!-- Credentials for AWS account. -->
|
||||
<aws-s3>
|
||||
<!-- 20 character key identifier -->
|
||||
<!-- 20 character key identifier, can override with AWS_ACCESS_KEY_ID environment variable -->
|
||||
<access-key-id><![CDATA[AKIAIOSFODNN7EXAMPLE]]></access-key-id>
|
||||
<!-- 40 character secret -->
|
||||
<!-- 40 character secret, can override with AWS_SECRET_ACCESS_KEY environment variable -->
|
||||
<secret-access-key><![CDATA[wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY]]></secret-access-key>
|
||||
<!--base-url><![CDATA[s3.example.com]]></base-url-->
|
||||
</aws-s3>
|
||||
@ -29,3 +29,4 @@
|
||||
</profiles>
|
||||
|
||||
</configuration>
|
||||
|
||||
|
@ -36,6 +36,8 @@
|
||||
#include <switch_curl.h>
|
||||
#include "aws.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
/* 253 max domain size + '/' + NUL byte */
|
||||
#define DOMAIN_BUF_SIZE 255
|
||||
|
||||
@ -1532,21 +1534,35 @@ static switch_status_t do_config(url_cache_t *cache)
|
||||
char *base_domain = NULL;
|
||||
if (s3) {
|
||||
switch_xml_t base_domain_xml = switch_xml_child(s3, "base-domain");
|
||||
switch_xml_t id = switch_xml_child(s3, "access-key-id");
|
||||
switch_xml_t secret = switch_xml_child(s3, "secret-access-key");
|
||||
if (id && secret) {
|
||||
access_key_id = switch_strip_whitespace(switch_xml_txt(id));
|
||||
secret_access_key = switch_strip_whitespace(switch_xml_txt(secret));
|
||||
if (zstr(access_key_id) || zstr(secret_access_key)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing aws s3 credentials for profile \"%s\"\n", name);
|
||||
switch_safe_free(access_key_id);
|
||||
access_key_id = NULL;
|
||||
switch_safe_free(secret_access_key);
|
||||
secret_access_key = NULL;
|
||||
}
|
||||
|
||||
/* check if environment variables set the keys */
|
||||
access_key_id = getenv("AWS_ACCESS_KEY_ID");
|
||||
secret_access_key = getenv("AWS_SECRET_ACCESS_KEY");
|
||||
if (!zstr(access_key_id) && !zstr(secret_access_key)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Using AWS_ACCESS_KEY_ID and AWS_SECRET_ACCESS_KEY environment variables for s3 access on profile \"%s\"\n", name);
|
||||
access_key_id = strdup(access_key_id);
|
||||
secret_access_key = strdup(secret_access_key);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n");
|
||||
continue;
|
||||
/* use configuration for keys */
|
||||
switch_xml_t id = switch_xml_child(s3, "access-key-id");
|
||||
switch_xml_t secret = switch_xml_child(s3, "secret-access-key");
|
||||
access_key_id = NULL;
|
||||
secret_access_key = NULL;
|
||||
|
||||
if (id && secret) {
|
||||
access_key_id = switch_strip_whitespace(switch_xml_txt(id));
|
||||
secret_access_key = switch_strip_whitespace(switch_xml_txt(secret));
|
||||
if (zstr(access_key_id) || zstr(secret_access_key)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Missing aws s3 credentials for profile \"%s\"\n", name);
|
||||
switch_safe_free(access_key_id);
|
||||
access_key_id = NULL;
|
||||
switch_safe_free(secret_access_key);
|
||||
secret_access_key = NULL;
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "Missing key id or secret\n");
|
||||
continue;
|
||||
}
|
||||
}
|
||||
if (base_domain_xml) {
|
||||
base_domain = switch_strip_whitespace(switch_xml_txt(base_domain_xml));
|
||||
|
@ -84,6 +84,13 @@ static opus_codec_settings_t default_codec_settings_8k = {
|
||||
/*.samplerate*/ 0
|
||||
};
|
||||
|
||||
struct dec_stats {
|
||||
uint32_t fec_counter;
|
||||
uint32_t plc_counter;
|
||||
uint32_t frame_counter;
|
||||
};
|
||||
typedef struct dec_stats dec_stats_t;
|
||||
|
||||
struct opus_context {
|
||||
OpusEncoder *encoder_object;
|
||||
OpusDecoder *decoder_object;
|
||||
@ -95,6 +102,7 @@ struct opus_context {
|
||||
opus_codec_settings_t codec_settings;
|
||||
int look_check;
|
||||
int look_ts;
|
||||
dec_stats_t decoder_stats;
|
||||
};
|
||||
|
||||
struct {
|
||||
@ -328,10 +336,17 @@ static char *gen_fmtp(opus_codec_settings_t *settings, switch_memory_pool_t *poo
|
||||
|
||||
static switch_bool_t switch_opus_has_fec(const uint8_t* payload,int payload_length_bytes)
|
||||
{
|
||||
/* nb_silk_frames: number of silk-frames (10 or 20 ms) in an opus frame: 0, 1, 2 or 3 */
|
||||
/* computed from the 5 MSB (configuration) of the TOC byte (payload[0]) */
|
||||
/* nb_opus_frames: number of opus frames in the packet */
|
||||
/* computed from the 2 LSB (p0p1) of the TOC byte */
|
||||
/* p0p1 = 0 => nb_opus_frames = 1 */
|
||||
/* p0p1 = 1 or 2 => nb_opus_frames = 2 */
|
||||
/* p0p1 = 3 => given by the 6 LSB of payload[1] */
|
||||
|
||||
int nb_silk_frames, nb_opus_frames, n, i;
|
||||
opus_int16 frame_sizes[48];
|
||||
const unsigned char *frame_data[48];
|
||||
int frames;
|
||||
|
||||
if (payload == NULL || payload_length_bytes <= 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "corrupted packet (invalid size)\n");
|
||||
@ -343,7 +358,7 @@ static switch_bool_t switch_opus_has_fec(const uint8_t* payload,int payload_leng
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
if ((nb_opus_frames = opus_packet_parse(payload, payload_length_bytes, NULL, frame_data, frame_sizes, NULL)) < 0 ) {
|
||||
if ((nb_opus_frames = opus_packet_parse(payload, payload_length_bytes, NULL, frame_data, frame_sizes, NULL)) <= 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "OPUS_INVALID_PACKET ! nb_opus_frames: %d\n", nb_opus_frames);
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
@ -355,38 +370,24 @@ static switch_bool_t switch_opus_has_fec(const uint8_t* payload,int payload_leng
|
||||
if(nb_silk_frames == 0) {
|
||||
nb_silk_frames = 1;
|
||||
}
|
||||
if (nb_silk_frames == 1) {
|
||||
for (n = 0; n <= (payload[0]&0x4) ; n++) { /* mono or stereo */
|
||||
if ((nb_silk_frames == 1) && (nb_opus_frames == 1)) {
|
||||
for (n = 0; n <= (payload[0]&0x4) ; n++) { /* mono or stereo: 10,20 ms */
|
||||
if (frame_data[0][0] & (0x80 >> ((n + 1) * (nb_silk_frames + 1) - 1))) {
|
||||
return SWITCH_TRUE; /* 1st 20ms (or 10 ms) frame has FEC */
|
||||
return SWITCH_TRUE; /* frame has FEC */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
opus_int16 LBRR_flag = 0 ;
|
||||
for (i=0 ; i < nb_opus_frames; i++ ) { /* only mono */
|
||||
for (i=0 ; i < nb_opus_frames; i++ ) { /* only mono Opus frames */
|
||||
LBRR_flag = (frame_data[i][0] >> (7 - nb_silk_frames)) & 0x1;
|
||||
if (LBRR_flag) {
|
||||
return SWITCH_TRUE; /* one of the silk frames has FEC */
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
frames = opus_packet_parse(payload, payload_length_bytes, NULL, frame_data, frame_sizes, NULL);
|
||||
|
||||
if (frames < 0) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
if (frame_sizes[0] <= 1) {
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
|
||||
for (n = 0; n <= (payload[0]&0x4);n++) {
|
||||
if (frame_data[0][0] & (0x80 >> ((n + 1) * (frames + 1) - 1))) {
|
||||
return SWITCH_TRUE; /*this works only for 20 ms frames now, it will return VAD for 40 ms or 60 ms*/
|
||||
}
|
||||
}
|
||||
|
||||
return SWITCH_FALSE;
|
||||
}
|
||||
@ -420,21 +421,13 @@ static int switch_opus_get_fec_bitrate(int fs, int loss)
|
||||
|
||||
static switch_status_t switch_opus_info(void * encoded_data, uint32_t len, uint32_t samples_per_second, char *print_text)
|
||||
{
|
||||
/* nb_silk_frames: number of silk-frames (10 or 20 ms) in an opus frame: 0, 1, 2 or 3 */
|
||||
/* computed from the 5 MSB (configuration) of the TOC byte (encoded_data[0]) */
|
||||
/* nb_opus_frames: number of opus frames in the packet */
|
||||
/* computed from the 2 LSB (p0p1) of the TOC byte */
|
||||
/* p0p1 = 0 => nb_opus_frames= 1 */
|
||||
/* p0p1 = 1 or 2 => nb_opus_frames= 2 */
|
||||
/* p0p1 = 3 => given by the 6 LSB of encoded_data[1] */
|
||||
|
||||
int nb_samples, nb_silk_frames, nb_opus_frames, n, i;
|
||||
int nb_samples, nb_opus_frames, nb_channels;
|
||||
int audiobandwidth;
|
||||
char audiobandwidth_str[32] = {0};
|
||||
opus_int16 frame_sizes[48];
|
||||
const unsigned char *frame_data[48];
|
||||
char has_fec = 0;
|
||||
uint8_t * payload = encoded_data ;
|
||||
uint8_t * payload = encoded_data;
|
||||
|
||||
if (!encoded_data) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
@ -446,38 +439,19 @@ static switch_status_t switch_opus_info(void * encoded_data, uint32_t len, uint3
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: OPUS_INVALID_PACKET !\n", print_text);
|
||||
}
|
||||
|
||||
if ((nb_opus_frames = opus_packet_parse(encoded_data, len, NULL, frame_data, frame_sizes, NULL)) < 0 ) {
|
||||
if ((nb_opus_frames = opus_packet_parse(encoded_data, len, NULL, frame_data, frame_sizes, NULL)) <= 0 ) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s: OPUS_INVALID_PACKET ! frames: %d\n", print_text, nb_opus_frames);
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
nb_samples = opus_packet_get_samples_per_frame(encoded_data, samples_per_second) * nb_opus_frames;
|
||||
nb_silk_frames = 0;
|
||||
|
||||
if ((payload[0] >> 3 ) < 12) { /* config in silk-only : NB,MB,WB */
|
||||
nb_silk_frames = (payload[0] >> 3) & 0x3;
|
||||
if(nb_silk_frames == 0) {
|
||||
nb_silk_frames = 1;
|
||||
}
|
||||
if (nb_silk_frames == 1) {
|
||||
for (n = 0; n <= (payload[0]&0x4) ; n++) { /* mono or stereo */
|
||||
if (frame_data[0][0] & (0x80 >> ((n + 1) * (nb_silk_frames + 1) - 1))){
|
||||
has_fec = 1 ; /* 1st 20ms (or 10 ms) frame has fec */
|
||||
}
|
||||
}
|
||||
} else {
|
||||
opus_int16 LBRR_flag = 0 ;
|
||||
for (i=0 ; i < nb_opus_frames; i++ ) { /* only mono */
|
||||
LBRR_flag = (frame_data[i][0] >> (7 - nb_silk_frames)) & 0x1;
|
||||
if (LBRR_flag) {
|
||||
has_fec = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
has_fec = switch_opus_has_fec(payload, len);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: nb_opus_frames [%d] nb_silk_frames [%d] samples [%d] audio bandwidth [%s] bytes [%d] FEC[%s]\n",
|
||||
print_text, nb_opus_frames, nb_silk_frames, nb_samples, audiobandwidth_str, len, has_fec ? "yes" : "no" );
|
||||
nb_channels = opus_packet_get_nb_channels(payload);
|
||||
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s: opus_frames [%d] samples [%d] audio bandwidth [%s] bytes [%d] FEC[%s] channels[%d]\n",
|
||||
print_text, nb_opus_frames, nb_samples, audiobandwidth_str, len, has_fec ? "yes" : "no", nb_channels);
|
||||
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
@ -682,6 +656,11 @@ static switch_status_t switch_opus_destroy(switch_codec_t *codec)
|
||||
|
||||
if (context) {
|
||||
if (context->decoder_object) {
|
||||
switch_core_session_t *session = codec->session;
|
||||
if (session) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG,"Opus decoder stats: Frames[%d] PLC[%d] FEC[%d]\n",
|
||||
context->decoder_stats.frame_counter, context->decoder_stats.plc_counter-context->decoder_stats.fec_counter, context->decoder_stats.fec_counter);
|
||||
}
|
||||
opus_decoder_destroy(context->decoder_object);
|
||||
context->decoder_object = NULL;
|
||||
}
|
||||
@ -832,6 +811,15 @@ static switch_status_t switch_opus_decode(switch_codec_t *codec,
|
||||
!encoded_data ? "PLC correction" : fec ? "FEC correction" : "decode");
|
||||
}
|
||||
|
||||
if (plc) {
|
||||
context->decoder_stats.plc_counter++;
|
||||
}
|
||||
if (fec) {
|
||||
context->decoder_stats.fec_counter++;
|
||||
}
|
||||
/* a frame for which we decode FEC will be counted twice */
|
||||
context->decoder_stats.frame_counter++;
|
||||
|
||||
samples = opus_decode(context->decoder_object, encoded_data, encoded_data_len, decoded_data, frame_size, fec);
|
||||
|
||||
if (samples < 0) {
|
||||
@ -858,8 +846,9 @@ static switch_status_t switch_opus_encode_repacketize(switch_codec_t *codec,
|
||||
int16_t *dec_ptr_buf = decoded_data;
|
||||
/* work inside the available buffer to avoid other buffer allocations. *encoded_data_len will be SWITCH_RECOMMENDED_BUFFER_SIZE */
|
||||
unsigned char *enc_ptr_buf = (unsigned char *)encoded_data + (len / 2);
|
||||
int nb_frames = codec->implementation->microseconds_per_packet / 20000 ; /* requested ptime: 20 ms * nb_frames */
|
||||
int frame_size, i, bytes = 0, want_fec = 0, toggle_fec = 0;
|
||||
uint32_t nb_frames = codec->implementation->microseconds_per_packet / 20000 ; /* requested ptime: 20 ms * nb_frames */
|
||||
uint32_t frame_size, i;
|
||||
int bytes = 0, want_fec = 0, toggle_fec = 0;
|
||||
opus_int32 ret = 0;
|
||||
opus_int32 total_len = 0;
|
||||
switch_status_t status = SWITCH_STATUS_SUCCESS;
|
||||
@ -875,22 +864,28 @@ static switch_status_t switch_opus_encode_repacketize(switch_codec_t *codec,
|
||||
if (codec->implementation->microseconds_per_packet / 1000 == 100) { /* 100 ms = 20 ms * 5 . because there is no 50 ms frame in Opus */
|
||||
nb_frames = 5;
|
||||
}
|
||||
toggle_fec = 1;
|
||||
}
|
||||
frame_size = (decoded_data_len / 2) / nb_frames;
|
||||
if((frame_size * nb_frames) != context->enc_frame_size) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Encoder Error: Decoded Datalen %u Number of frames: %d Encoder frame size: %d\n",decoded_data_len,nb_frames,context->enc_frame_size);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR,"Encoder Error: Decoded Datalen %u Number of frames: %u Encoder frame size: %u\n",decoded_data_len,nb_frames,context->enc_frame_size);
|
||||
switch_goto_status(SWITCH_STATUS_GENERR, end);
|
||||
}
|
||||
opus_repacketizer_init(rp);
|
||||
dec_ptr_buf = (int16_t *)decoded_data;
|
||||
for (i = 0; i < nb_frames; i++) {
|
||||
/* set inband FEC ON or OFF for the next Opus frame */
|
||||
if (i == (nb_frames - 1) && want_fec) {
|
||||
/* When FEC is enabled for Opus frame N, LBRR is stored during regular encoding of */
|
||||
/* this Opus frame N, and this LBRR data will be packed with the regular encoding */
|
||||
/* data of Opus frame N+1. We enable FEC on our last Opus frame which is to be packed, just */
|
||||
/* to actually have it stored in the first Opus frame, that is when switch_opus_encode_repacketize() */
|
||||
/* is called again to pack the next big 80,100 or 120 ms frame. */
|
||||
toggle_fec = 1; /* FEC ON for the last frame */
|
||||
}
|
||||
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(toggle_fec));
|
||||
bytes = opus_encode(context->encoder_object, (opus_int16 *) dec_ptr_buf, frame_size, enc_ptr_buf, len);
|
||||
/* set inband FEC off for the next frame to be packed, the current frame may contain FEC */
|
||||
if (toggle_fec == 1) {
|
||||
toggle_fec = 0;
|
||||
opus_encoder_ctl(context->encoder_object, OPUS_SET_INBAND_FEC(toggle_fec));
|
||||
}
|
||||
|
||||
if (bytes < 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Encoder Error: %s Decoded Datalen %u Codec NumberChans %u" \
|
||||
"Len %u DecodedDate %p EncodedData %p ContextEncoderObject %p enc_frame_size: %d\n",
|
||||
@ -975,7 +970,7 @@ static switch_status_t opus_load_config(switch_bool_t reload)
|
||||
opus_prefs.use_jb_lookahead = switch_true(val);
|
||||
} else if (!strcasecmp(key, "keep-fec-enabled")) { /* encoder */
|
||||
opus_prefs.keep_fec = atoi(val);
|
||||
} else if (!strcasecmp(key, "advertise_useinbandfec")) { /*decoder, has meaning only for FMTP: useinbandfec=1 by default */
|
||||
} else if (!strcasecmp(key, "advertise-useinbandfec")) { /*decoder, has meaning only for FMTP: useinbandfec=1 by default */
|
||||
opus_prefs.fec_decode = atoi(val);
|
||||
} else if (!strcasecmp(key, "maxaveragebitrate")) {
|
||||
opus_prefs.maxaveragebitrate = atoi(val);
|
||||
@ -1080,13 +1075,13 @@ static switch_status_t switch_opus_control(switch_codec_t *codec,
|
||||
switch(cmd) {
|
||||
case SCC_CODEC_SPECIFIC:
|
||||
{
|
||||
const char *cmd = (const char *)cmd_data;
|
||||
const char *command = (const char *)cmd_data;
|
||||
const char *arg = (const char *)cmd_arg;
|
||||
switch_codec_control_type_t reply_type = SCCT_STRING;
|
||||
const char *reply = "ERROR INVALID COMMAND";
|
||||
|
||||
if (!zstr(cmd)) {
|
||||
if (!strcasecmp(cmd, "jb_lookahead")) {
|
||||
if (!zstr(command)) {
|
||||
if (!strcasecmp(command, "jb_lookahead")) {
|
||||
if (!zstr(arg)) {
|
||||
context->use_jb_lookahead = switch_true(arg);
|
||||
}
|
||||
|
@ -227,6 +227,7 @@ struct vpx_context {
|
||||
uint8_t decoder_init;
|
||||
switch_buffer_t *vpx_packet_buffer;
|
||||
int got_key_frame;
|
||||
int no_key_frame;
|
||||
int got_start_frame;
|
||||
uint32_t last_received_timestamp;
|
||||
switch_bool_t last_received_complete_picture;
|
||||
@ -273,6 +274,7 @@ static switch_status_t init_decoder(switch_codec_t *codec)
|
||||
context->last_received_complete_picture = 0;
|
||||
context->decoder_init = 1;
|
||||
context->got_key_frame = 0;
|
||||
context->no_key_frame = 0;
|
||||
context->got_start_frame = 0;
|
||||
// the types of post processing to be done, should be combination of "vp8_postproc_level"
|
||||
ppcfg.post_proc_flag = VP8_DEBLOCK;//VP8_DEMACROBLOCK | VP8_DEBLOCK;
|
||||
@ -298,7 +300,8 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||
vpx_codec_enc_cfg_t *config = &context->config;
|
||||
int token_parts = 1;
|
||||
int cpus = switch_core_cpu_count();
|
||||
|
||||
int sane;
|
||||
|
||||
if (!context->codec_settings.video.width) {
|
||||
context->codec_settings.video.width = 1280;
|
||||
}
|
||||
@ -310,15 +313,19 @@ static switch_status_t init_encoder(switch_codec_t *codec)
|
||||
if (context->codec_settings.video.bandwidth == -1) {
|
||||
context->codec_settings.video.bandwidth = 0;
|
||||
}
|
||||
|
||||
|
||||
if (context->codec_settings.video.bandwidth) {
|
||||
context->bandwidth = context->codec_settings.video.bandwidth;
|
||||
} else {
|
||||
context->bandwidth = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 0, 0);
|
||||
|
||||
}
|
||||
|
||||
if (context->bandwidth > 40960) {
|
||||
context->bandwidth = 40960;
|
||||
sane = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 4, 30);
|
||||
|
||||
if (context->bandwidth > sane) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "BITRATE TRUNCATED TO %d\n", sane);
|
||||
context->bandwidth = sane;
|
||||
}
|
||||
|
||||
context->pkt = NULL;
|
||||
@ -812,7 +819,18 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
|
||||
is_start = (*(unsigned char *)frame->data & 0x10);
|
||||
is_keyframe = IS_VP8_KEY_FRAME((uint8_t *)frame->data);
|
||||
}
|
||||
|
||||
|
||||
|
||||
if (context->got_key_frame <= 0) {
|
||||
context->no_key_frame++;
|
||||
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no keyframe, %d\n", context->no_key_frame);
|
||||
if (context->no_key_frame > 50) {
|
||||
if ((is_keyframe = is_start)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "no keyframe, treating start as key.\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// if (is_keyframe) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "got key %d\n", is_keyframe);
|
||||
|
||||
if (context->need_decoder_reset != 0) {
|
||||
@ -845,9 +863,7 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
|
||||
if (is_keyframe) {
|
||||
if (context->got_key_frame <= 0) {
|
||||
context->got_key_frame = 1;
|
||||
if (!is_keyframe) {
|
||||
get_refresh = 1;
|
||||
}
|
||||
context->no_key_frame = 0;
|
||||
} else {
|
||||
context->got_key_frame++;
|
||||
}
|
||||
@ -855,6 +871,9 @@ static switch_status_t switch_vpx_decode(switch_codec_t *codec, switch_frame_t *
|
||||
if ((--context->got_key_frame % 200) == 0) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Waiting for key frame %d\n", context->got_key_frame);
|
||||
}
|
||||
|
||||
get_refresh = 1;
|
||||
|
||||
if (!context->got_start_frame) {
|
||||
switch_goto_status(SWITCH_STATUS_MORE_DATA, end);
|
||||
}
|
||||
|
@ -136,7 +136,7 @@ again:
|
||||
break;
|
||||
}
|
||||
|
||||
if (*len != orig_len) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "sent %ld of %ld\n", *len, orig_len);
|
||||
if (*len != orig_len) switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "sent %"SWITCH_SIZE_T_FMT" of %"SWITCH_SIZE_T_FMT"\n", *len, orig_len);
|
||||
buf += *len;
|
||||
remaining -= *len;
|
||||
*len = remaining;
|
||||
|
@ -130,9 +130,12 @@
|
||||
</ItemDefinitionGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="mod_skypopen.c">
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/analyze:stacksize65535</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/analyze:stacksize65535</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/analyze:stacksize65535</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</AdditionalOptions>
|
||||
</ClCompile>
|
||||
@ -141,9 +144,12 @@
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">4305;4306;28193;4244;4267;4324;6340;6246;6011;6387;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">4305;4306;28193;4244;4267;4324;6340;6246;6011;6387;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<DisableSpecificWarnings Condition="'$(Configuration)|$(Platform)'=='Release|x64'">4305;4306;28193;4244;4267;4324;6340;6246;6011;6387;%(DisableSpecificWarnings)</DisableSpecificWarnings>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">/analyze:stacksize32768</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">/analyze:stacksize32768</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">/analyze:stacksize32768</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|Win32'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Debug|x64'">
|
||||
</AdditionalOptions>
|
||||
<AdditionalOptions Condition="'$(Configuration)|$(Platform)'=='Release|x64'">
|
||||
</AdditionalOptions>
|
||||
</ClCompile>
|
||||
|
@ -2162,11 +2162,19 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
const char *call_info = switch_channel_get_variable(channel, "presence_call_info_full");
|
||||
const char *b_sdp = NULL;
|
||||
int is_proxy = 0, is_3pcc = 0;
|
||||
int send_sip_code = 183;
|
||||
const char * p_send_sip_msg = sip_183_Session_progress;
|
||||
|
||||
b_sdp = switch_channel_get_variable(channel, SWITCH_B_SDP_VARIABLE);
|
||||
is_proxy = (switch_channel_test_flag(channel, CF_PROXY_MODE) || switch_channel_test_flag(channel, CF_PROXY_MEDIA));
|
||||
is_3pcc = (sofia_test_pflag(tech_pvt->profile, PFLAG_3PCC_PROXY) && sofia_test_flag(tech_pvt, TFLAG_3PCC));
|
||||
|
||||
// send 180 instead of 183 if variable "early_use_180" is "true"
|
||||
if (switch_true(switch_channel_get_variable(channel, "early_use_180"))) {
|
||||
send_sip_code = 180;
|
||||
p_send_sip_msg = sip_180_Ringing;
|
||||
}
|
||||
|
||||
if (b_sdp && is_proxy && !is_3pcc) {
|
||||
switch_core_media_set_local_sdp(session, b_sdp, SWITCH_TRUE);
|
||||
|
||||
@ -2205,7 +2213,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
char *extra_headers = sofia_glue_get_extra_headers(channel, SOFIA_SIP_PROGRESS_HEADER_PREFIX);
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
|
||||
nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS,
|
||||
nua_respond(tech_pvt->nh, send_sip_code, p_send_sip_msg,
|
||||
TAG_IF(is_proxy, NUTAG_AUTOANSWER(0)),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->profile->url),
|
||||
SOATAG_USER_SDP_STR(tech_pvt->mparams.local_sdp_str),
|
||||
@ -2217,7 +2225,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
TAG_IF(switch_stristr("update_display", tech_pvt->x_freeswitch_support_remote),
|
||||
SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
|
||||
} else {
|
||||
nua_respond(tech_pvt->nh, SIP_183_SESSION_PROGRESS,
|
||||
nua_respond(tech_pvt->nh, send_sip_code, p_send_sip_msg,
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
SIPTAG_CONTACT_STR(tech_pvt->profile->url),
|
||||
TAG_IF(!zstr(extra_headers), SIPTAG_HEADER_STR(extra_headers)),
|
||||
@ -2341,7 +2349,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
|
||||
if (sofia_use_soa(tech_pvt)) {
|
||||
nua_respond(tech_pvt->nh,
|
||||
SIP_183_SESSION_PROGRESS,
|
||||
send_sip_code, p_send_sip_msg,
|
||||
NUTAG_AUTOANSWER(0),
|
||||
TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
|
||||
TAG_IF(cid, SIPTAG_HEADER_STR(cid)),
|
||||
@ -2356,7 +2364,7 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi
|
||||
SIPTAG_HEADER_STR("X-FS-Support: " FREESWITCH_SUPPORT)), TAG_END());
|
||||
} else {
|
||||
nua_respond(tech_pvt->nh,
|
||||
SIP_183_SESSION_PROGRESS,
|
||||
send_sip_code, p_send_sip_msg,
|
||||
NUTAG_AUTOANSWER(0),
|
||||
NUTAG_MEDIA_ENABLE(0),
|
||||
TAG_IF(sticky, NUTAG_PROXY(tech_pvt->record_route)),
|
||||
|
@ -5850,7 +5850,7 @@ static void sofia_handle_sip_r_options(switch_core_session_t *session, int statu
|
||||
int ping_time = 0;
|
||||
|
||||
if (sofia_private && sofia_private->ping_sent) {
|
||||
ping_time = switch_time_now() - sofia_private->ping_sent;
|
||||
ping_time = (int)(switch_time_now() - sofia_private->ping_sent);
|
||||
}
|
||||
|
||||
sip_user_status.status = ping_status;
|
||||
@ -8894,6 +8894,7 @@ void sofia_handle_sip_i_info(nua_t *nua, sofia_profile_t *profile, nua_handle_t
|
||||
switch_core_session_t *other_session;
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO)) {
|
||||
switch_core_media_gen_key_frame(session);
|
||||
if (switch_core_session_get_partner(session, &other_session) == SWITCH_STATUS_SUCCESS) {
|
||||
sofia_glue_build_vid_refresh_message(other_session, sip->sip_payload->pl_data);
|
||||
switch_core_session_rwunlock(other_session);
|
||||
|
@ -1234,6 +1234,12 @@ static void detach_calls(jsock_t *jsock)
|
||||
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(tech_pvt->channel, CF_VIDEO_ONLY)) {
|
||||
switch_channel_hangup(tech_pvt->channel, SWITCH_CAUSE_NORMAL_CLEARING);
|
||||
continue;
|
||||
}
|
||||
|
||||
switch_core_session_stop_media(tech_pvt->session);
|
||||
tech_pvt->detach_time = switch_epoch_time_now(NULL);
|
||||
globals.detached++;
|
||||
@ -1844,15 +1850,79 @@ static void client_run(jsock_t *jsock)
|
||||
switch_ssize_t bytes;
|
||||
ws_opcode_t oc;
|
||||
uint8_t *data;
|
||||
|
||||
|
||||
bytes = ws_read_frame(&jsock->ws, &oc, &data);
|
||||
|
||||
|
||||
if (bytes < 0) {
|
||||
die("BAD READ %" SWITCH_SSIZE_T_FMT "\n", bytes);
|
||||
break;
|
||||
}
|
||||
|
||||
if (bytes) {
|
||||
char *s = (char *) data;
|
||||
|
||||
if (*s == '#') {
|
||||
char repl[2048] = "";
|
||||
switch_time_t a, b;
|
||||
|
||||
if (s[1] == 'S' && s[2] == 'P') {
|
||||
|
||||
if (s[3] == 'U') {
|
||||
int i, size = 0;
|
||||
char *p = s+4;
|
||||
int loops = 0;
|
||||
int rem = 0;
|
||||
int dur = 0, j = 0;
|
||||
|
||||
if (!(size = atoi(p))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
a = switch_time_now();
|
||||
do {
|
||||
bytes = ws_read_frame(&jsock->ws, &oc, &data);
|
||||
s = (char *) data;
|
||||
} while (bytes && data && s[0] == '#' && s[3] == 'B');
|
||||
b = switch_time_now();
|
||||
|
||||
if (!bytes || !data) continue;
|
||||
|
||||
if (s[0] != '#') goto nm;
|
||||
|
||||
switch_snprintf(repl, sizeof(repl), "#SPU %ld", (b - a) / 1000);
|
||||
ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
|
||||
loops = size / 1024;
|
||||
rem = size % 1024;
|
||||
switch_snprintf(repl, sizeof(repl), "#SPB ");
|
||||
memset(repl+4, '.', 1024);
|
||||
|
||||
for (j = 0; j < 10 ; j++) {
|
||||
int ddur = 0;
|
||||
a = switch_time_now();
|
||||
for (i = 0; i < loops; i++) {
|
||||
ws_write_frame(&jsock->ws, WSOC_TEXT, repl, 1024);
|
||||
}
|
||||
if (rem) {
|
||||
ws_write_frame(&jsock->ws, WSOC_TEXT, repl, rem);
|
||||
}
|
||||
b = switch_time_now();
|
||||
ddur += ((b - a) / 1000);
|
||||
dur += ddur;
|
||||
|
||||
}
|
||||
|
||||
dur /= j+1;
|
||||
|
||||
switch_snprintf(repl, sizeof(repl), "#SPD %d", dur);
|
||||
ws_write_frame(&jsock->ws, WSOC_TEXT, repl, strlen(repl));
|
||||
}
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
nm:
|
||||
|
||||
if (process_input(jsock, data, bytes) != SWITCH_STATUS_SUCCESS) {
|
||||
die("Input Error\n");
|
||||
}
|
||||
@ -2485,6 +2555,10 @@ static int verto_recover_callback(switch_core_session_t *session)
|
||||
const char *profile_name = NULL, *jsock_uuid_str = NULL;
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
|
||||
if (switch_channel_test_flag(channel, CF_VIDEO_ONLY)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
PROTECT_INTERFACE(verto_endpoint_interface);
|
||||
|
||||
profile_name = switch_channel_get_variable(channel, "verto_profile_name");
|
||||
@ -3271,7 +3345,7 @@ static switch_bool_t verto__info_func(const char *method, cJSON *params, jsock_t
|
||||
|
||||
static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
|
||||
{
|
||||
cJSON *obj = cJSON_CreateObject(), *screenShare = NULL, *dedEnc = NULL, *mirrorInput, *json_ptr = NULL;
|
||||
cJSON *obj = cJSON_CreateObject(), *screenShare = NULL, *dedEnc = NULL, *mirrorInput, *json_ptr = NULL, *bandwidth = NULL;
|
||||
switch_core_session_t *session = NULL;
|
||||
switch_channel_t *channel;
|
||||
switch_event_t *var_event;
|
||||
@ -3281,7 +3355,7 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock
|
||||
cJSON *dialog;
|
||||
verto_pvt_t *tech_pvt;
|
||||
char name[512];
|
||||
const char *var, *destination_number, *call_id = NULL, *sdp = NULL, *bandwidth = NULL,
|
||||
const char *var, *destination_number, *call_id = NULL, *sdp = NULL,
|
||||
*caller_id_name = NULL, *caller_id_number = NULL, *remote_caller_id_name = NULL, *remote_caller_id_number = NULL,*context = NULL;
|
||||
switch_event_header_t *hp;
|
||||
|
||||
@ -3341,6 +3415,7 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock
|
||||
}
|
||||
|
||||
if ((screenShare = cJSON_GetObjectItem(dialog, "screenShare")) && screenShare->type == cJSON_True) {
|
||||
switch_channel_set_variable(channel, "video_screen_share", "true");
|
||||
switch_channel_set_flag(channel, CF_VIDEO_ONLY);
|
||||
}
|
||||
|
||||
@ -3353,15 +3428,41 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock
|
||||
switch_channel_set_flag(channel, CF_VIDEO_MIRROR_INPUT);
|
||||
}
|
||||
|
||||
if ((bandwidth = cJSON_GetObjectCstr(dialog, "outgoingBandwidth"))) {
|
||||
if (strcasecmp(bandwidth, "default")) {
|
||||
switch_channel_set_variable(channel, "rtp_video_max_bandwidth_in", bandwidth);
|
||||
if ((bandwidth = cJSON_GetObjectItem(dialog, "outgoingBandwidth"))) {
|
||||
int core_bw = 0, bwval = 0;
|
||||
const char *val;
|
||||
|
||||
if ((val = switch_channel_get_variable_dup(channel, "rtp_video_max_bandwidth_in", SWITCH_FALSE, -1))) {
|
||||
core_bw = switch_parse_bandwidth_string(val);
|
||||
}
|
||||
|
||||
if (!zstr(bandwidth->valuestring) && strcasecmp(bandwidth->valuestring, "default")) {
|
||||
bwval = atoi(bandwidth->valuestring);
|
||||
} else if (bandwidth->valueint) {
|
||||
bwval = bandwidth->valueint;
|
||||
}
|
||||
|
||||
if (bwval <= 0 || (core_bw && bwval < core_bw)) {
|
||||
switch_channel_set_variable_printf(channel, "rtp_video_max_bandwidth_in", "%d", bwval);
|
||||
}
|
||||
}
|
||||
|
||||
if ((bandwidth = cJSON_GetObjectCstr(dialog, "incomingBandwidth"))) {
|
||||
if (strcasecmp(bandwidth, "default")) {
|
||||
switch_channel_set_variable(channel, "rtp_video_max_bandwidth_out", bandwidth);
|
||||
if ((bandwidth = cJSON_GetObjectItem(dialog, "incomingBandwidth"))) {
|
||||
int core_bw = 0, bwval = 0;
|
||||
const char *val;
|
||||
|
||||
if ((val = switch_channel_get_variable_dup(channel, "rtp_video_max_bandwidth_out", SWITCH_FALSE, -1))) {
|
||||
core_bw = switch_parse_bandwidth_string(val);
|
||||
}
|
||||
|
||||
if (!zstr(bandwidth->valuestring) && strcasecmp(bandwidth->valuestring, "default")) {
|
||||
bwval = atoi(bandwidth->valuestring);
|
||||
} else if (bandwidth->valueint) {
|
||||
bwval = bandwidth->valueint;
|
||||
}
|
||||
|
||||
if (bwval <= 0 || (core_bw && bwval < core_bw)) {
|
||||
switch_channel_set_variable_printf(channel, "rtp_video_max_bandwidth_out", "%d", bwval);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,7 @@ int ws_handshake(wsh_t *wsh)
|
||||
}
|
||||
}
|
||||
|
||||
if (bytes > sizeof(wsh->buffer) -1) {
|
||||
if (bytes > wsh->buflen -1) {
|
||||
goto err;
|
||||
}
|
||||
|
||||
@ -362,7 +362,7 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
|
||||
}
|
||||
}
|
||||
|
||||
} while (r == -1 && err == SSL_ERROR_WANT_READ && wsh->x < 100);
|
||||
} while (r == -1 && err == SSL_ERROR_WANT_READ && wsh->x < 1000);
|
||||
|
||||
goto end;
|
||||
}
|
||||
@ -382,7 +382,7 @@ ssize_t ws_raw_read(wsh_t *wsh, void *data, size_t bytes, int block)
|
||||
ms_sleep(10);
|
||||
}
|
||||
}
|
||||
} while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 100);
|
||||
} while (r == -1 && xp_is_blocking(xp_errno()) && wsh->x < 1000);
|
||||
|
||||
if (wsh->x >= 1000 || (block && wsh->x >= 100)) {
|
||||
r = -1;
|
||||
@ -596,7 +596,15 @@ int ws_init(wsh_t *wsh, ws_socket_t sock, SSL_CTX *ssl_ctx, int close_sock, int
|
||||
wsh->close_sock = 1;
|
||||
}
|
||||
|
||||
wsh->buflen = sizeof(wsh->buffer);
|
||||
wsh->buflen = 1024 * 64;
|
||||
wsh->bbuflen = wsh->buflen;
|
||||
|
||||
wsh->buffer = malloc(wsh->buflen);
|
||||
wsh->bbuffer = malloc(wsh->bbuflen);
|
||||
//printf("init %p %ld\n", (void *) wsh->bbuffer, wsh->bbuflen);
|
||||
//memset(wsh->buffer, 0, wsh->buflen);
|
||||
//memset(wsh->bbuffer, 0, wsh->bbuflen);
|
||||
|
||||
wsh->secure = ssl_ctx ? 1 : 0;
|
||||
|
||||
setup_socket(sock);
|
||||
@ -644,6 +652,12 @@ void ws_destroy(wsh_t *wsh)
|
||||
SSL_free(wsh->ssl);
|
||||
wsh->ssl = NULL;
|
||||
}
|
||||
|
||||
if (wsh->buffer) free(wsh->buffer);
|
||||
if (wsh->bbuffer) free(wsh->bbuffer);
|
||||
|
||||
wsh->buffer = wsh->bbuffer = NULL;
|
||||
|
||||
}
|
||||
|
||||
ssize_t ws_close(wsh_t *wsh, int16_t reason)
|
||||
@ -685,6 +699,20 @@ ssize_t ws_close(wsh_t *wsh, int16_t reason)
|
||||
|
||||
}
|
||||
|
||||
|
||||
uint64_t hton64(uint64_t val)
|
||||
{
|
||||
if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
|
||||
else return __bswap_64(val);
|
||||
}
|
||||
|
||||
uint64_t ntoh64(uint64_t val)
|
||||
{
|
||||
if (__BYTE_ORDER == __BIG_ENDIAN) return (val);
|
||||
else return __bswap_64(val);
|
||||
}
|
||||
|
||||
|
||||
ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
{
|
||||
|
||||
@ -692,6 +720,10 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
char *maskp;
|
||||
int ll = 0;
|
||||
int frag = 0;
|
||||
int blen;
|
||||
|
||||
wsh->body = wsh->bbuffer;
|
||||
wsh->packetlen = 0;
|
||||
|
||||
again:
|
||||
need = 2;
|
||||
@ -745,12 +777,11 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
int fin = (wsh->buffer[0] >> 7) & 1;
|
||||
int mask = (wsh->buffer[1] >> 7) & 1;
|
||||
|
||||
if (fin) {
|
||||
if (*oc == WSOC_CONTINUATION) {
|
||||
frag = 1;
|
||||
} else {
|
||||
frag = 0;
|
||||
}
|
||||
|
||||
if (!fin && *oc != WSOC_CONTINUATION) {
|
||||
frag = 1;
|
||||
} else if (fin && *oc == WSOC_CONTINUATION) {
|
||||
frag = 0;
|
||||
}
|
||||
|
||||
if (mask) {
|
||||
@ -765,23 +796,33 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
|
||||
wsh->plen = wsh->buffer[1] & 0x7f;
|
||||
wsh->payload = &wsh->buffer[2];
|
||||
|
||||
|
||||
if (wsh->plen == 127) {
|
||||
uint64_t *u64;
|
||||
int more = 0;
|
||||
|
||||
need += 8;
|
||||
|
||||
if (need > wsh->datalen) {
|
||||
/* too small - protocol err */
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
}
|
||||
//*oc = WSOC_CLOSE;
|
||||
//return ws_close(wsh, WS_PROTO_ERR);
|
||||
|
||||
more = ws_raw_read(wsh, wsh->buffer + wsh->datalen, need - wsh->datalen, WS_BLOCK);
|
||||
|
||||
if (more < need - wsh->datalen) {
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
} else {
|
||||
wsh->datalen += more;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
u64 = (uint64_t *) wsh->payload;
|
||||
wsh->payload += 8;
|
||||
|
||||
wsh->plen = ntohl((u_long)*u64);
|
||||
|
||||
wsh->plen = ntoh64(*u64);
|
||||
} else if (wsh->plen == 126) {
|
||||
uint16_t *u16;
|
||||
|
||||
@ -811,16 +852,30 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
return ws_close(wsh, WS_PROTO_ERR);
|
||||
}
|
||||
|
||||
if ((need + wsh->datalen) > (ssize_t)wsh->buflen) {
|
||||
/* too big - Ain't nobody got time fo' dat */
|
||||
*oc = WSOC_CLOSE;
|
||||
return ws_close(wsh, WS_DATA_TOO_BIG);
|
||||
blen = wsh->body - wsh->bbuffer;
|
||||
|
||||
if (need + blen > (ssize_t)wsh->bbuflen) {
|
||||
void *tmp;
|
||||
|
||||
wsh->bbuflen = need + blen + wsh->rplen;
|
||||
|
||||
if ((tmp = realloc(wsh->bbuffer, wsh->bbuflen))) {
|
||||
wsh->bbuffer = tmp;
|
||||
} else {
|
||||
abort();
|
||||
}
|
||||
|
||||
wsh->body = wsh->bbuffer + blen;
|
||||
}
|
||||
|
||||
wsh->rplen = wsh->plen - need;
|
||||
|
||||
|
||||
if (wsh->rplen) {
|
||||
memcpy(wsh->body, wsh->payload, wsh->rplen);
|
||||
}
|
||||
|
||||
while(need) {
|
||||
ssize_t r = ws_raw_read(wsh, wsh->payload + wsh->rplen, need, WS_BLOCK);
|
||||
ssize_t r = ws_raw_read(wsh, wsh->body + wsh->rplen, need, WS_BLOCK);
|
||||
|
||||
if (r < 1) {
|
||||
/* invalid read - protocol err .. */
|
||||
@ -837,28 +892,30 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
ssize_t i;
|
||||
|
||||
for (i = 0; i < wsh->datalen; i++) {
|
||||
wsh->payload[i] ^= maskp[i % 4];
|
||||
wsh->body[i] ^= maskp[i % 4];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (*oc == WSOC_PING) {
|
||||
ws_write_frame(wsh, WSOC_PONG, wsh->payload, wsh->rplen);
|
||||
ws_write_frame(wsh, WSOC_PONG, wsh->body, wsh->rplen);
|
||||
goto again;
|
||||
}
|
||||
|
||||
*(wsh->body+wsh->rplen) = '\0';
|
||||
wsh->packetlen += wsh->rplen;
|
||||
wsh->body += wsh->rplen;
|
||||
|
||||
if (frag) {
|
||||
goto again;
|
||||
}
|
||||
|
||||
*data = (uint8_t *)wsh->bbuffer;
|
||||
|
||||
|
||||
*(wsh->payload+wsh->rplen) = '\0';
|
||||
*data = (uint8_t *)wsh->payload;
|
||||
|
||||
//printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->rplen, *oc, (char *)*data);
|
||||
//printf("READ[%ld][%d]-----------------------------:\n[%s]\n-------------------------------\n", wsh->packetlen, *oc, (char *)*data);
|
||||
|
||||
|
||||
return wsh->rplen;
|
||||
return wsh->packetlen;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
@ -871,6 +928,7 @@ ssize_t ws_read_frame(wsh_t *wsh, ws_opcode_t *oc, uint8_t **data)
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes)
|
||||
{
|
||||
|
||||
@ -885,6 +943,7 @@ ssize_t ws_feed_buf(wsh_t *wsh, void *data, size_t bytes)
|
||||
return bytes;
|
||||
}
|
||||
|
||||
|
||||
ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc)
|
||||
{
|
||||
ssize_t r = 0;
|
||||
@ -899,7 +958,7 @@ ssize_t ws_send_buf(wsh_t *wsh, ws_opcode_t oc)
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
|
||||
{
|
||||
@ -934,7 +993,7 @@ ssize_t ws_write_frame(wsh_t *wsh, ws_opcode_t oc, void *data, size_t bytes)
|
||||
hlen += 8;
|
||||
|
||||
u64 = (uint64_t *) &hdr[2];
|
||||
*u64 = htonl(bytes);
|
||||
*u64 = hton64(bytes);
|
||||
}
|
||||
|
||||
if (wsh->write_buffer_len < (hlen + bytes + 1)) {
|
||||
|
@ -78,15 +78,18 @@ typedef enum {
|
||||
|
||||
typedef struct wsh_s {
|
||||
ws_socket_t sock;
|
||||
char buffer[65536];
|
||||
char wbuffer[65536];
|
||||
char *buffer;
|
||||
char *bbuffer;
|
||||
char *body;
|
||||
char *uri;
|
||||
size_t buflen;
|
||||
size_t bbuflen;
|
||||
ssize_t datalen;
|
||||
ssize_t wdatalen;
|
||||
char *payload;
|
||||
ssize_t plen;
|
||||
ssize_t rplen;
|
||||
ssize_t packetlen;
|
||||
SSL *ssl;
|
||||
int handshake;
|
||||
uint8_t down;
|
||||
|
@ -322,7 +322,7 @@ static switch_status_t my_on_reporting_cb(switch_core_session_t *session, cdr_pr
|
||||
memset(cdr_text_escaped, 0, need_bytes);
|
||||
if (profile->encode == ENCODING_DEFAULT) {
|
||||
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-urlencoded");
|
||||
switch_url_encode(cdr_text, cdr_text_escaped, need_bytes);
|
||||
switch_url_encode_opt(cdr_text, cdr_text_escaped, need_bytes, SWITCH_TRUE);
|
||||
} else {
|
||||
headers = switch_curl_slist_append(headers, "Content-Type: application/x-www-form-base64-encoded");
|
||||
switch_b64_encode((unsigned char *) cdr_text, need_bytes / 3, (unsigned char *) cdr_text_escaped, need_bytes);
|
||||
|
@ -493,7 +493,7 @@ static void *SWITCH_THREAD_FUNC read_stream_thread(switch_thread_t *thread, void
|
||||
break;
|
||||
}
|
||||
|
||||
source->prebuf = source->samples * 2 * source->channels;
|
||||
source->prebuf = (uint32_t)(source->samples * 2 * source->channels);
|
||||
|
||||
if (!source->total) {
|
||||
flush_video_queue(source->video_q);
|
||||
@ -806,8 +806,8 @@ static switch_status_t local_stream_file_read_video(switch_file_handle_t *handle
|
||||
local_stream_context_t *context = handle->private_info;
|
||||
switch_status_t status;
|
||||
switch_time_t now;
|
||||
int fps = (int)ceil(handle->mm.fps);
|
||||
int min_qsize = fps;
|
||||
unsigned int fps = (unsigned int)ceil(handle->mm.fps);
|
||||
unsigned int min_qsize = fps;
|
||||
|
||||
if (!(context->ready && context->source->ready)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
|
@ -1707,6 +1707,7 @@ SWITCH_MODULE_LOAD_FUNCTION(mod_shout_load)
|
||||
|
||||
supported_formats[0] = "shout";
|
||||
supported_formats[1] = "mp3";
|
||||
supported_formats[2] = "mpga";
|
||||
|
||||
/* connect my internal structure to the blank pointer passed to me */
|
||||
*module_interface = switch_loadable_module_create_module_interface(pool, modname);
|
||||
|
@ -88,6 +88,11 @@ void Session::setLUA(lua_State * state)
|
||||
|
||||
int Session::originate(CoreSession *a_leg_session, char *dest, int timeout)
|
||||
{
|
||||
if (zstr(dest)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing destination.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
int x = CoreSession::originate(a_leg_session, dest, timeout);
|
||||
|
||||
if (x) {
|
||||
@ -356,7 +361,7 @@ Dbh::Dbh(char *dsn, char *user, char *pass)
|
||||
dsn = tmp;
|
||||
}
|
||||
|
||||
if (switch_cache_db_get_db_handle_dsn(&dbh, dsn) == SWITCH_STATUS_SUCCESS) {
|
||||
if (!zstr(dsn) && switch_cache_db_get_db_handle_dsn(&dbh, dsn) == SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "DBH handle %p Connected.\n", (void *) dbh);
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Connection failed. DBH NOT Connected.\n");
|
||||
@ -391,8 +396,12 @@ bool Dbh::connected()
|
||||
bool Dbh::test_reactive(char *test_sql, char *drop_sql, char *reactive_sql)
|
||||
{
|
||||
if (dbh) {
|
||||
if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) {
|
||||
return true;
|
||||
if (!zstr(test_sql) && !zstr(reactive_sql)) {
|
||||
if (switch_cache_db_test_reactive(dbh, test_sql, drop_sql, reactive_sql) == SWITCH_TRUE) {
|
||||
return true;
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing parameters.\n");
|
||||
}
|
||||
} else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "DBH NOT Connected.\n");
|
||||
@ -431,6 +440,11 @@ int Dbh::query_callback(void *pArg, int argc, char **argv, char **cargv)
|
||||
|
||||
bool Dbh::query(char *sql, SWIGLUA_FN lua_fun)
|
||||
{
|
||||
if (zstr(sql)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing SQL query.\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (dbh) {
|
||||
if (lua_fun.L) {
|
||||
if (switch_cache_db_execute_sql_callback(dbh, sql, query_callback, &lua_fun, NULL) == SWITCH_STATUS_SUCCESS) {
|
||||
@ -459,6 +473,11 @@ int Dbh::affected_rows()
|
||||
|
||||
int Dbh::load_extension(const char *extension)
|
||||
{
|
||||
if (zstr(extension)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Missing extension name.\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (dbh) {
|
||||
return switch_cache_db_load_extension(dbh, extension);
|
||||
}
|
||||
|
@ -365,6 +365,7 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch
|
||||
char *skip_if_set = (char *) switch_xml_attr(param, "skip_if_set");
|
||||
char *format = (char *) switch_xml_attr(param, "format");
|
||||
char *other_leg = (char *) switch_xml_attr(param, "other_leg");
|
||||
char *regex = (char *) switch_xml_attr(param, "regex");
|
||||
|
||||
attribute = rc_dict_findattr(handle, var);
|
||||
|
||||
@ -528,6 +529,24 @@ switch_status_t mod_xml_radius_add_params(switch_core_session_t *session, switch
|
||||
}
|
||||
}
|
||||
|
||||
if ( regex && val ) {
|
||||
switch_regex_t *re = NULL;
|
||||
int ovector[30];
|
||||
int proceed;
|
||||
char replace[1024] = "";
|
||||
proceed = 0;
|
||||
proceed = switch_regex_perform(val, regex, &re, ovector, sizeof(ovector) / sizeof(ovector[0]));
|
||||
if ( proceed > 0 ) {
|
||||
switch_regex_copy_substring(val, ovector, proceed, proceed - 1, replace, sizeof(replace));
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "original value: %s, regex: %s, result: %s\n", val, regex, replace);
|
||||
val = replace;
|
||||
}
|
||||
else {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "original value: %s, regex: %s, result: nomatch, value left intact\n", val, regex);
|
||||
}
|
||||
switch_regex_safe_free(re);
|
||||
}
|
||||
|
||||
if ( val == NULL && val_default != NULL) {
|
||||
av_value = switch_mprintf(format, val_default);
|
||||
} else {
|
||||
|
@ -944,32 +944,34 @@ SWITCH_DECLARE(const char *) switch_channel_get_variable_dup(switch_channel_t *c
|
||||
|
||||
switch_mutex_lock(channel->profile_mutex);
|
||||
|
||||
if (channel->scope_variables) {
|
||||
switch_event_t *ep;
|
||||
if (!zstr(varname)) {
|
||||
if (channel->scope_variables) {
|
||||
switch_event_t *ep;
|
||||
|
||||
for (ep = channel->scope_variables; ep; ep = ep->next) {
|
||||
if ((v = switch_event_get_header_idx(ep, varname, idx))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!v && (!channel->variables || !(v = switch_event_get_header_idx(channel->variables, varname, idx)))) {
|
||||
switch_caller_profile_t *cp = switch_channel_get_caller_profile(channel);
|
||||
|
||||
if (cp) {
|
||||
if (!strncmp(varname, "aleg_", 5)) {
|
||||
cp = cp->originator_caller_profile;
|
||||
varname += 5;
|
||||
} else if (!strncmp(varname, "bleg_", 5)) {
|
||||
cp = cp->originatee_caller_profile;
|
||||
varname += 5;
|
||||
for (ep = channel->scope_variables; ep; ep = ep->next) {
|
||||
if ((v = switch_event_get_header_idx(ep, varname, idx))) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!cp || !(v = switch_caller_get_field_by_name(cp, varname))) {
|
||||
if ((vdup = switch_core_get_variable_pdup(varname, switch_core_session_get_pool(channel->session)))) {
|
||||
v = vdup;
|
||||
if (!v && (!channel->variables || !(v = switch_event_get_header_idx(channel->variables, varname, idx)))) {
|
||||
switch_caller_profile_t *cp = switch_channel_get_caller_profile(channel);
|
||||
|
||||
if (cp) {
|
||||
if (!strncmp(varname, "aleg_", 5)) {
|
||||
cp = cp->originator_caller_profile;
|
||||
varname += 5;
|
||||
} else if (!strncmp(varname, "bleg_", 5)) {
|
||||
cp = cp->originatee_caller_profile;
|
||||
varname += 5;
|
||||
}
|
||||
}
|
||||
|
||||
if (!cp || !(v = switch_caller_get_field_by_name(cp, varname))) {
|
||||
if ((vdup = switch_core_get_variable_pdup(varname, switch_core_session_get_pool(channel->session)))) {
|
||||
v = vdup;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -393,11 +393,13 @@ SWITCH_DECLARE(char *) switch_core_get_variable_dup(const char *varname)
|
||||
{
|
||||
char *val = NULL, *v;
|
||||
|
||||
switch_thread_rwlock_rdlock(runtime.global_var_rwlock);
|
||||
if ((v = (char *) switch_event_get_header(runtime.global_vars, varname))) {
|
||||
val = strdup(v);
|
||||
if (varname) {
|
||||
switch_thread_rwlock_rdlock(runtime.global_var_rwlock);
|
||||
if ((v = (char *) switch_event_get_header(runtime.global_vars, varname))) {
|
||||
val = strdup(v);
|
||||
}
|
||||
switch_thread_rwlock_unlock(runtime.global_var_rwlock);
|
||||
}
|
||||
switch_thread_rwlock_unlock(runtime.global_var_rwlock);
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -406,11 +408,13 @@ SWITCH_DECLARE(char *) switch_core_get_variable_pdup(const char *varname, switch
|
||||
{
|
||||
char *val = NULL, *v;
|
||||
|
||||
switch_thread_rwlock_rdlock(runtime.global_var_rwlock);
|
||||
if ((v = (char *) switch_event_get_header(runtime.global_vars, varname))) {
|
||||
val = switch_core_strdup(pool, v);
|
||||
if (varname) {
|
||||
switch_thread_rwlock_rdlock(runtime.global_var_rwlock);
|
||||
if ((v = (char *) switch_event_get_header(runtime.global_vars, varname))) {
|
||||
val = switch_core_strdup(pool, v);
|
||||
}
|
||||
switch_thread_rwlock_unlock(runtime.global_var_rwlock);
|
||||
}
|
||||
switch_thread_rwlock_unlock(runtime.global_var_rwlock);
|
||||
|
||||
return val;
|
||||
}
|
||||
@ -2300,9 +2304,15 @@ static void switch_load_core_config(const char *file)
|
||||
} else if (!strcasecmp(var, "rtp-enable-zrtp")) {
|
||||
switch_core_set_variable("zrtp_enabled", val);
|
||||
#endif
|
||||
} else if (!strcasecmp(var, "switchname") && !zstr(val)) {
|
||||
} else if (!strcasecmp(var, "switchname") && !zstr(val)) {
|
||||
runtime.switchname = switch_core_strdup(runtime.memory_pool, val);
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Set switchname to %s\n", runtime.switchname);
|
||||
} else if (!strcasecmp(var, "rtp-retain-crypto-keys")) {
|
||||
if (switch_true(val)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
|
||||
"rtp-retain-crypto-keys enabled. Could be used to decrypt secure media.\n");
|
||||
}
|
||||
switch_core_set_variable("rtp_retain_crypto_keys", val);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1750,7 +1750,8 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
|
||||
const char *abs, *codec_string = NULL;
|
||||
const char *ocodec = NULL, *val;
|
||||
switch_media_handle_t *smh;
|
||||
|
||||
char *tmp_codec_string;
|
||||
|
||||
switch_assert(session);
|
||||
|
||||
if (!(smh = session->media_handle)) {
|
||||
@ -1806,16 +1807,16 @@ SWITCH_DECLARE(void) switch_core_media_prepare_codecs(switch_core_session_t *ses
|
||||
}
|
||||
|
||||
ready:
|
||||
if (codec_string) {
|
||||
char *tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
|
||||
|
||||
|
||||
switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string);
|
||||
smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
|
||||
smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
|
||||
} else {
|
||||
smh->mparams->num_codecs = switch_loadable_module_get_codecs(smh->codecs, sizeof(smh->codecs) / sizeof(smh->codecs[0]));
|
||||
if (!codec_string) {
|
||||
codec_string = "PCMU@20i,PCMA@20i,speex@20i";
|
||||
}
|
||||
|
||||
tmp_codec_string = switch_core_session_strdup(smh->session, codec_string);
|
||||
switch_channel_set_variable(session->channel, "rtp_use_codec_string", codec_string);
|
||||
smh->codec_order_last = switch_separate_string(tmp_codec_string, ',', smh->codec_order, SWITCH_MAX_CODECS);
|
||||
smh->mparams->num_codecs = switch_loadable_module_get_codecs_sorted(smh->codecs, SWITCH_MAX_CODECS, smh->codec_order, smh->codec_order_last);
|
||||
|
||||
}
|
||||
|
||||
|
||||
@ -3169,6 +3170,7 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t
|
||||
engine->ice_in.is_chosen[1] = 0;
|
||||
engine->ice_in.cand_idx[0] = 0;
|
||||
engine->ice_in.cand_idx[1] = 0;
|
||||
engine->remote_ssrc = 0;
|
||||
|
||||
if (m) {
|
||||
attr = m->m_attributes;
|
||||
@ -3428,7 +3430,6 @@ static switch_status_t check_ice(switch_media_handle_t *smh, switch_media_type_t
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(smh->session->channel, CF_REINVITE)) {
|
||||
|
||||
if (switch_rtp_ready(engine->rtp_session) && engine->ice_in.cands[engine->ice_in.chosen[0]][0].ready && engine->new_ice) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(smh->session), SWITCH_LOG_INFO, "RE-Activating %s ICE\n", type2str(type));
|
||||
|
||||
@ -3931,10 +3932,12 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
|
||||
switch_channel_set_variable(session->channel, "media_audio_mode", NULL);
|
||||
}
|
||||
|
||||
if (sendonly) {
|
||||
a_engine->smode = sdp_media_flow(sdp_sendonly);
|
||||
} else if (recvonly) {
|
||||
a_engine->smode = sdp_media_flow(sdp_recvonly);
|
||||
if (sdp_type == SDP_TYPE_RESPONSE) {
|
||||
if (sendonly) {
|
||||
a_engine->smode = sdp_media_flow(sdp_sendonly);
|
||||
} else if (recvonly) {
|
||||
a_engine->smode = sdp_media_flow(sdp_recvonly);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -4379,8 +4382,13 @@ SWITCH_DECLARE(uint8_t) switch_core_media_negotiate_sdp(switch_core_session_t *s
|
||||
|
||||
switch_snprintf(tmp, sizeof(tmp), "%d", a_engine->cur_payload_map->recv_pt);
|
||||
switch_channel_set_variable(session->channel, "rtp_audio_recv_pt", tmp);
|
||||
|
||||
if (switch_core_codec_ready(&a_engine->read_codec) && strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame)) {
|
||||
|
||||
if (switch_core_codec_ready(&a_engine->read_codec) &&
|
||||
(strcasecmp(matches[0].imp->iananame, a_engine->read_codec.implementation->iananame) ||
|
||||
matches[0].imp->microseconds_per_packet != a_engine->read_codec.implementation->microseconds_per_packet ||
|
||||
matches[0].imp->samples_per_second != a_engine->read_codec.implementation->samples_per_second
|
||||
)) {
|
||||
|
||||
a_engine->reset_codec = 1;
|
||||
}
|
||||
|
||||
@ -7173,24 +7181,12 @@ SWITCH_DECLARE(void)switch_core_media_set_local_sdp(switch_core_session_t *sessi
|
||||
|
||||
static void add_fb(char *buf, uint32_t buflen, int pt, int fir, int nack, int pli, int tmmbr)
|
||||
{
|
||||
const char *zfir = "";
|
||||
const char *ztmmbr = "";
|
||||
char *sp = "";
|
||||
|
||||
if (fir) {
|
||||
zfir = "fir";
|
||||
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d ccm fir\n", pt);
|
||||
}
|
||||
|
||||
if (tmmbr) {
|
||||
ztmmbr = "tmmbr";
|
||||
}
|
||||
|
||||
if (fir && tmmbr) {
|
||||
sp = " ";
|
||||
}
|
||||
|
||||
if (!zstr(zfir) || !zstr(ztmmbr)) {
|
||||
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d ccm %s%s%s\n", pt, zfir, sp, ztmmbr);
|
||||
switch_snprintf(buf + strlen(buf), buflen - strlen(buf), "a=rtcp-fb:%d ccm tmmbr\n", pt);
|
||||
}
|
||||
|
||||
if (nack) {
|
||||
@ -8894,6 +8890,30 @@ SWITCH_DECLARE(switch_bool_t) switch_core_media_check_dtls(switch_core_session_t
|
||||
}
|
||||
|
||||
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_set_outgoing_bitrate(switch_core_session_t *session, switch_media_type_t type, uint32_t bitrate)
|
||||
{
|
||||
switch_media_handle_t *smh;
|
||||
switch_rtp_engine_t *engine;
|
||||
switch_status_t status = SWITCH_STATUS_FALSE;
|
||||
|
||||
if (!(smh = session->media_handle)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (switch_channel_down(session->channel)) {
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
engine = &smh->engines[type];
|
||||
|
||||
if (switch_core_codec_ready(&engine->write_codec)) {
|
||||
status = switch_core_codec_control(&engine->write_codec, SCC_VIDEO_BANDWIDTH,
|
||||
SCCT_INT, &bitrate, SCCT_NONE, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
return status;
|
||||
}
|
||||
|
||||
//?
|
||||
SWITCH_DECLARE(switch_status_t) switch_core_media_receive_message(switch_core_session_t *session, switch_core_session_message_t *msg)
|
||||
{
|
||||
@ -10769,12 +10789,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_write_video_frame(switch_cor
|
||||
bug_frame.img = img;
|
||||
|
||||
if (bp->callback && switch_test_flag(bp, SMBF_WRITE_VIDEO_PING)) {
|
||||
bp->ping_frame = &bug_frame;
|
||||
bp->video_ping_frame = &bug_frame;
|
||||
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_WRITE_VIDEO_PING) == SWITCH_FALSE
|
||||
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
|
||||
ok = SWITCH_FALSE;
|
||||
}
|
||||
bp->ping_frame = NULL;
|
||||
bp->video_ping_frame = NULL;
|
||||
}
|
||||
|
||||
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM_BLEG) && !patched) {
|
||||
@ -10874,12 +10894,6 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core
|
||||
return SWITCH_STATUS_FALSE;
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(session->channel, CF_VIDEO_PAUSE_READ)) {
|
||||
*frame = &runtime.dummy_cng_frame;
|
||||
switch_yield(20000);
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (session->endpoint_interface->io_routines->read_video_frame) {
|
||||
if ((status = session->endpoint_interface->io_routines->read_video_frame(session, frame, flags, stream_id)) == SWITCH_STATUS_SUCCESS) {
|
||||
for (ptr = session->event_hooks.video_read_frame; ptr; ptr = ptr->next) {
|
||||
@ -10890,6 +10904,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core
|
||||
}
|
||||
}
|
||||
|
||||
if (switch_channel_test_flag(session->channel, CF_VIDEO_PAUSE_READ)) {
|
||||
*frame = &runtime.dummy_cng_frame;
|
||||
switch_cond_next();
|
||||
return SWITCH_STATUS_SUCCESS;
|
||||
}
|
||||
|
||||
if (status == SWITCH_STATUS_INUSE) {
|
||||
*frame = &runtime.dummy_cng_frame;
|
||||
switch_cond_next();
|
||||
@ -11002,12 +11022,12 @@ SWITCH_DECLARE(switch_status_t) switch_core_session_read_video_frame(switch_core
|
||||
|
||||
|
||||
if (bp->callback && switch_test_flag(bp, SMBF_READ_VIDEO_PING)) {
|
||||
bp->ping_frame = *frame;
|
||||
bp->video_ping_frame = *frame;
|
||||
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_READ_VIDEO_PING) == SWITCH_FALSE
|
||||
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
|
||||
ok = SWITCH_FALSE;
|
||||
}
|
||||
bp->ping_frame = NULL;
|
||||
bp->video_ping_frame = NULL;
|
||||
}
|
||||
|
||||
if (switch_core_media_bug_test_flag(bp, SMBF_SPY_VIDEO_STREAM) && !patched) {
|
||||
|
@ -90,7 +90,7 @@ SWITCH_DECLARE(switch_core_session_t *) switch_core_media_bug_get_session(switch
|
||||
|
||||
SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_video_ping_frame(switch_media_bug_t *bug)
|
||||
{
|
||||
return bug->ping_frame;
|
||||
return bug->video_ping_frame;
|
||||
}
|
||||
|
||||
SWITCH_DECLARE(switch_frame_t *) switch_core_media_bug_get_write_replace_frame(switch_media_bug_t *bug)
|
||||
@ -603,17 +603,15 @@ static void *SWITCH_THREAD_FUNC video_bug_thread(switch_thread_t *thread, void *
|
||||
}
|
||||
|
||||
switch_thread_rwlock_rdlock(bug->session->bug_rwlock);
|
||||
//switch_mutex_lock(bug->read_mutex);
|
||||
frame.img = other_q ? IMG : img;
|
||||
bug->ping_frame = &frame;
|
||||
bug->video_ping_frame = &frame;
|
||||
if (bug->callback) {
|
||||
if (bug->callback(bug, bug->user_data, SWITCH_ABC_TYPE_STREAM_VIDEO_PING) == SWITCH_FALSE
|
||||
|| (bug->stop_time && bug->stop_time <= switch_epoch_time_now(NULL))) {
|
||||
ok = SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
bug->ping_frame = NULL;
|
||||
//switch_mutex_unlock(bug->read_mutex);
|
||||
bug->video_ping_frame = NULL;
|
||||
switch_thread_rwlock_unlock(bug->session->bug_rwlock);
|
||||
|
||||
if (!ok) {
|
||||
@ -1021,14 +1019,14 @@ SWITCH_DECLARE(uint32_t) switch_core_media_bug_patch_video(switch_core_session_t
|
||||
for (bp = orig_session->bugs; bp; bp = bp->next) {
|
||||
if (!switch_test_flag(bp, SMBF_PRUNE) && !switch_test_flag(bp, SMBF_LOCK) && !strcmp(bp->function, "patch:video")) {
|
||||
if (bp->ready && frame->img && switch_test_flag(bp, SMBF_VIDEO_PATCH)) {
|
||||
bp->ping_frame = frame;
|
||||
bp->video_ping_frame = frame;
|
||||
if (bp->callback) {
|
||||
if (bp->callback(bp, bp->user_data, SWITCH_ABC_TYPE_VIDEO_PATCH) == SWITCH_FALSE
|
||||
|| (bp->stop_time && bp->stop_time <= switch_epoch_time_now(NULL))) {
|
||||
ok = SWITCH_FALSE;
|
||||
}
|
||||
}
|
||||
bp->ping_frame = NULL;
|
||||
bp->video_ping_frame = NULL;
|
||||
}
|
||||
|
||||
if (ok == SWITCH_FALSE) {
|
||||
|
@ -266,17 +266,24 @@ SWITCH_DECLARE(const char *) API::executeString(const char *cmd)
|
||||
|
||||
this_check("");
|
||||
|
||||
mycmd = strdup(cmd);
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
|
||||
switch_assert(mycmd);
|
||||
if (zstr(cmd)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No application specified\n");
|
||||
stream.write_function(&stream, "-ERR No application specified");
|
||||
} else {
|
||||
mycmd = strdup(cmd);
|
||||
|
||||
if ((arg = strchr(mycmd, ' '))) {
|
||||
*arg++ = '\0';
|
||||
switch_assert(mycmd);
|
||||
|
||||
if ((arg = strchr(mycmd, ' '))) {
|
||||
*arg++ = '\0';
|
||||
}
|
||||
|
||||
switch_api_execute(mycmd, arg, session, &stream);
|
||||
switch_safe_free(mycmd);
|
||||
}
|
||||
|
||||
SWITCH_STANDARD_STREAM(stream);
|
||||
switch_api_execute(mycmd, arg, session, &stream);
|
||||
switch_safe_free(mycmd);
|
||||
return (char *) stream.data;
|
||||
}
|
||||
|
||||
@ -425,6 +432,11 @@ SWITCH_DECLARE(const char *)Event::getHeader(const char *header_name)
|
||||
{
|
||||
this_check("");
|
||||
|
||||
if (zstr(header_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Trying to getHeader an invalid header!\n");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
if (event) {
|
||||
return switch_event_get_header(event, header_name);
|
||||
} else {
|
||||
@ -450,6 +462,11 @@ SWITCH_DECLARE(bool) Event::delHeader(const char *header_name)
|
||||
{
|
||||
this_check(false);
|
||||
|
||||
if (zstr(header_name)) {
|
||||
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Trying to delHeader an invalid header!\n");
|
||||
return false;
|
||||
}
|
||||
|
||||
if (event) {
|
||||
return switch_event_del_header(event, header_name) == SWITCH_STATUS_SUCCESS ? true : false;
|
||||
} else {
|
||||
|
@ -1932,9 +1932,10 @@ SWITCH_DECLARE(void) switch_event_prep_for_delivery_detailed(const char *file, c
|
||||
char date[80] = "";
|
||||
switch_size_t retsize;
|
||||
switch_time_t ts = switch_micro_time_now();
|
||||
uint64_t seq;
|
||||
|
||||
switch_mutex_lock(EVENT_QUEUE_MUTEX);
|
||||
EVENT_SEQUENCE_NR++;
|
||||
seq = ++EVENT_SEQUENCE_NR;
|
||||
switch_mutex_unlock(EVENT_QUEUE_MUTEX);
|
||||
|
||||
|
||||
@ -1954,7 +1955,7 @@ SWITCH_DECLARE(void) switch_event_prep_for_delivery_detailed(const char *file, c
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Event-Calling-File", switch_cut_path(file));
|
||||
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Event-Calling-Function", func);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Calling-Line-Number", "%d", line);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Sequence", "%" SWITCH_UINT64_T_FMT, (uint64_t) EVENT_SEQUENCE_NR);
|
||||
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Event-Sequence", "%" SWITCH_UINT64_T_FMT, seq);
|
||||
|
||||
|
||||
}
|
||||
|
188
src/switch_ivr.c
188
src/switch_ivr.c
@ -2490,6 +2490,105 @@ SWITCH_DECLARE(int) switch_ivr_set_xml_profile_data(switch_xml_t xml, switch_cal
|
||||
return off;
|
||||
}
|
||||
|
||||
|
||||
#define add_stat(_x, _i, _s) \
|
||||
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
|
||||
x_tmp = switch_xml_add_child_d(_x, _s, loff++); \
|
||||
switch_xml_set_txt_d(x_tmp, var_val)
|
||||
|
||||
#define add_stat_double(_x, _i, _s) \
|
||||
switch_snprintf(var_val, sizeof(var_val), "%0.2f", _i); \
|
||||
x_tmp = switch_xml_add_child_d(_x, _s, loff++); \
|
||||
switch_xml_set_txt_d(x_tmp, var_val)
|
||||
|
||||
SWITCH_DECLARE(int) switch_ivr_set_xml_call_stats(switch_xml_t xml, switch_core_session_t *session, int off, switch_media_type_t type)
|
||||
{
|
||||
const char *name = (type == SWITCH_MEDIA_TYPE_VIDEO) ? "video" : "audio";
|
||||
switch_xml_t x_stat, x_in, x_out, x_tmp = NULL;
|
||||
int loff = 0;
|
||||
switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
|
||||
char var_val[35] = "";
|
||||
|
||||
if (!stats) return off;
|
||||
|
||||
if (!(x_stat = switch_xml_add_child_d(xml, name, off++))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!(x_in = switch_xml_add_child_d(x_stat, "inbound", off++))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
if (!(x_out = switch_xml_add_child_d(x_stat, "outbound", off++))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
stats->inbound.std_deviation = sqrt(stats->inbound.variance);
|
||||
|
||||
add_stat(x_in, stats->inbound.raw_bytes, "raw_bytes");
|
||||
add_stat(x_in, stats->inbound.media_bytes, "media_bytes");
|
||||
add_stat(x_in, stats->inbound.packet_count, "packet_count");
|
||||
add_stat(x_in, stats->inbound.media_packet_count, "media_packet_count");
|
||||
add_stat(x_in, stats->inbound.skip_packet_count, "skip_packet_count");
|
||||
add_stat(x_in, stats->inbound.jb_packet_count, "jitter_packet_count");
|
||||
add_stat(x_in, stats->inbound.dtmf_packet_count, "dtmf_packet_count");
|
||||
add_stat(x_in, stats->inbound.cng_packet_count, "cng_packet_count");
|
||||
add_stat(x_in, stats->inbound.flush_packet_count, "flush_packet_count");
|
||||
add_stat(x_in, stats->inbound.largest_jb_size, "largest_jb_size");
|
||||
add_stat_double(x_in, stats->inbound.min_variance, "jitter_min_variance");
|
||||
add_stat_double(x_in, stats->inbound.max_variance, "jitter_max_variance");
|
||||
add_stat_double(x_in, stats->inbound.lossrate, "jitter_loss_rate");
|
||||
add_stat_double(x_in, stats->inbound.burstrate, "jitter_burst_rate");
|
||||
add_stat_double(x_in, stats->inbound.mean_interval, "mean_interval");
|
||||
add_stat(x_in, stats->inbound.flaws, "flaw_total");
|
||||
add_stat_double(x_in, stats->inbound.R, "quality_percentage");
|
||||
add_stat_double(x_in, stats->inbound.mos, "mos");
|
||||
|
||||
|
||||
if (stats->inbound.error_log) {
|
||||
switch_xml_t x_err_log, x_err;
|
||||
switch_error_period_t *ep;
|
||||
int eoff = 0;
|
||||
|
||||
if (!(x_err_log = switch_xml_add_child_d(x_stat, "error-log", off++))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
for(ep = stats->inbound.error_log; ep; ep = ep->next) {
|
||||
|
||||
if (!(ep->start && ep->stop)) continue;
|
||||
|
||||
if (!(x_err = switch_xml_add_child_d(x_err_log, "error-period", eoff++))) {
|
||||
abort();
|
||||
}
|
||||
|
||||
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_TIME_T_FMT, ep->start);
|
||||
x_tmp = switch_xml_add_child_d(x_err, "start", 0);
|
||||
switch_xml_set_txt_d(x_tmp, var_val);
|
||||
|
||||
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_TIME_T_FMT, ep->stop);
|
||||
x_tmp = switch_xml_add_child_d(x_err, "stop", 1);
|
||||
switch_xml_set_txt_d(x_tmp, var_val);
|
||||
|
||||
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_TIME_T_FMT, (ep->stop - ep->start) / 1000);
|
||||
x_tmp = switch_xml_add_child_d(x_err, "duration-msec", 2);
|
||||
switch_xml_set_txt_d(x_tmp, var_val);
|
||||
}
|
||||
}
|
||||
|
||||
add_stat(x_out, stats->outbound.raw_bytes, "raw_bytes");
|
||||
add_stat(x_out, stats->outbound.media_bytes, "media_bytes");
|
||||
add_stat(x_out, stats->outbound.packet_count, "packet_count");
|
||||
add_stat(x_out, stats->outbound.media_packet_count, "media_packet_count");
|
||||
add_stat(x_out, stats->outbound.skip_packet_count, "skip_packet_count");
|
||||
add_stat(x_out, stats->outbound.dtmf_packet_count, "dtmf_packet_count");
|
||||
add_stat(x_out, stats->outbound.cng_packet_count, "cng_packet_count");
|
||||
add_stat(x_out, stats->rtcp.packet_count, "rtcp_packet_count");
|
||||
add_stat(x_out, stats->rtcp.octet_count, "rtcp_octet_count");
|
||||
|
||||
return off;
|
||||
}
|
||||
|
||||
static int switch_ivr_set_xml_chan_var(switch_xml_t xml, const char *var, const char *val, int off)
|
||||
{
|
||||
char *data;
|
||||
@ -2584,6 +2683,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_xml_cdr(switch_core_session_
|
||||
free(f);
|
||||
}
|
||||
|
||||
if (!(variables = switch_xml_add_child_d(cdr, "call-stats", cdr_off++))) {
|
||||
goto error;
|
||||
}
|
||||
|
||||
switch_ivr_set_xml_call_stats(variables, session, v_off, SWITCH_MEDIA_TYPE_AUDIO);
|
||||
switch_ivr_set_xml_call_stats(variables, session, v_off, SWITCH_MEDIA_TYPE_VIDEO);
|
||||
|
||||
|
||||
if (!(variables = switch_xml_add_child_d(cdr, "variables", cdr_off++))) {
|
||||
goto error;
|
||||
@ -2888,6 +2994,80 @@ static void switch_ivr_set_json_profile_data(cJSON *json, switch_caller_profile_
|
||||
cJSON_AddItemToObject(json, "chan_name", cJSON_CreateString(caller_profile->chan_name));
|
||||
}
|
||||
|
||||
#define add_jstat(_j, _i, _s) \
|
||||
switch_snprintf(var_val, sizeof(var_val), "%" SWITCH_SIZE_T_FMT, _i); \
|
||||
cJSON_AddItemToObject(_j, _s, cJSON_CreateNumber(_i))
|
||||
|
||||
SWITCH_DECLARE(void) switch_ivr_set_json_call_stats(cJSON *json, switch_core_session_t *session, switch_media_type_t type)
|
||||
{
|
||||
const char *name = (type == SWITCH_MEDIA_TYPE_VIDEO) ? "video" : "audio";
|
||||
cJSON *j_stat, *j_in, *j_out;
|
||||
switch_rtp_stats_t *stats = switch_core_media_get_stats(session, type, NULL);
|
||||
char var_val[35] = "";
|
||||
|
||||
if (!stats) return;
|
||||
|
||||
j_stat = cJSON_CreateObject();
|
||||
j_in = cJSON_CreateObject();
|
||||
j_out = cJSON_CreateObject();
|
||||
|
||||
cJSON_AddItemToObject(json, name, j_stat);
|
||||
cJSON_AddItemToObject(j_stat, "inbound", j_in);
|
||||
cJSON_AddItemToObject(j_stat, "outbound", j_out);
|
||||
|
||||
stats->inbound.std_deviation = sqrt(stats->inbound.variance);
|
||||
|
||||
add_jstat(j_in, stats->inbound.raw_bytes, "raw_bytes");
|
||||
add_jstat(j_in, stats->inbound.media_bytes, "media_bytes");
|
||||
add_jstat(j_in, stats->inbound.packet_count, "packet_count");
|
||||
add_jstat(j_in, stats->inbound.media_packet_count, "media_packet_count");
|
||||
add_jstat(j_in, stats->inbound.skip_packet_count, "skip_packet_count");
|
||||
add_jstat(j_in, stats->inbound.jb_packet_count, "jitter_packet_count");
|
||||
add_jstat(j_in, stats->inbound.dtmf_packet_count, "dtmf_packet_count");
|
||||
add_jstat(j_in, stats->inbound.cng_packet_count, "cng_packet_count");
|
||||
add_jstat(j_in, stats->inbound.flush_packet_count, "flush_packet_count");
|
||||
add_jstat(j_in, stats->inbound.largest_jb_size, "largest_jb_size");
|
||||
add_jstat(j_in, stats->inbound.min_variance, "jitter_min_variance");
|
||||
add_jstat(j_in, stats->inbound.max_variance, "jitter_max_variance");
|
||||
add_jstat(j_in, stats->inbound.lossrate, "jitter_loss_rate");
|
||||
add_jstat(j_in, stats->inbound.burstrate, "jitter_burst_rate");
|
||||
add_jstat(j_in, stats->inbound.mean_interval, "mean_interval");
|
||||
add_jstat(j_in, stats->inbound.flaws, "flaw_total");
|
||||
add_jstat(j_in, stats->inbound.R, "quality_percentage");
|
||||
add_jstat(j_in, stats->inbound.mos, "mos");
|
||||
|
||||
|
||||
if (stats->inbound.error_log) {
|
||||
cJSON *j_err_log, *j_err;
|
||||
switch_error_period_t *ep;
|
||||
|
||||
j_err_log = cJSON_CreateArray();
|
||||
cJSON_AddItemToObject(j_in, "errorLog", j_err_log);
|
||||
|
||||
for(ep = stats->inbound.error_log; ep; ep = ep->next) {
|
||||
|
||||
if (!(ep->start && ep->stop)) continue;
|
||||
|
||||
j_err = cJSON_CreateObject();
|
||||
|
||||
cJSON_AddItemToObject(j_err, "start", cJSON_CreateNumber(ep->start));
|
||||
cJSON_AddItemToObject(j_err, "stop", cJSON_CreateNumber(ep->stop));
|
||||
cJSON_AddItemToObject(j_err, "durationMS", cJSON_CreateNumber((ep->stop - ep->start) / 1000));
|
||||
cJSON_AddItemToArray(j_err_log, j_err);
|
||||
}
|
||||
}
|
||||
|
||||
add_jstat(j_out, stats->outbound.raw_bytes, "raw_bytes");
|
||||
add_jstat(j_out, stats->outbound.media_bytes, "media_bytes");
|
||||
add_jstat(j_out, stats->outbound.packet_count, "packet_count");
|
||||
add_jstat(j_out, stats->outbound.media_packet_count, "media_packet_count");
|
||||
add_jstat(j_out, stats->outbound.skip_packet_count, "skip_packet_count");
|
||||
add_jstat(j_out, stats->outbound.dtmf_packet_count, "dtmf_packet_count");
|
||||
add_jstat(j_out, stats->outbound.cng_packet_count, "cng_packet_count");
|
||||
add_jstat(j_out, stats->rtcp.packet_count, "rtcp_packet_count");
|
||||
add_jstat(j_out, stats->rtcp.octet_count, "rtcp_octet_count");
|
||||
}
|
||||
|
||||
static void switch_ivr_set_json_chan_vars(cJSON *json, switch_channel_t *channel, switch_bool_t urlencode)
|
||||
{
|
||||
switch_event_header_t *hi = switch_channel_variable_first(channel);
|
||||
@ -2925,7 +3105,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_json_cdr(switch_core_session
|
||||
switch_channel_t *channel = switch_core_session_get_channel(session);
|
||||
switch_caller_profile_t *caller_profile;
|
||||
cJSON *variables, *j_main_cp, *j_caller_profile, *j_caller_extension, *j_caller_extension_apps, *j_times, *j_application,
|
||||
*j_callflow, *j_profile, *j_inner_extension, *j_app_log, *j_apps, *j_o, *j_o_profiles, *j_channel_data;
|
||||
*j_callflow, *j_profile, *j_inner_extension, *j_app_log, *j_apps, *j_o, *j_o_profiles, *j_channel_data, *callStats;
|
||||
switch_app_log_t *app_log;
|
||||
char tmp[512], *f;
|
||||
|
||||
@ -2951,9 +3131,13 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_generate_json_cdr(switch_core_session
|
||||
free(f);
|
||||
}
|
||||
|
||||
callStats = cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(cdr, "callStats", callStats);
|
||||
switch_ivr_set_json_call_stats(callStats, session, SWITCH_MEDIA_TYPE_AUDIO);
|
||||
switch_ivr_set_json_call_stats(callStats, session, SWITCH_MEDIA_TYPE_VIDEO);
|
||||
|
||||
variables = cJSON_CreateObject();
|
||||
cJSON_AddItemToObject(cdr, "variables", variables);
|
||||
|
||||
switch_ivr_set_json_chan_vars(variables, channel, urlencode);
|
||||
|
||||
|
||||
|
@ -1481,9 +1481,10 @@ static switch_bool_t record_callback(switch_media_bug_t *bug, void *user_data, s
|
||||
case SWITCH_ABC_TYPE_READ_VIDEO_PING:
|
||||
case SWITCH_ABC_TYPE_STREAM_VIDEO_PING:
|
||||
if (rh->fh) {
|
||||
if (!bug->ping_frame) break;
|
||||
if (!bug->video_ping_frame) break;
|
||||
|
||||
if ((len || bug->ping_frame->img) && switch_core_file_write_video(rh->fh, bug->ping_frame) != SWITCH_STATUS_SUCCESS && rh->hangup_on_error) {
|
||||
if ((len || bug->video_ping_frame->img) && switch_core_file_write_video(rh->fh, bug->video_ping_frame) != SWITCH_STATUS_SUCCESS &&
|
||||
rh->hangup_on_error) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing video to %s\n", rh->file);
|
||||
switch_channel_hangup(channel, SWITCH_CAUSE_DESTINATION_OUT_OF_ORDER);
|
||||
switch_core_session_reset(session, SWITCH_TRUE, SWITCH_TRUE);
|
||||
@ -1716,12 +1717,12 @@ static switch_bool_t eavesdrop_callback(switch_media_bug_t *bug, void *user_data
|
||||
case SWITCH_ABC_TYPE_STREAM_VIDEO_PING:
|
||||
{
|
||||
|
||||
if (!bug->ping_frame || !bug->ping_frame->img) {
|
||||
if (!bug->video_ping_frame || !bug->video_ping_frame->img) {
|
||||
break;
|
||||
}
|
||||
|
||||
if (ep->eavesdropper && switch_core_session_read_lock(ep->eavesdropper) == SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_core_session_write_video_frame(ep->eavesdropper, bug->ping_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
if (switch_core_session_write_video_frame(ep->eavesdropper, bug->video_ping_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
|
||||
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Error writing video to %s\n", switch_core_session_get_name(ep->eavesdropper));
|
||||
ep->errs++;
|
||||
|
||||
|
@ -1234,9 +1234,9 @@ SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp
|
||||
|
||||
jb->period_miss_pct = ((double)jb->period_miss_count / jb->period_count) * 100;
|
||||
|
||||
if (jb->period_miss_pct > 40.0f) {
|
||||
if (jb->period_miss_pct > 60.0f) {
|
||||
jb_debug(jb, 2, "Miss percent %02f too high, resetting buffer.\n", jb->period_miss_pct);
|
||||
//switch_jb_reset(jb);
|
||||
switch_jb_reset(jb);
|
||||
}
|
||||
|
||||
if ((status = jb_next_packet(jb, &node)) == SWITCH_STATUS_SUCCESS) {
|
||||
@ -1324,15 +1324,12 @@ SWITCH_DECLARE(switch_status_t) switch_jb_get_packet(switch_jb_t *jb, switch_rtp
|
||||
}
|
||||
|
||||
switch_mutex_unlock(jb->mutex);
|
||||
|
||||
if (status == SWITCH_STATUS_SUCCESS) {
|
||||
if (jb->complete_frames > jb->max_frame_len) {
|
||||
thin_frames(jb, 8, 25);
|
||||
}
|
||||
|
||||
if (jb->complete_frames > jb->max_frame_len) {
|
||||
thin_frames(jb, 8, 25);
|
||||
}
|
||||
|
||||
return status;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
@ -150,6 +150,13 @@ static char *print_number(cJSON *item)
|
||||
return str;
|
||||
}
|
||||
|
||||
#define is_hexdigit(c) ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'))
|
||||
static int scan_unicode(const char *ptr, unsigned int *uc)
|
||||
{
|
||||
if (!is_hexdigit(*(ptr)) || !is_hexdigit(*(ptr+1)) || !is_hexdigit(*(ptr+2)) || !is_hexdigit(*(ptr+3))) return -1;
|
||||
return sscanf(ptr, "%4x", uc);
|
||||
}
|
||||
|
||||
/* Parse the input text into an unescaped cstring, and populate item. */
|
||||
static const unsigned char firstByteMark[7] = { 0x00, 0x00, 0xC0, 0xE0, 0xF0, 0xF8, 0xFC };
|
||||
static const char *parse_string(cJSON *item,const char *str)
|
||||
@ -177,8 +184,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
case 'r': *ptr2++='\r'; break;
|
||||
case 't': *ptr2++='\t'; break;
|
||||
case 'u': /* transcode utf16 to utf8. */
|
||||
if (sscanf(ptr+1,"%4x",&uc) < 1) break;
|
||||
|
||||
if (scan_unicode(ptr+1, &uc) < 1) break;
|
||||
ptr+=4; /* get the unicode char. */
|
||||
|
||||
if ((uc>=0xDC00 && uc<=0xDFFF) || uc==0) break; // check for invalid.
|
||||
@ -186,7 +192,7 @@ static const char *parse_string(cJSON *item,const char *str)
|
||||
if (uc>=0xD800 && uc<=0xDBFF) // UTF16 surrogate pairs.
|
||||
{
|
||||
if (ptr[1]!='\\' || ptr[2]!='u') break; // missing second-half of surrogate.
|
||||
if (sscanf(ptr+3,"%4x",&uc2) < 1) break;
|
||||
if (scan_unicode(ptr+3,&uc2) < 1) break;
|
||||
ptr+=6;
|
||||
if (uc2<0xDC00 || uc2>0xDFFF) break; // invalid second-half of surrogate.
|
||||
uc=0x10000 | ((uc&0x3FF)<<10) | (uc2&0x3FF);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user