diff --git a/debian/bootstrap.sh b/debian/bootstrap.sh index 2163c06947..f94ac56900 100755 --- a/debian/bootstrap.sh +++ b/debian/bootstrap.sh @@ -1008,7 +1008,6 @@ EOF print_conf_install () { cat <> freeswitch-all.install +echo "/var/lib/freeswitch/images" >> freeswitch-all.install + for x in postinst postrm preinst prerm; do cp -a freeswitch.$x freeswitch-all.$x done diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index 7d3e0ad2ec..b63a57e4e9 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -542,17 +542,10 @@ var bestFrameRate = obj.options.videoParams.vertoBestFrameRate; delete obj.options.videoParams.vertoBestFrameRate; - if (window.moz) { - video = obj.options.videoParams; - if (!video.width) video.width = video.minWidth; - if (!video.height) video.height = video.minHeight; - if (!video.frameRate) video.frameRate = video.minFrameRate; - } else { - video = { - mandatory: obj.options.videoParams, - optional: [] - } - } + video = { + mandatory: obj.options.videoParams, + optional: [] + } var useVideo = obj.options.useVideo; @@ -1124,13 +1117,6 @@ "maxHeight": h }; - if (window.moz) { - video = video.mandatory; - if (!video.width) video.width = video.minWidth; - if (!video.height) video.height = video.minHeight; - if (!video.frameRate) video.frameRate = video.minFrameRate; - } - getUserMedia({ constraints: { audio: ttl++ == 0, diff --git a/html5/verto/js/src/jquery.verto.js b/html5/verto/js/src/jquery.verto.js index 0528652673..792331f18a 100644 --- a/html5/verto/js/src/jquery.verto.js +++ b/html5/verto/js/src/jquery.verto.js @@ -1697,7 +1697,22 @@ $(vlselect_id).append(new Option("Choose a Layout", "none")); if (e.data.responseData) { - options = e.data.responseData.sort(); + var rdata = []; + + for (var i in e.data.responseData) { + rdata.push(e.data.responseData[i].name); + } + + options = rdata.sort(function(a, b) { + var ga = a.substring(0, 6) == "group:" ? true : false; + var gb = b.substring(0, 6) == "group:" ? true : false; + + if ((ga || gb) && ga != gb) { + return ga ? -1 : 1; + } + + return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) ); + }); for (var i in options) { $(vlselect_id).append(new Option(options[i], options[i])); diff --git a/html5/verto/verto_communicator/src/css/verto.css b/html5/verto/verto_communicator/src/css/verto.css index 4e0175d583..84666c880a 100644 --- a/html5/verto/verto_communicator/src/css/verto.css +++ b/html5/verto/verto_communicator/src/css/verto.css @@ -21,7 +21,6 @@ body { text-overflow: ellipsis; overflow: hidden; white-space: nowrap; - width: 160px; display: inline-block; } @@ -604,12 +603,24 @@ body .modal-body .btn-group .btn.active { transition-delay:0s; } + +#incall .dropdown-menu .selected { + background-color: #ccc; + color: white; +} + +#incall .dropdown-menu .selected:hover { + background-color: #ccc; + color: white; + cursor: pointer; +} + #incall .video-hover-buttons .btn-group .dropdown-menu { max-height: 200px; overflow: auto; } -#incall .video-hover-buttons .btn-group ul li a:hover { +#incall .video-hover-buttons .btn-group ul li a:not(.selected):hover { background-color: #EEE; cursor: pointer; } @@ -850,6 +861,10 @@ body .modal-body .btn-group .btn.active { padding-right: 360px; } + .watcher #wrapper { + padding-right: 0; + } + #wrapper.toggled { padding-right: 0; } @@ -906,13 +921,11 @@ body .modal-body .btn-group .btn.active { } .members-name { - width: 160px; - overflow: hidden; - text-overflow: ellipsis; - white-space: nowrap; + width: 140px; } .members-number { + width: 140px; font-size: 10px; } @@ -970,6 +983,7 @@ body .modal-body .btn-group .btn.active { display: inline-block; line-height: 16px; margin-top: -3px; + width: 140px; } .chat-members .chat-members-status i { @@ -1018,6 +1032,17 @@ body .modal-body .btn-group .btn.active { vertical-align: -2px; } +.chat-members .resevartion-menu .icon { + color: #C5C5C5; +} + +.chat-members .resevartion-menu .dropdown-menu { + min-width: 0; +} + +.chat-members .resevartion-menu .dropdown-menu .selected { + font-weight: bold; +} /*.chat-messages {*/ /*border-top: 1px solid #E5E5E5;*/ @@ -1545,3 +1570,42 @@ body:-webkit-full-screen #incall .video-footer { #preview .refresh { margin: 15px 0px 0px 0px; } + +.watcher { + padding: 0; + background-color: #333333; +} + +.watcher .navbar, .watcher #sidebar-wrapper, .watcher #dialpad { + display: none; +} + +.watcher #wrapper.toggled { + padding-right: 0; +} + +.watcher #incall .panel { + margin: 0; +} + +.watcher #video-tag-wrapper { + background: linear-gradient(to bottom, #272627, #27252A); + background-color: #27252A; +} + +.watcher #incall .video-call { + width: 100%; + height: 100%; + padding: 0; + max-width: none; + max-height: none; +} + +.watcher #webcam { + max-width: 160.78vh; + margin: auto; +} + +.watcher .spinner { + top: 20%; +} diff --git a/html5/verto/verto_communicator/src/partials/chat.html b/html5/verto/verto_communicator/src/partials/chat.html index 23797d0b51..afe85c1af7 100644 --- a/html5/verto/verto_communicator/src/partials/chat.html +++ b/html5/verto/verto_communicator/src/partials/chat.html @@ -23,12 +23,12 @@

-
{{ member.name }}
+
{{ member.name }}
({{ member.number }})
Floor
-
Presenter
+
{{ member.status.video.reservationID }}
Screen Share

@@ -57,12 +57,6 @@ Mute/Unmute Video -
  • - - - Presenter - -
  • @@ -99,6 +93,39 @@ Transfer
  • +
  • + + + Canvas In + +
  • +
  • + + + Canvas Out + +
  • +
  • + + + Layer + +
  • + + + + +
    +
    + +
    diff --git a/html5/verto/verto_communicator/src/partials/incall.html b/html5/verto/verto_communicator/src/partials/incall.html index 702c943994..9f58c25456 100644 --- a/html5/verto/verto_communicator/src/partials/incall.html +++ b/html5/verto/verto_communicator/src/partials/incall.html @@ -1,5 +1,5 @@
    -
    +
    diff --git a/html5/verto/verto_communicator/src/partials/video_call.html b/html5/verto/verto_communicator/src/partials/video_call.html index 9633149c77..5b83e19d5e 100644 --- a/html5/verto/verto_communicator/src/partials/video_call.html +++ b/html5/verto/verto_communicator/src/partials/video_call.html @@ -1,6 +1,6 @@
    -
    +
    @@ -68,6 +68,17 @@
    +
    + + +
    @@ -80,13 +91,14 @@
    - {{hhours}}:{{mminutes}}:{{sseconds}} + Room {{ extension }} - Canvas {{ canvasID }} + {{hhours}}:{{mminutes}}:{{sseconds}}
    diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js index 3129db87c7..75947db607 100644 --- a/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js +++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/ChatController.js @@ -49,6 +49,39 @@ }); }); + + $rootScope.$on('changedVideoLayout', function(event, layout) { + $scope.resIDs = getResByLayout(layout); + + // remove resIDs param to clear every members resID. + // passing $scope.resIDs results in preserving resIDs compatible + // with the current layout + clearMembersResID($scope.resIDs); + }); + + $rootScope.$on('conference.canvasInfo', function(event, data) { + $scope.currentLayout = data[0].layoutName; + $scope.resIDs = getResByLayout($scope.currentLayout); + }); + + function getResByLayout(layout) { + var layoutsData = verto.data.confLayoutsData; + for (var i = 0; i < layoutsData.length; i++) { + if (layoutsData[i].name === layout) { + return layoutsData[i].resIDS; + } + } + } + + // @preserve - a array of values to be preserved + function clearMembersResID(preserve) { + $scope.members.forEach(function(member) { + var resID = member.status.video.reservationID; + if (resID && preserve && preserve.indexOf(resID) !== -1) return; + $scope.confResID(member.id, resID); + }); + }; + function findMemberByUUID(uuid) { var found = false; for (var idx in $scope.members) { @@ -98,6 +131,11 @@ }); $rootScope.$on('members.del', function(event, uuid) { + if ($rootScope.watcher && $rootScope.master === uuid) { + verto.hangup(); + window.close(); + } + $scope.$apply(function() { var memberIdx = findMemberByUUID(uuid); if (memberIdx != -1) { @@ -171,6 +209,11 @@ verto.data.conf.presenter(memberID); }; + $scope.confResID = function(memberID, resID) { + console.log('Set', memberID, 'to', resID); + verto.setResevartionId(memberID, resID); + }; + $scope.confVideoFloor = function(memberID) { console.log('$scope.confVideoFloor'); verto.data.conf.videoFloor(memberID); @@ -191,6 +234,41 @@ }); }; + $scope.confCanvasIn = function(memberID, canvasID) { + if (canvasID) { + verto.setCanvasIn(memberID, canvasID); + return; + } + + shortPrompt('Please insert the Canvas Id', function(canvasID) { + console.log(memberID, canvasID); + verto.setCanvasIn(memberID, canvasID); + }); + + }; + + $scope.confCanvasOut = function(memberID, canvasID) { + if (canvasID) { + verto.setCanvasOut(memberID, canvasID); + return; + } + + shortPrompt('Please insert the Canvas Id', function(canvasID) { + verto.setCanvasOut(memberID, canvasID); + }); + }; + + $scope.confLayer = function(memberID, canvasID) { + if (canvasID) { + verto.setLayer(memberID, canvasID); + return; + } + + shortPrompt('Please insert the Layer', function(canvasID) { + verto.setLayer(memberID, canvasID); + }); + }; + $scope.confResetBanner = function(memberID) { console.log('$scope.confResetBanner'); var text = 'reset'; @@ -221,6 +299,19 @@ } }); }; + + function shortPrompt(text, cb) { + prompt({ + title: text, + input: true, + label: '', + value: '', + }).then(function(val) { + if (val && cb) { + cb(val); + } + }); + } } ]); diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js index 305befeea1..305e4e60fb 100644 --- a/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js +++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/DialPadController.js @@ -10,6 +10,15 @@ eventQueue.process(); + if ($location.search().autocall) { + $rootScope.dialpadNumber = $location.search().autocall; + delete $location.search().autocall; + call($rootScope.dialpadNumber); + if($rootScope.watcher) { + return; + } + } + $scope.call_history = CallHistory.all(); $scope.history_control = CallHistory.all_control(); $scope.has_history = Object.keys($scope.call_history).length; @@ -32,11 +41,6 @@ /** * fill dialpad via querystring [?autocall=\d+] */ - if ($location.search().autocall) { - $rootScope.dialpadNumber = $location.search().autocall; - delete $location.search().autocall; - call($rootScope.dialpadNumber); - } /** * fill in dialpad via config.json @@ -83,6 +87,13 @@ return false; } + if (extension.indexOf('-canvas-') != -1) { + $rootScope.watcher = true; + verto.call($rootScope.dialpadNumber, null, { useCamera: false, useMic: false, caller_id_name: null, userVariables: {}, caller_id_number: null, mirrorInput: false }); + $location.path('/incall'); + return; + } + storage.data.mutedVideo = false; storage.data.mutedMic = false; diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js index 93e510d5e3..f030b5d611 100644 --- a/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js +++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/InCallController.js @@ -15,7 +15,6 @@ $scope.dialpadTemplate = ''; $scope.incall = true; - if (storage.data.videoCall) { $scope.callTemplate = 'partials/video_call.html'; } @@ -25,6 +24,7 @@ if($scope.chatStatus) { $scope.openChat(); } + buildCanvasesData(); }); }); @@ -73,6 +73,8 @@ $scope.confChangeVideoLayout = function(layout) { verto.data.conf.setVideoLayout(layout); + $scope.videoLayout = layout; + $rootScope.$emit('changedVideoLayout', layout); }; $scope.confChangeSpeaker = function(speakerId) { @@ -80,6 +82,24 @@ $rootScope.$emit('changedSpeaker', speakerId); }; + $scope.confPopup = function(canvas_id) { + var video = document.getElementById('webcam'); + var s = window.location.href; + var curCall = verto.data.call.callID; + var extension = verto.data.call.params.remote_caller_id_number; + var width = webcam.offsetWidth; + var height = webcam.offsetHeight + 100; + var x = (screen.width - width)/2 + var y = (screen.height - height)/2 + + s = s.replace(/\#.*/, ''); + s += "#/?sessid=random&master=" + curCall + "&watcher=true&extension=" + extension+ "&canvas_id=" + canvas_id; + + console.log("opening new window to " + s); + var popup = window.open(s, "canvas_window_" + canvas_id, "toolbar=0,location=0,menubar=0,directories=0,width=" + width + ",height=" + height, + ',left=' + x + ',top=' + y); + popup.moveTo(x, y); + }; + $scope.screenshare = function() { if(verto.data.shareCall) { verto.screenshareHangup(); @@ -88,6 +108,14 @@ verto.screenshare(storage.data.called_number); }; + function buildCanvasesData() { + $scope.conf = verto.data.conf.params.laData; + $scope.canvases = [{ id: 1, name: 'Super Canvas' }]; + for (var i = 1; i < $scope.conf.canvasCount; i++) { + $scope.canvases.push({ id: i+1, name: 'Canvas ' + (i+1) }); + } + } + $scope.muteMic = verto.muteMic; $scope.muteVideo = verto.muteVideo; diff --git a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js index 3c245301a4..5f965a2a74 100644 --- a/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js +++ b/html5/verto/verto_communicator/src/vertoControllers/controllers/MainController.js @@ -8,6 +8,24 @@ console.debug('Executing MainController.'); + $rootScope.master = $location.search().master; + if ($location.search().watcher === 'true') { + $rootScope.watcher = true; + angular.element(document.body).addClass('watcher'); + var dialpad; + var extension = dialpad = $location.search().extension; + var canvasID = $location.search().canvas_id; + + if (dialpad) { + if (canvasID) { + dialpad += '-canvas-' + canvasID; + } + $rootScope.extension = extension; + $rootScope.canvasID = canvasID; + $location.search().autocall = dialpad; + } + } + var myVideo = document.getElementById("webcam"); $scope.verto = verto; $scope.storage = storage; @@ -432,6 +450,11 @@ return; } + if ($rootScope.watcher) { + window.close(); + return; + } + //var hangupCallback = function(v, hangup) { // if (hangup) { // $location.path('/dialpad'); diff --git a/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js b/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js index 38b50552f7..e40adc879a 100644 --- a/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js +++ b/html5/verto/verto_communicator/src/vertoDirectives/directives/videoTag.js @@ -32,4 +32,4 @@ } }); -})(); \ No newline at end of file +})(); diff --git a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js index 9bf54c3cbd..3b2c01758a 100644 --- a/html5/verto/verto_communicator/src/vertoService/services/vertoService.js +++ b/html5/verto/verto_communicator/src/vertoService/services/vertoService.js @@ -391,7 +391,27 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora if (message.action == 'response') { // This is a response with the video layouts list. if (message['conf-command'] == 'list-videoLayouts') { - data.confLayouts = message.responseData.sort(); + var rdata = []; + + for (var i in message.responseData) { + rdata.push(message.responseData[i].name); + } + + var options = rdata.sort(function(a, b) { + var ga = a.substring(0, 6) == "group:" ? true : false; + var gb = b.substring(0, 6) == "group:" ? true : false; + + if ((ga || gb) && ga != gb) { + return ga ? -1 : 1; + } + + return ( ( a == b ) ? 0 : ( ( a > b ) ? 1 : -1 ) ); + }); + data.confLayoutsData = message.responseData; + data.confLayouts = options; + } else if (message['conf-command'] == 'canvasInfo') { + data.canvasInfo = message.responseData; + $rootScope.$emit('conference.canvasInfo', message.responseData); } else { $rootScope.$emit('conference.broadcast', message); } @@ -402,6 +422,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora if (data.confRole == "moderator") { console.log('>>> conf.listVideoLayouts();'); conf.listVideoLayouts(); + conf.modCommand('canvasInfo'); } data.conf = conf; @@ -584,6 +605,11 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora var that = this; function ourBootstrap() { + var sessid = $location.search().sessid; + if (sessid === 'random') { + sessid = $.verto.genUUID(); + $location.search().sessid = sessid; + } // Checking if we have a failed connection attempt before // connecting again. if (data.instance && !data.instance.rpcClient.socketReady()) { @@ -604,6 +630,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora googNoiseSuppression: storage.data.googNoiseSuppression || true, googHighpassFilter: storage.data.googHighpassFilter || true }, + sessid: sessid, iceServers: storage.data.useSTUN }, callbacks); @@ -614,6 +641,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora jQuery.verto.unloadJobs.push(function() { that.reloaded = true; }); + data.instance.deviceParams({ useCamera: storage.data.selectedVideo, useSpeak: storage.data.selectedSpeaker, @@ -674,10 +702,10 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora * * @param callback */ - call: function(destination, callback) { + call: function(destination, callback, custom) { console.debug('Attempting to call destination ' + destination + '.'); - var call = data.instance.newCall({ + var call = data.instance.newCall(angular.extend({ destination_number: destination, caller_id_name: data.name, caller_id_number: data.callerid ? data.callerid : data.email, @@ -694,7 +722,7 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora email : storage.data.email, avatar: "http://gravatar.com/avatar/" + md5(storage.data.email) + ".png?s=600" } - }); + }, custom)); data.call = call; @@ -912,6 +940,21 @@ vertoService.service('verto', ['$rootScope', '$cookieStore', '$location', 'stora sendConferenceChat: function(message) { data.conf.sendChat(message, "message"); }, + setCanvasIn: function(memberID, canvasID) { + data.conf.modCommand('vid-canvas', memberID, canvasID); + }, + setCanvasOut: function(memberID, canvasID) { + data.conf.modCommand('vid-watching-canvas', memberID, canvasID); + }, + setLayer: function(memberID, canvasID) { + data.conf.modCommand('vid-layer', memberID, canvasID); + }, + /* + * Method is used to set a member's resevartion Id. + */ + setResevartionId: function(memberID, resID) { + data.conf.modCommand('vid-res-id', memberID, resID); + }, /* * Method is used to send user2user chats. * VC does not yet support that. diff --git a/html5/verto/video_demo/js/verto-min.js b/html5/verto/video_demo/js/verto-min.js index f4e362be1b..4a9e5a5c98 100644 --- a/html5/verto/video_demo/js/verto-min.js +++ b/html5/verto/video_demo/js/verto-min.js @@ -47,7 +47,7 @@ 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!");}});} getUserMedia({constraints:{audio:mediaParams.audio,video:mediaParams.video},video:mediaParams.useVideo,onsuccess:onSuccess,onerror:onError});};function getMediaParams(obj){var audio;if(obj.options.useMic&&obj.options.useMic==="none"){console.log("Microphone Disabled");audio=false;}else if(obj.options.videoParams&&obj.options.screenShare){console.error("SCREEN SHARE");audio=false;}else{audio={mandatory:obj.options.audioParams,optional:[]};if(obj.options.useMic!=="any"){audio.optional=[{sourceId:obj.options.useMic}]}} if(obj.options.useVideo&&obj.options.localVideo){getUserMedia({constraints:{audio:false,video:{mandatory:obj.options.videoParams,optional:[]},},localVideo:obj.options.localVideo,onsuccess:function(e){self.options.localVideoStream=e;console.log("local video ready");},onerror:function(e){console.error("local video error!");}});} -var video={};var bestFrameRate=obj.options.videoParams.vertoBestFrameRate;delete obj.options.videoParams.vertoBestFrameRate;if(window.moz){video=obj.options.videoParams;if(!video.width)video.width=video.minWidth;if(!video.height)video.height=video.minHeight;if(!video.frameRate)video.frameRate=video.minFrameRate;}else{video={mandatory:obj.options.videoParams,optional:[]}} +var video={};var bestFrameRate=obj.options.videoParams.vertoBestFrameRate;delete obj.options.videoParams.vertoBestFrameRate;video={mandatory:obj.options.videoParams,optional:[]} var useVideo=obj.options.useVideo;if(useVideo&&obj.options.useCamera&&obj.options.useCamera!=="none"){if(!video.optional){video.optional=[];} if(obj.options.useCamera!=="any"){video.optional.push({sourceId:obj.options.useCamera});} if(bestFrameRate&&!window.moz){video.optional.push({minFrameRate:bestFrameRate});}}else{console.log("Camera Disabled");video=false;useVideo=false;} @@ -93,8 +93,7 @@ return[w,h];} var resList=[[320,180],[320,240],[640,360],[640,480],[1280,720],[1920,1080]];var resI=0;var ttl=0;var checkRes=function(cam,func){if(resI>=resList.length){var res={'validRes':$.FSRTC.validRes,'bestResSupported':$.FSRTC.bestResSupported()};localStorage.setItem("res_"+cam,$.toJSON(res));if(func)return func(res);return;} var video={mandatory:{},optional:[]} if(cam){video.optional=[{sourceId:cam}];} -w=resList[resI][0];h=resList[resI][1];resI++;video.mandatory={"minWidth":w,"minHeight":h,"maxWidth":w,"maxHeight":h};if(window.moz){video=video.mandatory;if(!video.width)video.width=video.minWidth;if(!video.height)video.height=video.minHeight;if(!video.frameRate)video.frameRate=video.minFrameRate;} -getUserMedia({constraints:{audio:ttl++==0,video:video},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info(w+"x"+h+" supported.");$.FSRTC.validRes.push([w,h]);checkRes(cam,func);},onerror:function(e){console.error(w+"x"+h+" not supported.");checkRes(cam,func);}});} +w=resList[resI][0];h=resList[resI][1];resI++;video.mandatory={"minWidth":w,"minHeight":h,"maxWidth":w,"maxHeight":h};getUserMedia({constraints:{audio:ttl++==0,video:video},onsuccess:function(e){e.getTracks().forEach(function(track){track.stop();});console.info(w+"x"+h+" supported.");$.FSRTC.validRes.push([w,h]);checkRes(cam,func);},onerror:function(e){console.error(w+"x"+h+" not supported.");checkRes(cam,func);}});} $.FSRTC.getValidRes=function(cam,func){var used=[];var cached=localStorage.getItem("res_"+cam);if(cached){var cache=$.parseJSON(cached);if(cache){$.FSRTC.validRes=cache.validRes;console.log("CACHED RES FOR CAM "+cam,cache);}else{console.error("INVALID CACHE");} return func?func(cache):null;} $.FSRTC.validRes=[];resI=0;checkRes(cam,func);} @@ -238,7 +237,9 @@ jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mous $("#"+volup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_in",x,"down");});return html;} var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready

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

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

    ");},4000);}}}});if(confMan.params.hasVid){confMan.modCommand("list-videoLayouts",null,null);}} var row_callback=null;if(confMan.params.laData.role==="moderator"){row_callback=function(nRow,aData,iDisplayIndex,iDisplayIndexFull){if(!aData[5]){var $row=$('td:eq(5)',nRow);genControls($row,aData);if(confMan.params.onLaRow){confMan.params.onLaRow(verto,confMan,$row,aData);}}};} @@ -259,15 +260,15 @@ dialog.verto.rpcClient.call(method,obj,function(e){dialog.processReply(method,tr 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.setAudioPlaybackDevice=function(sinkId,callback,arg){var dialog=this;var element=dialog.audioStream;if(typeof element.sinkId!=='undefined'){var devname=find_name(sinkId);console.info("Dialog: "+dialog.callID+" Setting speaker:",element,devname);element.setSinkId(sinkId).then(function(){console.log("Dialog: "+dialog.callID+' Success, audio output device attached: '+sinkId);if(callback){callback(true,devname,arg);}}).catch(function(error){var errorMessage=error;if(error.name==='SecurityError'){errorMessage="Dialog: "+dialog.callID+' You need to use HTTPS for selecting audio output '+'device: '+error;} +if(callback){callback(false,null,arg);} +console.error(errorMessage);});}else{console.warn("Dialog: "+dialog.callID+' Browser does not support output device selection.');if(callback){callback(false,null,arg);}}} $.verto.dialog.prototype.setState=function(state){var dialog=this;if(dialog.state==$.verto.enum.state.ringing){dialog.stopRinging();} if(dialog.state==state||!checkStateChange(dialog.state,state)){console.error("Dialog "+dialog.callID+": INVALID state change from "+dialog.state.name+" to "+state.name);dialog.hangup();return false;} console.log("Dialog "+dialog.callID+": state change from "+dialog.state.name+" to "+state.name);dialog.lastState=dialog.state;dialog.state=state;if(!dialog.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"){setTimeout(function(){dialog.setAudioDevice(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.setAudioPlaybackDevice(speaker);},500);} break;case $.verto.enum.state.trying:setTimeout(function(){if(dialog.state==$.verto.enum.state.trying){dialog.setState($.verto.enum.state.hangup);}},30000);break;case $.verto.enum.state.purge:dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.hangup:if(dialog.lastState.val>$.verto.enum.state.requesting.val&&dialog.lastState.val<$.verto.enum.state.hangup.val){dialog.sendMethod("verto.bye",{});} dialog.setState($.verto.enum.state.destroy);break;case $.verto.enum.state.destroy:delete dialog.verto.dialogs[dialog.callID];if(dialog.params.screenShare){dialog.rtc.stopPeer();}else{dialog.rtc.stop();} break;} diff --git a/src/include/switch_types.h b/src/include/switch_types.h index 864a40fc51..1f2005dba9 100644 --- a/src/include/switch_types.h +++ b/src/include/switch_types.h @@ -215,7 +215,9 @@ SWITCH_BEGIN_EXTERN_C #define SWITCH_LOCAL_VIDEO_PORT_VARIABLE "local_video_port" #define SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE "hangup_after_bridge" #define SWITCH_PARK_AFTER_BRIDGE_VARIABLE "park_after_bridge" +#define SWITCH_PARK_AFTER_EARLY_BRIDGE_VARIABLE "park_after_early_bridge" #define SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE "transfer_after_bridge" +#define SWITCH_TRANSFER_AFTER_EARLY_BRIDGE_VARIABLE "transfer_after_early_bridge" #define SWITCH_EXEC_AFTER_BRIDGE_APP_VARIABLE "exec_after_bridge_app" #define SWITCH_EXEC_AFTER_BRIDGE_ARG_VARIABLE "exec_after_bridge_arg" #define SWITCH_MAX_FORWARDS_VARIABLE "max_forwards" diff --git a/src/mod/applications/mod_av/avcodec.c b/src/mod/applications/mod_av/avcodec.c index 359be792e1..b4afb7ab40 100644 --- a/src/mod/applications/mod_av/avcodec.c +++ b/src/mod/applications/mod_av/avcodec.c @@ -848,7 +848,7 @@ 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; } - sane = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 30); + sane = switch_calc_bitrate(1920, 1080, 2, 30); if (context->bandwidth > sane) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "BITRATE TRUNCATED TO %d\n", sane); diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index 041591910c..dc9d683e7e 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -1577,12 +1577,7 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc return SWITCH_STATUS_SUCCESS; } - if (zstr(text)) { - stream->write_function(stream, "-ERR missing arg\n"); - return SWITCH_STATUS_SUCCESS; - } - - if (!strcasecmp(text, "clear") || (member->video_reservation_id && !strcasecmp(text, member->video_reservation_id))) { + if (zstr(text) || !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"); } else { diff --git a/src/mod/applications/mod_conference/conference_cdr.c b/src/mod/applications/mod_conference/conference_cdr.c index 83ba8ee579..36938cb22c 100644 --- a/src/mod/applications/mod_conference/conference_cdr.c +++ b/src/mod/applications/mod_conference/conference_cdr.c @@ -42,7 +42,7 @@ #include -inline switch_bool_t conference_cdr_test_mflag(conference_cdr_node_t *np, member_flag_t mflag) +static inline switch_bool_t conference_cdr_test_mflag(conference_cdr_node_t *np, member_flag_t mflag) { return !!np->mflags[mflag]; } diff --git a/src/mod/applications/mod_conference/conference_event.c b/src/mod/applications/mod_conference/conference_event.c index d5b094e978..2a1b2df93d 100644 --- a/src/mod/applications/mod_conference/conference_event.c +++ b/src/mod/applications/mod_conference/conference_event.c @@ -42,6 +42,21 @@ #include +static cJSON *get_canvas_info(mcu_canvas_t *canvas) +{ + cJSON *obj = cJSON_CreateObject(); + + cJSON_AddItemToObject(obj, "canvasID", cJSON_CreateNumber(canvas->canvas_id)); + cJSON_AddItemToObject(obj, "totalLayers", cJSON_CreateNumber(canvas->total_layers)); + cJSON_AddItemToObject(obj, "layersUsed", cJSON_CreateNumber(canvas->layers_used)); + cJSON_AddItemToObject(obj, "layoutFloorID", cJSON_CreateNumber(canvas->layout_floor_id)); + if (canvas->vlayout) { + cJSON_AddItemToObject(obj, "layoutName", cJSON_CreateString(canvas->vlayout->name)); + } + + return obj; +} + void conference_event_mod_channel_handler(const char *event_channel, cJSON *json, const char *key, switch_event_channel_id_t id) { cJSON *data, *addobj = NULL; @@ -63,6 +78,7 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json if ((data = cJSON_GetObjectItem(json, "data"))) { action = cJSON_GetObjectCstr(data, "command"); + if ((jid = cJSON_GetObjectItem(data, "id"))) { if (jid->valueint) { switch_snprintf(cid, sizeof(cid), "%d", jid->valueint); @@ -151,6 +167,68 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json switch_thread_rwlock_unlock(conference->rwlock); } goto end; + } else if (!strcasecmp(action, "canvasInfo")) { + cJSON *j_member_id; + int member_id = 0; + int i = 0; + cJSON *array = cJSON_CreateArray(); + conference_obj_t *conference; + + if ((conference = conference_find(conference_name, NULL))) { + + if ((j_member_id = cJSON_GetObjectItem(data, "memberID"))) { + if (j_member_id->valueint) { + member_id = j_member_id->valueint; + } else if (j_member_id->valuedouble) { + member_id = (int) j_member_id->valuedouble; + } else if (j_member_id->valuestring) { + member_id = atoi(j_member_id->valuestring); + } + if (member_id < 0) member_id = 0; + } + + if (member_id > 0) { + conference_member_t *member; + + if ((member = conference_member_get(conference, member_id))) { + mcu_canvas_t *canvas; + + if ((canvas = conference_video_get_canvas_locked(member))) { + cJSON *obj; + + if ((obj = get_canvas_info(canvas))) { + cJSON_AddItemToObject(obj, "layerID", cJSON_CreateNumber(member->video_layer_id)); + cJSON_AddItemToArray(array, obj); + } + + conference_video_release_canvas(&canvas); + } + + switch_thread_rwlock_unlock(member->rwlock); + } + + } else { + switch_mutex_lock(conference->canvas_mutex); + + for (i = 0; i <= conference->canvas_count; i++) { + mcu_canvas_t *canvas = conference->canvases[i]; + if (canvas) { + cJSON *obj; + + if ((obj = get_canvas_info(canvas))) { + cJSON_AddItemToArray(array, obj); + } + } + } + + switch_mutex_unlock(conference->canvas_mutex); + } + + switch_thread_rwlock_unlock(conference->rwlock); + } + + addobj = array; + } else if (!strcasecmp(action, "list-videoLayouts")) { switch_hash_index_t *hi; void *val; @@ -161,17 +239,49 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json switch_mutex_lock(conference_globals.setup_mutex); if (conference->layout_hash) { for (hi = switch_core_hash_first(conference->layout_hash); hi; hi = switch_core_hash_next(&hi)) { + video_layout_t *vlayout; + cJSON *obj = cJSON_CreateObject(); + cJSON *resarray = cJSON_CreateArray(); + int i; + switch_core_hash_this(hi, &vvar, NULL, &val); - cJSON_AddItemToArray(array, cJSON_CreateString((char *)vvar)); + vlayout = (video_layout_t *)val; + for (i = 0; i < vlayout->layers; i++) { + if (vlayout->images[i].res_id) { + cJSON_AddItemToArray(resarray, cJSON_CreateString((char *)vlayout->images[i].res_id)); + } + } + + cJSON_AddItemToObject(obj, "type", cJSON_CreateString("layout")); + cJSON_AddItemToObject(obj, "name", cJSON_CreateString((char *)vvar)); + cJSON_AddItemToObject(obj, "resIDS", resarray); + + cJSON_AddItemToArray(array, obj); } } if (conference->layout_group_hash) { for (hi = switch_core_hash_first(conference->layout_group_hash); hi; hi = switch_core_hash_next(&hi)) { char *name; + cJSON *obj = cJSON_CreateObject(); + cJSON *grouparray = cJSON_CreateArray(); + layout_group_t *lg; + video_layout_node_t *vlnode; + switch_core_hash_this(hi, &vvar, NULL, &val); + lg = (layout_group_t *) val; + name = switch_mprintf("group:%s", (char *)vvar); - cJSON_AddItemToArray(array, cJSON_CreateString(name)); + + for (vlnode = lg->layouts; vlnode; vlnode = vlnode->next) { + cJSON_AddItemToArray(grouparray, cJSON_CreateString(vlnode->vlayout->name)); + } + + cJSON_AddItemToObject(obj, "type", cJSON_CreateString("layoutGroup")); + cJSON_AddItemToObject(obj, "name", cJSON_CreateString(name)); + cJSON_AddItemToObject(obj, "groupLayouts", grouparray); + + cJSON_AddItemToArray(array, obj); free(name); } } diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 16d49e481a..36344a815d 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -1629,7 +1629,13 @@ int conference_member_setup_media(conference_member_t *member, conference_obj_t switch_mutex_lock(member->audio_out_mutex); - switch_core_session_get_read_impl(member->session, &read_impl); + if (!member->orig_read_impl.samples_per_second) { + switch_core_session_get_read_impl(member->session, &member->orig_read_impl); + member->native_rate = read_impl.samples_per_second; + } + + read_impl = member->orig_read_impl; + if (switch_core_codec_ready(&member->read_codec)) { switch_core_codec_destroy(&member->read_codec); @@ -1645,9 +1651,6 @@ int conference_member_setup_media(conference_member_t *member, conference_obj_t switch_resample_destroy(&member->read_resampler); } - switch_core_session_get_read_impl(member->session, &member->orig_read_impl); - member->native_rate = read_impl.samples_per_second; - /* Setup a Signed Linear codec for reading audio. */ if (switch_core_codec_init(&member->read_codec, "L16", diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index 489564e6e5..6a16604226 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -1921,9 +1921,17 @@ void conference_video_check_auto_bitrate(conference_member_t *member, mcu_layer_ switch_channel_get_name(member->channel), kps); } else { int max = 0; + switch_vid_params_t vid_params = { 0 }; + + switch_core_media_get_vid_params(member->session, &vid_params); + + if (w > vid_params.width || h > vid_params.height) { + w = vid_params.width; + h = vid_params.height; + } if (layer) { - kps = switch_calc_bitrate(w, h, 1, (int)(member->conference->video_fps.fps)); + kps = switch_calc_bitrate(w, h, member->conference->video_quality, (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); } @@ -2024,7 +2032,8 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr int do_refresh = 0; int last_file_count = 0; int layout_applied = 0; - + int files_playing = 0; + canvas->video_timer_reset = 1; packet = switch_core_alloc(conference->pool, SWITCH_RTP_MAX_BUF_LEN); @@ -2058,9 +2067,8 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr canvas->send_keyframe = 1; } - if (!conference->playing_video_file) { - switch_core_timer_next(&canvas->timer); - } + + switch_core_timer_next(&canvas->timer); now = switch_micro_time_now(); @@ -2080,8 +2088,9 @@ 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) { - if (imember->channel && switch_channel_ready(imember->channel) && conference_utils_member_test_flag(imember, MFLAG_RUNNING) - && imember->canvas_id == canvas->canvas_id) { + if (imember->channel && switch_channel_ready(imember->channel) && switch_channel_test_flag(imember->channel, CF_VIDEO) && + conference_utils_member_test_flag(imember, MFLAG_RUNNING) + && imember->canvas_id == canvas->canvas_id && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY) { canvas_count++; } } @@ -2105,11 +2114,13 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr if (conference->async_fnode && switch_core_file_has_video(&conference->async_fnode->fh)) { check_async_file = 1; file_count++; + files_playing = 1; } if (conference->fnode && switch_core_file_has_video(&conference->fnode->fh)) { check_file = 1; file_count++; + files_playing = 1; } if (file_count != last_file_count) { @@ -2211,11 +2222,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr continue; } - if (conference->playing_video_file) { - switch_core_session_rwunlock(imember->session); - continue; - } - //VIDFLOOR if (canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder && imember->video_layer_id != canvas->layout_floor_id) { @@ -2226,6 +2232,13 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr layer = NULL; + if (conference->playing_video_file) { + switch_img_free(&img); + switch_core_session_rwunlock(imember->session); + continue; + } + + switch_mutex_lock(canvas->mutex); @@ -2381,7 +2394,9 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr if (count_changed) { int total = conference->members_with_video; - + int kps; + switch_vid_params_t vid_params = { 0 }; + if (!conference_utils_test_flag(conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS)) { total += conference->members_with_avatar; } @@ -2401,6 +2416,13 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr conference_video_init_canvas_layers(conference, imember->canvas, vlayout); } } + + if (!switch_channel_test_flag(imember->channel, CF_VIDEO_BITRATE_UNMANAGABLE) && + conference_utils_test_flag(conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE)) { + switch_core_media_get_vid_params(imember->session, &vid_params); + kps = switch_calc_bitrate(vid_params.width, vid_params.height, conference->video_quality, (int)(imember->conference->video_fps.fps)); + conference_video_set_incoming_bitrate(imember, kps); + } } if (switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY) { @@ -2416,18 +2438,28 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr } if (check_async_file) { - if (switch_core_file_read_video(&conference->async_fnode->fh, &file_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + switch_status_t st = switch_core_file_read_video(&conference->async_fnode->fh, &file_frame, SVR_FLUSH); + + if (st == SWITCH_STATUS_SUCCESS) { if ((async_file_img = file_frame.img)) { + switch_img_free(&file_imgs[j]); file_imgs[j++] = async_file_img; } + } else if (st == SWITCH_STATUS_BREAK) { + j++; } } if (check_file) { - if (switch_core_file_read_video(&conference->fnode->fh, &file_frame, SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + switch_status_t st = switch_core_file_read_video(&conference->fnode->fh, &file_frame, SVR_FLUSH); + + if (st == SWITCH_STATUS_SUCCESS) { if ((normal_file_img = file_frame.img)) { + switch_img_free(&file_imgs[j]); file_imgs[j++] = normal_file_img; } + } else if (st == SWITCH_STATUS_BREAK) { + j++; } } @@ -2440,13 +2472,15 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr 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); + if (files_playing && !file_count) { + 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; } - i = 0; - + if (!file_count && imember->canvas->layout_floor_id > -1 && imember->conference->video_floor_holder && imember->id != imember->conference->video_floor_holder) { @@ -2477,7 +2511,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr 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) { @@ -2539,8 +2572,6 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr conference_video_scale_and_patch(layer, use_img, SWITCH_FALSE); } } - - conference_video_check_auto_bitrate(omember, layer); } for (j = 0; j < file_count; j++) { @@ -2558,8 +2589,11 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr switch_core_session_rwunlock(imember->session); } - switch_img_free(&normal_file_img); - switch_img_free(&async_file_img); + if (files_playing && !file_count) { + switch_img_free(&file_imgs[0]); + switch_img_free(&file_imgs[1]); + files_playing = 0; + } for (imember = conference->members; imember; imember = imember->next) { switch_frame_t *dupframe; @@ -2595,7 +2629,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr switch_mutex_unlock(conference->member_mutex); } else { - + if (conference->async_fnode && (conference->async_fnode->canvas_id == canvas->canvas_id || conference->async_fnode->canvas_id == -1)) { if (conference->async_fnode->layer_id > -1) { conference_video_patch_fnode(canvas, conference->async_fnode); @@ -2686,20 +2720,20 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr if (canvas->play_file) { canvas->send_keyframe = 1; canvas->play_file = 0; - - canvas->timer.interval = 1; - canvas->timer.samples = 90; } - write_img = file_img = write_frame.img; + switch_img_free(&file_img); + file_img = write_img = write_frame.img; switch_core_timer_sync(&canvas->timer); timestamp = canvas->timer.samplecount; + } else if (file_img) { + write_img = file_img; } } else if (file_img) { switch_img_free(&file_img); } - + write_frame.img = write_img; wait_for_canvas(canvas); @@ -2893,9 +2927,7 @@ void *SWITCH_THREAD_FUNC conference_video_super_muxing_thread_run(switch_thread_ canvas->send_keyframe = 1; } - if (!conference->playing_video_file) { - switch_core_timer_next(&canvas->timer); - } + switch_core_timer_next(&canvas->timer); now = switch_micro_time_now(); @@ -3446,11 +3478,10 @@ void conference_video_write_frame(conference_obj_t *conference, conference_membe continue; } - if (!isession || !switch_channel_test_flag(imember->channel, CF_VIDEO) ) { - continue; + if (switch_channel_test_flag(imember->channel, CF_VIDEO) ) { + switch_core_session_request_video_refresh(imember->session); } - - switch_core_session_request_video_refresh(imember->session); + switch_core_session_rwunlock(isession); } } diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index a62896c1ec..f9c9fc68c9 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -2410,6 +2410,7 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co char *video_codec_bandwidth = NULL; char *no_video_avatar = NULL; conference_video_mode_t conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH; + int conference_video_quality = 1; float fps = 15.0f; uint32_t max_members = 0; uint32_t announce_count = 0; @@ -2721,6 +2722,15 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co terminate_on_silence = val; } else if (!strcasecmp(var, "endconf-grace-time") && !zstr(val)) { endconference_grace_time = val; + } else if (!strcasecmp(var, "video-quality") && !zstr(val)) { + int tmp = atoi(val); + + if (tmp > 0 && tmp < 5) { + conference_video_quality = tmp; + } else { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "Video quality must be between 1 and 4\n"); + } + } else if (!strcasecmp(var, "video-mode") && !zstr(val)) { if (!strcasecmp(val, "passthrough")) { conference_video_mode = CONF_VIDEO_MODE_PASSTHROUGH; @@ -2789,8 +2799,8 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co conference->caller_controls = switch_core_strdup(conference->pool, caller_controls); conference->moderator_controls = switch_core_strdup(conference->pool, moderator_controls); conference->broadcast_chat_messages = broadcast_chat_messages; - - + conference->video_quality = conference_video_quality; + conference->conference_video_mode = conference_video_mode; if (!switch_core_has_video() && (conference->conference_video_mode == CONF_VIDEO_MODE_MUX || conference->conference_video_mode == CONF_VIDEO_MODE_TRANSCODE)) { @@ -2864,7 +2874,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, 1, (int)conference->video_fps.fps); + conference->video_codec_settings.video.bandwidth = switch_calc_bitrate(canvas_w, canvas_h, conference->video_quality, (int)conference->video_fps.fps); } else { conference->video_codec_settings.video.bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth); } diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index 4ad382d8dd..7c9793686b 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -560,6 +560,7 @@ typedef struct conference_obj { char *video_letterbox_bgcolor; char *no_video_avatar; conference_video_mode_t conference_video_mode; + int video_quality; int members_with_video; int members_with_avatar; switch_codec_settings_t video_codec_settings; diff --git a/src/mod/applications/mod_httapi/mod_httapi.c b/src/mod/applications/mod_httapi/mod_httapi.c index 93a70972f8..62055d736f 100644 --- a/src/mod/applications/mod_httapi/mod_httapi.c +++ b/src/mod/applications/mod_httapi/mod_httapi.c @@ -2206,7 +2206,7 @@ static switch_status_t my_on_reporting(switch_core_session_t *session) var = switch_event_get_header(client->params, "url"); - if (client->record.action) { + if (var && client->record.action) { if (strcmp(var, client->record.action)) { switch_event_add_header_string(client->one_time_params, SWITCH_STACK_BOTTOM, "url", client->record.action); httapi_sync(client); diff --git a/src/mod/codecs/mod_vpx/mod_vpx.c b/src/mod/codecs/mod_vpx/mod_vpx.c index 44e93fc4d8..2826cb8866 100644 --- a/src/mod/codecs/mod_vpx/mod_vpx.c +++ b/src/mod/codecs/mod_vpx/mod_vpx.c @@ -321,7 +321,7 @@ static switch_status_t init_encoder(switch_codec_t *codec) } - sane = switch_calc_bitrate(context->codec_settings.video.width, context->codec_settings.video.height, 1, 30); + sane = switch_calc_bitrate(1920, 1080, 2, 30); if (context->bandwidth > sane) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(codec->session), SWITCH_LOG_WARNING, "BITRATE TRUNCATED FROM %d TO %d\n", context->bandwidth, sane); diff --git a/src/mod/endpoints/mod_sofia/mod_sofia.c b/src/mod/endpoints/mod_sofia/mod_sofia.c index 750bbf84d6..12932bec75 100644 --- a/src/mod/endpoints/mod_sofia/mod_sofia.c +++ b/src/mod/endpoints/mod_sofia/mod_sofia.c @@ -28,7 +28,7 @@ * Paul D. Tinsley * Bret McDanel * Raymond Chandler - * Emmanuel Schmidbauer + * Emmanuel Schmidbauer * * * mod_sofia.c -- SOFIA SIP Endpoint @@ -1877,14 +1877,21 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi if (!zstr(msg->string_arg)) { if (!switch_channel_test_flag(channel, CF_ANSWERED) && !sofia_test_flag(tech_pvt, TFLAG_BYE)) { - char *dest = (char *) msg->string_arg; + char *mydest = (char *) msg->string_arg; char *argv[MAX_REDIR] = { 0 }; char *mydata = NULL, *newdest = NULL; int argc = 0, i; switch_size_t len = 0; + switch_call_cause_t sip_redirect_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED; + char *dest = switch_core_session_strdup(session, mydest); + + if ((argc = switch_separate_string(dest, ' ', argv, (sizeof(argv) / sizeof(argv[0])))) >= 2) { + const char *redirect_cause = argv[1]; + sip_redirect_cause = switch_channel_str2cause(redirect_cause); + } if (strchr(dest, ',')) { - mydata = switch_core_session_strdup(session, dest); + mydata = dest; len = strlen(mydata) * 2; newdest = switch_core_session_alloc(session, len); @@ -1936,7 +1943,10 @@ static switch_status_t sofia_receive_message(switch_core_session_t *session, swi tech_pvt->respond_phrase = "Moved Temporarily"; } - switch_channel_hangup(tech_pvt->channel, sofia_glue_sip_cause_to_freeswitch(tech_pvt->respond_code)); + if (sip_redirect_cause == SWITCH_CAUSE_NONE) { + sip_redirect_cause = SWITCH_CAUSE_NORMAL_UNSPECIFIED; + } + switch_channel_hangup(tech_pvt->channel, sip_redirect_cause); } else { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_WARNING, "Too late for redirecting, already answered\n"); diff --git a/src/mod/endpoints/mod_sofia/sofia.c b/src/mod/endpoints/mod_sofia/sofia.c index 96f28eac92..941668bf47 100644 --- a/src/mod/endpoints/mod_sofia/sofia.c +++ b/src/mod/endpoints/mod_sofia/sofia.c @@ -5472,6 +5472,11 @@ switch_status_t config_sofia(sofia_config_t reload, char *profile_name) sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION); } + if (sofia_test_flag(profile, TFLAG_INB_NOMEDIA) && !sofia_test_flag(profile, TFLAG_LATE_NEGOTIATION)) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "inbound-bypass-media implictly enables inbound-late-negotiation\n"); + sofia_set_flag(profile, TFLAG_LATE_NEGOTIATION); + } + if (sofia_test_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE) && !sofia_test_pflag(profile, PFLAG_ALLOW_UPDATE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "send-display-update=true is set, but we can't comply because allow-update=false\n"); sofia_clear_pflag(profile, PFLAG_SEND_DISPLAY_UPDATE); diff --git a/src/mod/endpoints/mod_verto/ws.h b/src/mod/endpoints/mod_verto/ws.h index 66231db419..1d020d0b33 100644 --- a/src/mod/endpoints/mod_verto/ws.h +++ b/src/mod/endpoints/mod_verto/ws.h @@ -25,7 +25,7 @@ //#include "sha1.h" #include -#ifdef _MSC_VER +#if defined(_MSC_VER) || defined(__APPLE__) #define __bswap_64(x) \ x = (x>>56) | \ ((x<<40) & 0x00FF000000000000) | \ @@ -35,6 +35,8 @@ ((x>>24) & 0x0000000000FF0000) | \ ((x>>40) & 0x000000000000FF00) | \ (x<<56) +#endif +#ifdef _MSC_VER #ifndef strncasecmp #define strncasecmp _strnicmp #endif diff --git a/src/switch_channel.c b/src/switch_channel.c index 5d21a4d7a7..b6e282ced5 100644 --- a/src/switch_channel.c +++ b/src/switch_channel.c @@ -3799,7 +3799,7 @@ SWITCH_DECLARE(switch_status_t) switch_channel_perform_answer(switch_channel_t * } - if (switch_core_session_in_thread(channel->session)) { + if (switch_core_session_in_thread(channel->session) && !switch_channel_test_flag(channel, CF_PROXY_MODE)) { const char *delay; if (switch_channel_test_flag(channel, CF_VIDEO)) { diff --git a/src/switch_ivr_async.c b/src/switch_ivr_async.c index eaf68ec636..bd6cb6f34f 100644 --- a/src/switch_ivr_async.c +++ b/src/switch_ivr_async.c @@ -79,6 +79,7 @@ struct switch_ivr_dmachine { void *user_data; switch_mutex_t *mutex; switch_status_t last_return; + uint8_t pinging; }; @@ -487,6 +488,12 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * return SWITCH_STATUS_SUCCESS; } + if (dmachine->pinging) { + return SWITCH_STATUS_BREAK; + } + + dmachine->pinging = 1; + if (zstr(dmachine->digits) && !is_timeout) { r = SWITCH_STATUS_SUCCESS; } else if (dmachine->cur_digit_len > dmachine->max_digit_len) { @@ -579,6 +586,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_ping(switch_ivr_dmachine_t * dmachine->last_return = r; + dmachine->pinging = 0; + switch_mutex_unlock(dmachine->mutex); return r; @@ -608,6 +617,7 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_dmachine_feed(switch_ivr_dmachine_t * status = istatus; } } else { + switch_mutex_unlock(dmachine->mutex); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "dmachine overflow error!\n"); status = SWITCH_STATUS_FALSE; } diff --git a/src/switch_ivr_bridge.c b/src/switch_ivr_bridge.c index d17d3fa77c..5e8a5a50be 100644 --- a/src/switch_ivr_bridge.c +++ b/src/switch_ivr_bridge.c @@ -1698,6 +1698,8 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_call_cause_t cause = switch_channel_get_cause(peer_channel); const char *hup = switch_channel_get_variable(caller_channel, SWITCH_HANGUP_AFTER_BRIDGE_VARIABLE); int explicit = 0; + int answered = 0; + int early = 0; if (cause == SWITCH_CAUSE_NONE) { cause = SWITCH_CAUSE_NORMAL_CLEARING; @@ -1718,16 +1720,21 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_multi_threaded_bridge(switch_core_ses switch_channel_hangup(caller_channel, cause); } - if ((state != CS_EXECUTE && state != CS_SOFT_EXECUTE && state != CS_PARK && state != CS_ROUTING) || - (switch_channel_test_flag(peer_channel, CF_ANSWERED) && state < CS_HANGUP)) { + answered = switch_channel_test_flag(peer_channel, CF_ANSWERED); + early = switch_channel_test_flag(peer_channel, CF_EARLY_MEDIA); + + if ((state != CS_EXECUTE && state != CS_SOFT_EXECUTE && state != CS_PARK && state != CS_ROUTING) || ((answered || early) && state < CS_HANGUP)) { if (!switch_channel_test_flag(caller_channel, CF_TRANSFER)) { - if (switch_true(switch_channel_get_variable(caller_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE))) { + + if ((answered && switch_true(switch_channel_get_variable(caller_channel, SWITCH_PARK_AFTER_BRIDGE_VARIABLE))) || + switch_true(switch_channel_get_variable(caller_channel, SWITCH_PARK_AFTER_EARLY_BRIDGE_VARIABLE))) { switch_ivr_park_session(session); - } else if ((var = switch_channel_get_variable(caller_channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE))) { + } else if ((answered && (var = switch_channel_get_variable(caller_channel, SWITCH_TRANSFER_AFTER_BRIDGE_VARIABLE))) || + (var = switch_channel_get_variable(caller_channel, SWITCH_TRANSFER_AFTER_EARLY_BRIDGE_VARIABLE))) { transfer_after_bridge(session, var); - } else { - if ((switch_channel_test_flag(peer_channel, CF_ANSWERED) && switch_true(hup))) { + } else if (answered) { + if (switch_true(hup)) { if (switch_channel_test_flag(peer_channel, CF_INTERCEPTED)) { switch_channel_set_flag(peer_channel, CF_INTERCEPT); } diff --git a/src/switch_ivr_originate.c b/src/switch_ivr_originate.c index c65b80b7d4..6b03c1739d 100644 --- a/src/switch_ivr_originate.c +++ b/src/switch_ivr_originate.c @@ -1863,6 +1863,7 @@ static void *SWITCH_THREAD_FUNC early_thread_run(switch_thread_t *thread, void * if (!session) continue; if (switch_core_codec_ready((&read_codecs[i]))) { + switch_core_session_set_read_codec(session, NULL); switch_core_codec_destroy(&read_codecs[i]); } diff --git a/src/switch_ivr_play_say.c b/src/switch_ivr_play_say.c index 968c7d031d..89325b2c83 100644 --- a/src/switch_ivr_play_say.c +++ b/src/switch_ivr_play_say.c @@ -1490,12 +1490,14 @@ SWITCH_DECLARE(switch_status_t) switch_ivr_play_file(switch_core_session_t *sess if you return anything but SWITCH_STATUS_SUCCESS the playback will stop. */ if (switch_channel_has_dtmf(channel)) { + switch_channel_dequeue_dtmf(channel, &dtmf); + if (!args->input_callback && !args->buf && !args->dmachine) { status = SWITCH_STATUS_BREAK; done = 1; break; } - switch_channel_dequeue_dtmf(channel, &dtmf); + if (args->dmachine) { char ds[2] = {dtmf.digit, '\0'}; diff --git a/src/switch_rtp.c b/src/switch_rtp.c index c04d626a59..f9a16e9839 100644 --- a/src/switch_rtp.c +++ b/src/switch_rtp.c @@ -3259,7 +3259,9 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d const char *kind = ""; BIO *bio; DH *dh; +#ifndef OPENSSL_NO_EC EC_KEY* ecdh; +#endif #ifndef HAVE_OPENSSL_DTLS_SRTP return SWITCH_STATUS_FALSE; @@ -3367,6 +3369,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d SSL_set_read_ahead(dtls->ssl, 1); //SSL_set_verify(dtls->ssl, (SSL_VERIFY_PEER | SSL_VERIFY_FAIL_IF_NO_PEER_CERT), cb_verify_peer); +#ifndef OPENSSL_NO_EC ecdh = EC_KEY_new_by_curve_name(NID_X9_62_prime256v1); if (!ecdh) { return SWITCH_STATUS_FALSE; @@ -3374,6 +3377,7 @@ SWITCH_DECLARE(switch_status_t) switch_rtp_add_dtls(switch_rtp_t *rtp_session, d SSL_set_options(dtls->ssl, SSL_OP_SINGLE_ECDH_USE); SSL_set_tmp_ecdh(dtls->ssl, ecdh); EC_KEY_free(ecdh); +#endif SSL_set_verify(dtls->ssl, SSL_VERIFY_NONE, NULL); SSL_set_app_data(dtls->ssl, dtls); @@ -6724,6 +6728,7 @@ static int rtp_common_read(switch_rtp_t *rtp_session, switch_payload_t *payload_ case RESULT_GOTO_TIMERCHECK: goto timer_check; case RESULT_CONTINUE: + status = SWITCH_STATUS_SUCCESS; goto result_continue; }