diff --git a/conf/vanilla/autoload_configs/conference_layouts.conf.xml b/conf/vanilla/autoload_configs/conference_layouts.conf.xml index 3620f64011..9ba756c210 100644 --- a/conf/vanilla/autoload_configs/conference_layouts.conf.xml +++ b/conf/vanilla/autoload_configs/conference_layouts.conf.xml @@ -12,6 +12,11 @@ + + + + + @@ -300,11 +305,14 @@ + + 1x1 2x1 + 1x1+2x1 2x2 3x3 4x4 diff --git a/html5/verto/js/src/jquery.FSRTC.js b/html5/verto/js/src/jquery.FSRTC.js index fcd300d185..663f804164 100644 --- a/html5/verto/js/src/jquery.FSRTC.js +++ b/html5/verto/js/src/jquery.FSRTC.js @@ -491,7 +491,7 @@ var iceTimer; } if (bestFrameRate && !window.moz) { - video.optional.push({minFrameRate: bestFrameRate}); + video.optional.push({minFrameRate: bestFrameRate}); } } else { diff --git a/html5/verto/js/src/jquery.verto.js b/html5/verto/js/src/jquery.verto.js index bef4f49bc6..0297ff1bb6 100644 --- a/html5/verto/js/src/jquery.verto.js +++ b/html5/verto/js/src/jquery.verto.js @@ -76,15 +76,21 @@ videoParams: {}, audioParams: {}, loginParams: {}, + deviceParams: {}, userVariables: {}, iceServers: false, - ringSleep: 6000 + ringSleep: 6000, + sessid: null }, options); - verto.sessid = $.cookie('verto_session_uuid') || generateGUID(); - $.cookie('verto_session_uuid', verto.sessid, { - expires: 1 - }); + if (verto.options.sessid) { + verto.sessid = verto.options.sessid; + } else { + verto.sessid = $.cookie('verto_session_uuid') || generateGUID(); + $.cookie('verto_session_uuid', verto.sessid, { + expires: 1 + }); + } verto.dialogs = {}; verto.callbacks = callbacks || {}; @@ -1160,6 +1166,8 @@ var CONFMAN_SERNO = 1; + $.verto.modfuncs = {}; + $.verto.confMan = function(verto, params) { var confMan = this; @@ -1177,7 +1185,8 @@ confMan.verto = verto; confMan.serno = CONFMAN_SERNO++; - + confMan.canvasCount = confMan.params.laData.canvasCount; + function genMainMod(jq) { var play_id = "play_" + confMan.serno; var stop_id = "stop_" + confMan.serno; @@ -1186,8 +1195,6 @@ var rec_stop_id = "recording_stop" + confMan.serno; var div_id = "confman_" + confMan.serno; - - var html = "

" + "" + "" + @@ -1198,21 +1205,25 @@ jq.html(html); - if (confMan.params.hasVid) { - var vlayout_id = "confman_vid_layout_" + confMan.serno; - var vlselect_id = "confman_vl_select_" + confMan.serno; - - var vlhtml = "

" + - "Video Layout " + - "

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

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

"; + jq.append(vlhtml); + } $("#" + snapshot_id).click(function() { var file = prompt("Please enter file name", ""); @@ -1249,6 +1260,18 @@ function genControls(jq, rowid) { var x = parseInt(rowid); var kick_id = "kick_" + x; + var canvas_in_next_id = "canvas_in_next_" + x; + var canvas_in_prev_id = "canvas_in_prev_" + x; + var canvas_out_next_id = "canvas_out_next_" + x; + var canvas_out_prev_id = "canvas_out_prev_" + x; + + var canvas_in_set_id = "canvas_in_set_" + x; + var canvas_out_set_id = "canvas_out_set_" + x; + + var layer_set_id = "layer_set_" + x; + var layer_next_id = "layer_next_" + x; + var layer_prev_id = "layer_prev_" + x; + var tmute_id = "tmute_" + x; var tvmute_id = "tvmute_" + x; var vbanner_id = "vbanner_" + x; @@ -1260,21 +1283,52 @@ var transfer_id = "transfer" + x; - var html = "
" + - "" + + var html = "
"; + + html += "General Controls
"; + + html += "" + "" + - (confMan.params.hasVid ? "" : "") + - (confMan.params.hasVid ? "" : "") + - (confMan.params.hasVid ? "" : "") + - (confMan.params.hasVid ? "" : "") + "" + "" + - "" + - "
" - ; + ""; + + if (confMan.params.hasVid) { + html += "

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

Canvas Controls
" + + "" + + "" + + "" + + + "
" + + + "" + + "" + + ""; + } + + html += "
" + + + "" + + "" + + "" + + + + + "
"; + } jq.html(html); + if (!jq.data("mouse")) { $("#" + box_id).hide(); } @@ -1300,6 +1354,50 @@ confMan.modCommand("kick", x); }); + + $("#" + layer_set_id).click(function() { + var cid = prompt("Please enter layer ID", ""); + if (cid) { + confMan.modCommand("vid-layer", x, cid); + } + }); + + $("#" + layer_next_id).click(function() { + confMan.modCommand("vid-layer", x, "next"); + }); + $("#" + layer_prev_id).click(function() { + confMan.modCommand("vid-layer", x, "prev"); + }); + + $("#" + canvas_in_set_id).click(function() { + var cid = prompt("Please enter canvas ID", ""); + if (cid) { + confMan.modCommand("vid-canvas", x, cid); + } + }); + + $("#" + canvas_out_set_id).click(function() { + var cid = prompt("Please enter canvas ID", ""); + if (cid) { + confMan.modCommand("vid-watching-canvas", x, cid); + } + }); + + $("#" + canvas_in_next_id).click(function() { + confMan.modCommand("vid-canvas", x, "next"); + }); + $("#" + canvas_in_prev_id).click(function() { + confMan.modCommand("vid-canvas", x, "prev"); + }); + + + $("#" + canvas_out_next_id).click(function() { + confMan.modCommand("vid-watching-canvas", x, "next"); + }); + $("#" + canvas_out_prev_id).click(function() { + confMan.modCommand("vid-watching-canvas", x, "prev"); + }); + $("#" + tmute_id).click(function() { confMan.modCommand("tmute", x); }); @@ -1340,7 +1438,7 @@ if (confMan.params.laData.role === "moderator") { atitle = "Action"; - awidth = 300; + awidth = 600; if (confMan.params.mainModID) { genMainMod($(confMan.params.mainModID)); @@ -1357,30 +1455,33 @@ } if (e.data["conf-command"] === "list-videoLayouts") { - var vlselect_id = "#confman_vl_select_" + confMan.serno; - var vlayout_id = "#confman_vid_layout_" + confMan.serno; - var x = 0; - var options; - - $(vlselect_id).selectmenu({}); - $(vlselect_id).selectmenu("enable"); - $(vlselect_id).empty(); - - $(vlselect_id).append(new Option("Choose a Layout", "none")); + for (var j = 0; j < confMan.canvasCount; j++) { + var vlselect_id = "#confman_vl_select_" + j + "_" + confMan.serno; + var vlayout_id = "#confman_vid_layout_" + j + "_" + confMan.serno; + + var x = 0; + var options; + + $(vlselect_id).selectmenu({}); + $(vlselect_id).selectmenu("enable"); + $(vlselect_id).empty(); + + $(vlselect_id).append(new Option("Choose a Layout", "none")); - if (e.data.responseData) { - options = e.data.responseData.sort(); + if (e.data.responseData) { + options = e.data.responseData.sort(); - for (var i in options) { - $(vlselect_id).append(new Option(options[i], options[i])); - x++; + 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(); + if (x) { + $(vlselect_id).selectmenu('refresh', true); + } else { + $(vlayout_id).hide(); + } } } else { @@ -1432,16 +1533,20 @@ "aaData": [], "aoColumns": [ { - "sTitle": "ID" + "sTitle": "ID", + "sWidth": "50" }, { - "sTitle": "Number" + "sTitle": "Number", + "sWidth": "250" }, { - "sTitle": "Name" + "sTitle": "Name", + "sWidth": "250" }, { - "sTitle": "Codec" + "sTitle": "Codec", + "sWidth": "100" }, { "sTitle": "Status", @@ -1459,7 +1564,7 @@ "bFilter": false, "bLengthChange": false, "bPaginate": false, - "iDisplayLength": 1000, + "iDisplayLength": 1400, "oLanguage": { "sEmptyTable": "The Conference is Empty....." @@ -1519,6 +1624,9 @@ videoParams: verto.options.videoParams }, params); + dialog.useCamera = verto.options.deviceParams.useCamera; + dialog.useMic = verto.options.deviceParams.useMic; + dialog.verto = verto; dialog.direction = direction; dialog.lastState = null; @@ -1957,12 +2065,17 @@ params.sdp = dialog.params.sdp; + dialog.useCamera = verto.options.deviceParams.useCamera; + dialog.useMic = verto.options.deviceParams.useMic; + if (params) { if (params.useVideo) { dialog.useVideo(true); } dialog.params.callee_id_name = params.callee_id_name; dialog.params.callee_id_number = params.callee_id_number; + dialog.useCamera = params.useCamera; + dialog.useMic = params.useMic; } dialog.rtc.createAnswer(params); @@ -2130,8 +2243,14 @@ $.verto.enum = Object.freeze($.verto.enum); $.verto.saved = []; + + $.verto.unloadJobs = []; $(window).bind('beforeunload', function() { + for (var f in $.verto.unloadJobs) { + $.verto.unloadJobs[f](); + } + for (var i in $.verto.saved) { var verto = $.verto.saved[i]; if (verto) { @@ -2139,6 +2258,7 @@ verto.logout(); } } + return $.verto.warnOnUnload; }); @@ -2216,4 +2336,9 @@ }); } + $.verto.genUUID = function () { + return generateGUID(); + } + + })(jQuery); diff --git a/html5/verto/video_demo/images/search.gif b/html5/verto/video_demo/images/search.gif new file mode 100644 index 0000000000..7bce165967 Binary files /dev/null and b/html5/verto/video_demo/images/search.gif differ diff --git a/html5/verto/video_demo/index.html b/html5/verto/video_demo/index.html index 6725e38ad1..548d269e49 100644 --- a/html5/verto/video_demo/index.html +++ b/html5/verto/video_demo/index.html @@ -2,6 +2,14 @@ + + + + + + + + @@ -16,9 +24,11 @@ } .ctlbtn { - border: 0px; - color: #eeeeee; - background-color: #0000ae; + border: 2px; + border-style:outset; + color: #ffffff; + min-width: 125px; + background-color: #666666; font-face: arial; height:18px; font-size:7pt; @@ -73,6 +83,7 @@ max-height:40px; } +div#preload { display: none; } @@ -86,6 +97,17 @@
+
+ + + +
+ +
+

@@ -184,6 +228,7 @@ +
@@ -300,12 +345,10 @@ if ($('#devices').is(':visible')) { - + - -

+ -
@@ -422,7 +465,7 @@ if ($('#devices').is(':visible')) {

- +


@@ -474,10 +517,25 @@ if ($('#devices').is(':visible')) {
+
+ + +
+ +
+ + +
+
-
+
+ + + + +

@@ -587,7 +645,14 @@ if ($('#devices').is(':visible')) { + + + + + diff --git a/html5/verto/video_demo/js/jquery.hipchat.js b/html5/verto/video_demo/js/jquery.hipchat.js new file mode 100644 index 0000000000..e0e418ae6d --- /dev/null +++ b/html5/verto/video_demo/js/jquery.hipchat.js @@ -0,0 +1,47 @@ +(function ($) { + + // Creates an iframe with an embedded HipChat conversation window. + // + // Options: + // url - The url to the room to embed; required + // container - The container in which to insert the HipChat panel; required + // timezone - The timezone to use in the embedded room; required + // welcome - A welcome message to display when the room is joined; optional + // noframes - Content to include when iframes are disabled in the browser; optional + // width - The width of the iframe; defaults to 100% + // height - The height of the iframe; defaults to 400px + $.createHipChat = function (options) { + if (options && options.url && options.container && options.timezone) { + var $container = $(options.container); + if ($container.length === 0) return; + var params = { + anonymous: 0, + timezone: options.timezone, + minimal: 0 + }; + if (options.welcome) { + params.welcome_msg = options.welcome; + } + var url = options.url + (options.url.indexOf('?') > 0 ? '&' : '?') + $.param(params); + if (url.indexOf('https://') !== 0) { + url = 'https://' + url; + } + var w = options.width || '100%'; + var h = options.height || 400; + var nf = (options.noframes || ''); + return { + show: function () { + $container.html(''); + } + }; + } + }; + + $.fn.hipChatPanel = function (options) { + options.container = this[0]; + var panel = $.createHipChat(options); + this.html('') + .find('.show-hipchat').click(function (e) { panel.show(); }); + }; + +}(jQuery)); diff --git a/html5/verto/video_demo/js/md5.min.js b/html5/verto/video_demo/js/md5.min.js new file mode 100644 index 0000000000..11b1545602 --- /dev/null +++ b/html5/verto/video_demo/js/md5.min.js @@ -0,0 +1 @@ +!function(a){"use strict";function b(a,b){var c=(65535&a)+(65535&b),d=(a>>16)+(b>>16)+(c>>16);return d<<16|65535&c}function c(a,b){return a<>>32-b}function d(a,d,e,f,g,h){return b(c(b(b(d,a),b(f,h)),g),e)}function e(a,b,c,e,f,g,h){return d(b&c|~b&e,a,b,f,g,h)}function f(a,b,c,e,f,g,h){return d(b&e|c&~e,a,b,f,g,h)}function g(a,b,c,e,f,g,h){return d(b^c^e,a,b,f,g,h)}function h(a,b,c,e,f,g,h){return d(c^(b|~e),a,b,f,g,h)}function i(a,c){a[c>>5]|=128<>>9<<4)+14]=c;var d,i,j,k,l,m=1732584193,n=-271733879,o=-1732584194,p=271733878;for(d=0;d>5]>>>b%32&255);return c}function k(a){var b,c=[];for(c[(a.length>>2)-1]=void 0,b=0;b>5]|=(255&a.charCodeAt(b/8))<16&&(e=i(e,8*a.length)),c=0;16>c;c+=1)f[c]=909522486^e[c],g[c]=1549556828^e[c];return d=i(f.concat(k(b)),512+8*b.length),j(i(g.concat(d),640))}function n(a){var b,c,d="0123456789abcdef",e="";for(c=0;c>>4&15)+d.charAt(15&b);return e}function o(a){return unescape(encodeURIComponent(a))}function p(a){return l(o(a))}function q(a){return n(p(a))}function r(a,b){return m(o(a),o(b))}function s(a,b){return n(r(a,b))}function t(a,b,c){return b?c?r(b,a):s(b,a):c?p(a):q(a)}"function"==typeof define&&define.amd?define(function(){return t}):a.md5=t}(this); \ No newline at end of file diff --git a/html5/verto/video_demo/js/verto-min.js b/html5/verto/video_demo/js/verto-min.js index 4edb39ccea..558d66893c 100644 --- a/html5/verto/video_demo/js/verto-min.js +++ b/html5/verto/video_demo/js/verto-min.js @@ -117,7 +117,8 @@ for(i=0;i-1){dt.fnClearTable();dt.fnAddData(obj.asArray());}else{dt.fnAddData(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++;} -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.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="

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

";jq.html(html);if(confMan.params.hasVid){var vlayout_id="confman_vid_layout_"+confMan.serno;var vlselect_id="confman_vl_select_"+confMan.serno;var vlhtml="

"+"Video Layout "+"

";jq.append(vlhtml);$("#"+vlselect_id).change(function(){var val=$("#"+vlselect_id).find(":selected").val();if(val!=="none"){confMan.modCommand("vid-layout",null,val);}});$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});} +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.modfuncs={};$.verto.confMan=function(verto,params){var confMan=this;confMan.params=$.extend({tableID:null,statusID:null,mainModID:null,dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);confMan.verto=verto;confMan.serno=CONFMAN_SERNO++;confMan.canvasCount=confMan.params.laData.canvasCount;function genMainMod(jq){var play_id="play_"+confMan.serno;var stop_id="stop_"+confMan.serno;var recording_id="recording_"+confMan.serno;var snapshot_id="snapshot_"+confMan.serno;var rec_stop_id="recording_stop"+confMan.serno;var div_id="confman_"+confMan.serno;var html="

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

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

";jq.append(vlhtml);} +$("#"+snapshot_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("vid-write-png",null,file);}});} $("#"+play_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("play",null,file);}});$("#"+stop_id).click(function(){confMan.modCommand("stop",null,"all");});$("#"+recording_id).click(function(){var file=prompt("Please enter file name","");if(file){confMan.modCommand("recording",null,["start",file]);}});$("#"+rec_stop_id).click(function(){confMan.modCommand("recording",null,["stop","all"]);});} -function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var volup_id="volume_in_up"+x;var voldn_id="volume_in_dn"+x;var transfer_id="transfer"+x;var html="
"+""+""+ -(confMan.params.hasVid?"":"")+ -(confMan.params.hasVid?"":"")+ -(confMan.params.hasVid?"":"")+ -(confMan.params.hasVid?"":"")+""+""+""+"
";jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();} -jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});} +function genControls(jq,rowid){var x=parseInt(rowid);var kick_id="kick_"+x;var canvas_in_next_id="canvas_in_next_"+x;var canvas_in_prev_id="canvas_in_prev_"+x;var canvas_out_next_id="canvas_out_next_"+x;var canvas_out_prev_id="canvas_out_prev_"+x;var canvas_in_set_id="canvas_in_set_"+x;var canvas_out_set_id="canvas_out_set_"+x;var layer_set_id="layer_set_"+x;var layer_next_id="layer_next_"+x;var layer_prev_id="layer_prev_"+x;var tmute_id="tmute_"+x;var tvmute_id="tvmute_"+x;var vbanner_id="vbanner_"+x;var tvpresenter_id="tvpresenter_"+x;var tvfloor_id="tvfloor_"+x;var box_id="box_"+x;var volup_id="volume_in_up"+x;var voldn_id="volume_in_dn"+x;var transfer_id="transfer"+x;var html="
";html+="General Controls
";html+=""+""+""+""+"";if(confMan.params.hasVid){html+="

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

Canvas Controls
"+""+""+""+"
"+""+""+"";} +html+="
"+""+""+""+"
";} +jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();} +jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});} $("#"+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;if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=300;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready

");}else{$(confMan.params.mainModID).html("");} +var atitle="";var awidth=0;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"){var vlselect_id="#confman_vl_select_"+confMan.serno;var vlayout_id="#confman_vid_layout_"+confMan.serno;var x=0;var options;$(vlselect_id).selectmenu({});$(vlselect_id).selectmenu("enable");$(vlselect_id).empty();$(vlselect_id).append(new Option("Choose a Layout","none"));if(e.data.responseData){options=e.data.responseData.sort();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;} +if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;j
");if(confMan.lastTimeout){clearTimeout(confMan.lastTimeout);confMan.lastTimeout=0;} confMan.lastTimeout=setTimeout(function(){$(confMan.params.displayID).html(confMan.destroyed?"":"Moderator Controls Ready

");},4000);}}}});if(confMan.params.hasVid){confMan.modCommand("list-videoLayouts",null,null);}} var row_callback=null;if(confMan.params.laData.role==="moderator"){row_callback=function(nRow,aData,iDisplayIndex,iDisplayIndexFull){if(!aData[5]){var $row=$('td:eq(5)',nRow);genControls($row,aData);if(confMan.params.onLaRow){confMan.params.onLaRow(verto,confMan,$row,aData);}}};} -confMan.lt=new $.verto.liveTable(verto,confMan.params.laData.laChannel,confMan.params.laData.laName,$(confMan.params.tableID),{subParams:{callID:confMan.params.dialog?confMan.params.dialog.callID:null},"onChange":function(obj,args){$(confMan.params.statusID).text("Conference Members: "+" ("+obj.arrayLen()+" Total)");if(confMan.params.onLaChange){confMan.params.onLaChange(verto,confMan,$.verto.enum.confEvent.laChange,obj,args);}},"aaData":[],"aoColumns":[{"sTitle":"ID"},{"sTitle":"Number"},{"sTitle":"Name"},{"sTitle":"Codec"},{"sTitle":"Status","sWidth":confMan.params.hasVid?"200px":"150px"},{"sTitle":atitle,"sWidth":awidth,}],"bAutoWidth":true,"bDestroy":true,"bSort":false,"bInfo":false,"bFilter":false,"bLengthChange":false,"bPaginate":false,"iDisplayLength":1000,"oLanguage":{"sEmptyTable":"The Conference is Empty....."},"fnRowCallback":row_callback});};$.verto.confMan.prototype.modCommand=function(cmd,id,value){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.confMan.prototype.destroy=function(){var confMan=this;confMan.destroyed=true;if(confMan.lt){confMan.lt.destroy();} +confMan.lt=new $.verto.liveTable(verto,confMan.params.laData.laChannel,confMan.params.laData.laName,$(confMan.params.tableID),{subParams:{callID:confMan.params.dialog?confMan.params.dialog.callID:null},"onChange":function(obj,args){$(confMan.params.statusID).text("Conference Members: "+" ("+obj.arrayLen()+" Total)");if(confMan.params.onLaChange){confMan.params.onLaChange(verto,confMan,$.verto.enum.confEvent.laChange,obj,args);}},"aaData":[],"aoColumns":[{"sTitle":"ID","sWidth":"50"},{"sTitle":"Number","sWidth":"250"},{"sTitle":"Name","sWidth":"250"},{"sTitle":"Codec","sWidth":"100"},{"sTitle":"Status","sWidth":confMan.params.hasVid?"200px":"150px"},{"sTitle":atitle,"sWidth":awidth,}],"bAutoWidth":true,"bDestroy":true,"bSort":false,"bInfo":false,"bFilter":false,"bLengthChange":false,"bPaginate":false,"iDisplayLength":1400,"oLanguage":{"sEmptyTable":"The Conference is Empty....."},"fnRowCallback":row_callback});};$.verto.confMan.prototype.modCommand=function(cmd,id,value){var confMan=this;confMan.verto.rpcClient.call("verto.broadcast",{"eventChannel":confMan.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.confMan.prototype.destroy=function(){var confMan=this;confMan.destroyed=true;if(confMan.lt){confMan.lt.destroy();} if(confMan.params.laData.modChannel){confMan.verto.unsubscribe(confMan.params.laData.modChannel);} if(confMan.params.mainModID){$(confMan.params.mainModID).html("");}};$.verto.dialog=function(direction,verto,params){var dialog=this;dialog.params=$.extend({useVideo:verto.options.useVideo,useStereo:verto.options.useStereo,screenShare:false,useCamera:"any",useMic:"any",tag:verto.options.tag,localTag:verto.options.localTag,login:verto.options.login,videoParams:verto.options.videoParams},params);dialog.verto=verto;dialog.direction=direction;dialog.lastState=null;dialog.state=dialog.lastState=$.verto.enum.state.new;dialog.callbacks=verto.callbacks;dialog.answered=false;dialog.attach=params.attach||false;dialog.screenShare=params.screenShare||false;dialog.useCamera=params.useCamera;dialog.useMic=params.useMic;if(dialog.params.callID){dialog.callID=dialog.params.callID;}else{dialog.callID=dialog.params.callID=generateGUID();} if(dialog.params.tag){dialog.audioStream=document.getElementById(dialog.params.tag);if(dialog.params.useVideo){dialog.videoStream=dialog.audioStream;}} @@ -237,12 +237,14 @@ if(!msg.body){console.error("Missing Body");err++;} if(err){return false;} dialog.sendMethod("verto.info",{msg:msg});return true;};$.verto.dialog.prototype.answer=function(params){var dialog=this;if(!dialog.answered){if(!params){params={};} params.sdp=dialog.params.sdp;if(params){if(params.useVideo){dialog.useVideo(true);} -dialog.params.callee_id_name=params.callee_id_name;dialog.params.callee_id_number=params.callee_id_number;} +dialog.params.callee_id_name=params.callee_id_name;dialog.params.callee_id_number=params.callee_id_number;dialog.useCamera=params.useCamera;dialog.useMic=params.useMic;} dialog.rtc.createAnswer(params);dialog.answered=true;}};$.verto.dialog.prototype.handleAnswer=function(params){var dialog=this;dialog.gotAnswer=true;if(dialog.state.val>=$.verto.enum.state.active.val){return;} if(dialog.state.val>=$.verto.enum.state.early.val){dialog.setState($.verto.enum.state.active);}else{if(dialog.gotEarly){console.log("Dialog "+dialog.callID+" Got answer while still establishing early media, delaying...");}else{console.log("Dialog "+dialog.callID+" Answering Channel");dialog.rtc.answer(params.sdp,function(){dialog.setState($.verto.enum.state.active);},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"ANSWER SDP",params.sdp);}}};$.verto.dialog.prototype.cidString=function(enc){var dialog=this;var party=dialog.params.remote_caller_id_name+(enc?" <":" <")+dialog.params.remote_caller_id_number+(enc?">":">");return party;};$.verto.dialog.prototype.sendMessage=function(msg,params){var dialog=this;if(dialog.callbacks.onMessage){dialog.callbacks.onMessage(dialog.verto,dialog,msg,params);}};$.verto.dialog.prototype.handleInfo=function(params){var dialog=this;dialog.sendMessage($.verto.enum.message.info,params.msg);};$.verto.dialog.prototype.handleDisplay=function(params){var dialog=this;if(params.display_name){dialog.params.remote_caller_id_name=params.display_name;} if(params.display_number){dialog.params.remote_caller_id_number=params.display_number;} dialog.sendMessage($.verto.enum.message.display,{});};$.verto.dialog.prototype.handleMedia=function(params){var dialog=this;if(dialog.state.val>=$.verto.enum.state.early.val){return;} -dialog.gotEarly=true;dialog.rtc.answer(params.sdp,function(){console.log("Dialog "+dialog.callID+"Establishing early media");dialog.setState($.verto.enum.state.early);if(dialog.gotAnswer){console.log("Dialog "+dialog.callID+"Answering Channel");dialog.setState($.verto.enum.state.active);}},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"EARLY SDP",params.sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,recovering:1,ringing:1,destroy:1,answering:1,hangup:1},requesting:{trying:1,hangup:1},recovering:{answering:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{answering:1,requesting:1,hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$(window).bind('beforeunload',function(){for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.purge();verto.logout();}} +dialog.gotEarly=true;dialog.rtc.answer(params.sdp,function(){console.log("Dialog "+dialog.callID+"Establishing early media");dialog.setState($.verto.enum.state.early);if(dialog.gotAnswer){console.log("Dialog "+dialog.callID+"Answering Channel");dialog.setState($.verto.enum.state.active);}},function(e){console.error(e);dialog.hangup();});console.log("Dialog "+dialog.callID+"EARLY SDP",params.sdp);};$.verto.ENUM=function(s){var i=0,o={};s.split(" ").map(function(x){o[x]={name:x,val:i++};});return Object.freeze(o);};$.verto.enum={};$.verto.enum.states=Object.freeze({new:{requesting:1,recovering:1,ringing:1,destroy:1,answering:1,hangup:1},requesting:{trying:1,hangup:1},recovering:{answering:1,hangup:1},trying:{active:1,early:1,hangup:1},ringing:{answering:1,hangup:1},answering:{active:1,hangup:1},active:{answering:1,requesting:1,hangup:1,held:1},held:{hangup:1,active:1},early:{hangup:1,active:1},hangup:{destroy:1},destroy:{},purge:{destroy:1}});$.verto.enum.state=$.verto.ENUM("new requesting trying recovering ringing answering early active held hangup destroy purge");$.verto.enum.direction=$.verto.ENUM("inbound outbound");$.verto.enum.message=$.verto.ENUM("display info pvtEvent");$.verto.enum=Object.freeze($.verto.enum);$.verto.saved=[];$.verto.unloadJobs=[];$(window).bind('beforeunload',function(){for(var f in $.verto.unloadJobs){$.verto.unloadJobs[f]();} +for(var i in $.verto.saved){var verto=$.verto.saved[i];if(verto){verto.purge();verto.logout();}} return $.verto.warnOnUnload;});$.verto.videoDevices=[];$.verto.audioDevices=[];var checkDevices=function(runtime){console.info("enumerating devices");var aud=[],vid=[];if(MediaStreamTrack.getSources){MediaStreamTrack.getSources(function(media_sources){for(var i=0;i $(window).width()) { + if ($("#" + video_screen).width() > $(window).width()) { //resize(false); - $("#webcam").width("100%"); - $("#webcam").height("100%"); + $("#" + video_screen).width("100%"); + $("#" + video_screen).height("100%"); } }); function resize(up) { - var width = $("#webcam").width(); - var height = $("#webcam").height(); + var width = $("#" + video_screen).width(); + var height = $("#" + video_screen).height(); if (up) { - $("#webcam").width(width * 1.20); - $("#webcam").height(height * 1.20); + $("#" + video_screen).width(width * 1.20); + $("#" + video_screen).height(height * 1.20); } else { - $("#webcam").width(width * .80); - $("#webcam").height(height * .80); + $("#" + video_screen).width(width * .80); + $("#" + video_screen).height(height * .80); } - console.log("video size changed to " + $("#webcam").width() + "x" + $("#webcam").height()); + console.log("video size changed to " + $("#" + video_screen).width() + "x" + $("#" + video_screen).height()); } function real_size() { - $("#webcam").width(""); - $("#webcam").height(""); + $("#" + video_screen).width(""); + $("#" + video_screen).height(""); console.log("video size changed to natural default"); @@ -253,24 +261,88 @@ var callbacks = { case "conference-liveArray-part": clearConfMan(); + if (data.pvtData.secondScreen) { + $("#mainButtons").show(); + $("#canvasButtons").hide(); + $("#keypad").show(); + } break; case "conference-liveArray-join": clearConfMan(); - confMan = new $.verto.confMan(verto, { - tableID: "#conf_list", - statusID: "#conf_count", - mainModID: "#conf_mod", - displayID: "#conf_display", - dialog: dialog, - hasVid: check_vid(), - laData: data.pvtData - }); - $("#conf").show(); - $("#chatwin").html(""); - $("#message").show(); + if (data.pvtData.secondScreen) { + $("#mainButtons").hide(); + $("#canvasButtons").show(); + $("#keypad").hide(); + } else { + confMan = new $.verto.confMan(verto, { + tableID: "#conf_list", + statusID: "#conf_count", + mainModID: "#conf_mod", + displayID: "#conf_display", + dialog: dialog, + hasVid: check_vid(), + laData: data.pvtData + }); - chatting_with = data.pvtData.chatID; + if (!data.pvtData.canvasCount) { + data.pvtData.canvasCount = 1; + } + + var canvasCount = data.pvtData.canvasCount + 0; + + if (canvasCount <= 1) { + $("#canvasui").hide(); + } if (canvasCount > 1) { + $("#canvasui").show(); + $("#canvasid").selectmenu({}); + $("#canvasid").selectmenu("enable"); + $("#canvasid").empty(); + + var x; + + for (x = 1; x < canvasCount; x++) { + $("#canvasid").append(new Option("Canvas " + (x + 1), (x + 1))); + } + + $("#canvasid").append(new Option("Super Canvas", x + 1)); + + $("#canvasid").selectmenu('refresh', true); + + $("#canvasbut").click(function() { + var canvas_id = $("#canvasid").find(":selected").val(); + var s = window.location.href; + s = s.replace(/\#.*/,''); + s += "#sessid=random&master=" + cur_call.callID + + "&secondScreen=true&canvas_id=" + canvas_id + "&autocall=" + $("#ext").val() + "-canvas-" + canvas_id; + console.log("opening new window to " + s); + window.open(s, "canvas_window_" + canvas_id, "toolbar=0,location=0,menubar=0,directories=0,width=" + ($("#" + video_screen).width() + 50) + ",height=" + ($("#" + video_screen).height() + 400)); + }); + } + + $("#conf").show(); + $("#chatwin").html(""); + + if (data.pvtData.hipchatURL) { + var namex = $("#cidname").val(); + + if (!namex.indexOf(" ") > 0) { + namex += " " + $("#cid").val(); + } + + var name = namex.replace(/ /i, '%20'); + + $('#hcmessage').hipChatPanel({ + url: data.pvtData.hipchatURL + "?name=" + name, + timezone: "CST" + }); + $("#hctop").show().find('.show-hipchat').click(); + } else { + $("#message").show(); + } + + chatting_with = data.pvtData.chatID; + } break; } @@ -402,17 +474,38 @@ var callbacks = { break; case $.verto.enum.state.early: case $.verto.enum.state.active: - display("Talking to: " + d.cidString()); + if (sessid) { + cur_call.setMute("on"); + display("Viewing Canvas: " + canvas_id); + + verto.subscribe("presence", { + handler: function(v, e) { + if (e.data.channelUUID === master && e.data.channelCallState === "HANGUP") { + cur_call.hangup(); + } + } + }); + + } else { + display("Talking to: " + d.cidString()); + } goto_page("incall"); break; case $.verto.enum.state.hangup: $("#main_info").html("Call ended with cause: " + d.cause); goto_page("main"); + exit_full_screen(); case $.verto.enum.state.destroy: $("#hangup_cause").html(""); clearConfMan(); real_size(); cur_call = null; + if (sessid) { + setTimeout(function() { + delete $.verto.warnOnUnload; + window.close(); + }, 500); + } break; case $.verto.enum.state.held: break; @@ -458,6 +551,10 @@ var callbacks = { var today = new Date(); $("#errordisplay").html("Connection Error.
Last Attempt: " + today); goto_page("main"); + + if (sessid) { + window.close(); + } }, onEvent: function(v, e) { @@ -511,6 +608,12 @@ $("#hupbtn").click(function() { cur_call = null; }); +$("#hupbtn2").click(function() { + delete $.verto.warnOnUnload; + verto.hangup(); + cur_call = null; +}); + $("#mutebtn").click(function() { cur_call.dtmf("0"); }); @@ -542,19 +645,23 @@ function on_full(which) clearTimeout(rs); $("#usr2").hide(); rs = setTimeout(function() { - $("#webcam").width($(window).width()); - $("#webcam").height($(window).height()); + $("#" + video_screen).width($(window).width()); + $("#" + video_screen).height($(window).height()); }, 1500); $("#rows").css("position", "absolute").css("z-index", "2"); $("#fullbtn").text("Exit Full Screen"); + $("#fullbtn2").text("Exit Full Screen"); + $("#usrctl").show(); } else { + $("#usrctl").hide(); $("#rows").css("position", "static").css("z-index", "2"); $("#fullbtn").text("Enter Full Screen"); + $("#fullbtn2").text("Enter Full Screen"); clearTimeout(usrto); clearTimeout(rs); rs = setTimeout(function() { - $("#webcam").width("100%"); - $("#webcam").height("100%"); + $("#" + video_screen).width("100%"); + $("#" + video_screen).height("100%"); }, 1500); } @@ -587,10 +694,15 @@ $("#fullbtn").click(function() { } else { exit_full_screen(); } +}); +$("#fullbtn2").click(function() { -// $("#mod1").css("position", "absolute").css("z-index", "2"); - + if (!is_full) { + full_screen("fs"); + } else { + exit_full_screen(); + } }); $("#biggerbtn").click(function() { @@ -601,7 +713,7 @@ $("#smallerbtn").click(function() { resize(false); }); -$("#webcam").click(function() { +$("#" + video_screen).click(function() { check_vid(); }); @@ -624,10 +736,14 @@ function docall() { incomingBandwidth: incomingBandwidth, useVideo: check_vid(), useStereo: $("#use_stereo").is(':checked'), - useCamera: $("#usecamera").find(":selected").val(), + useCamera: sessid ? "none" : $("#usecamera").find(":selected").val(), useMic: $("#usemic").find(":selected").val(), dedEnc: $("#use_dedenc").is(':checked'), - mirrorInput: $("#mirror_input").is(':checked') + mirrorInput: $("#mirror_input").is(':checked'), + userVariables: { + avatar: $("#avatar").val(), + email: $("#email").val(), + }, }); } @@ -727,13 +843,29 @@ function pop(id, cname, dft) { $.cookie(cname, tmp, { expires: 365 }); + $(id).val(tmp).change(function() { + if (!save_settings) return; + $.cookie(cname, $(id).val(), { expires: 365 }); }); } +function pop_select(id, cname, dft) { + var tmp = $.cookie(cname) || dft; + $.cookie(cname, tmp, { + expires: 365 + }); + // $("#usecamera").find(":selected").val() + $(id).change(function() { + tmp = $(id).find(":selected").val(); + $.cookie(cname, tmp, { + expires: 365 + }); + }); +} function refresh_devices() @@ -756,6 +888,7 @@ function refresh_devices() var x = 0; $("#usecamera").append(new Option("No Camera", "none")); + $("#usemic").append(new Option("Do Not Specify", "any")); for (var i in $.verto.videoDevices) { var source = $.verto.videoDevices[i]; var o = new Option(source.label, source.id); @@ -772,7 +905,7 @@ function refresh_devices() $("#useshare").append(oo); } - x = 0; + x = 1; for (var i in $.verto.audioDevices) { var source = $.verto.audioDevices[i]; @@ -799,10 +932,24 @@ function refresh_devices() $("input[type='checkbox']").checkboxradio("refresh"); //console.error($("#usecamera").find(":selected").val()); + + var tmp; + tmp = $.cookie("verto_demo_camera_selected") || "false"; + if (tmp) { + $('#usecamera option[value=' + tmp + ']').prop('selected', 'selected').change(); + pop_select("#usecamera","verto_demo_camera_selected", tmp); + } + + tmp = $.cookie("verto_demo_mic_selected") || "false"; + if (tmp) { + $('#usemic option[value=' + tmp + ']').prop('selected', 'selected').change(); + pop_select("#usemic","verto_demo_mic_selected", tmp); + } } function init() { cur_call = null; + goto_page("main"); $("#usecamera").selectmenu({}); $("#usemic").selectmenu({}); @@ -812,8 +959,10 @@ function init() { pop("#ext", "verto_demo_ext", "3500"); } + pop("#avatar", "verto_demo_avatar", ""); pop("#cidname", "verto_demo_name", "FreeSWITCH User"); pop("#cid", "verto_demo_cid", "1008"); + pop("#email", "verto_demo_email", ""); pop("#textto", "verto_demo_textto", "1000"); pop("#login", "verto_demo_login", "1008"); @@ -1146,9 +1295,6 @@ function init() { $.cookie("verto_demo_local_video_checked", tmp ? "true" : "false", { expires: 365 }); - if (verto) { - verto.iceServers(tmp); - } }); check_vid_res(); @@ -1157,10 +1303,11 @@ function init() { login: $("#login").val() + "@" + $("#hostName").val(), passwd: $("#passwd").val(), socketUrl: $("#wsURL").val(), - tag: "webcam", + tag: video_screen, //localTag: $("#local_video").is(':checked') ? "local_webcam" : null, ringFile: "sounds/bell_ring2.wav", - loginParams: {foo: true, bar: "yes"}, + sessid: sessid, + //loginParams: {second_screen: second_screen}, videoParams: { "minWidth": vid_width, "minHeight": vid_height, @@ -1171,6 +1318,11 @@ function init() { //chromeMediaSource: 'screen', //mediaSource: 'screen' }, + + deviceParams: { + useCamera: $("#usecamera").find(":selected").val(), useMic: $("#usemic").find(":selected").val() + }, + // audioParams: { // googAutoGainControl: false, // googNoiseSuppression: false, @@ -1181,6 +1333,55 @@ function init() { },callbacks); + function handleEmailResponse(resp) { + for (var i=0; i < resp.emails.length; i++) { + if (resp.emails[i].type === 'account' && resp.emails[i].value) { + $("#email").val(resp.emails[i].value); + $("#email").change(); + } + } + + if (resp.displayName) { + $("#cidname").val(resp.displayName); + $("#cidname").trigger("change"); + } + + $("#avatar").val(resp.image.url + "0"); + $("#avatar").trigger("change"); + + gapi.auth.signOut(); + } + + $("#signinButton").click(function() { + gapi.auth.signIn({callback: function(authResult) { + console.log('Sign-in state: ' + authResult['error']); + if (authResult['status']['signed_in']) { + // Update the app to reflect a signed in user + // Hide the sign-in button now that the user is authorized, for example: + //document.getElementById('signinButton').setAttribute('style', 'display: none'); + gapi.client.load('plus','v1', function(){ + var request = gapi.client.plus.people.get({userId: 'me'}).execute(handleEmailResponse); + }); + } else { + // Update the app to reflect a signed out user + // Possible error values: + // "user_signed_out" - User is signed-out + // "access_denied" - User denied access to your app + // "immediate_failed" - Could not automatically log in the user + console.log('Sign-in state: ' + authResult['error']); + } + + }}); + }); + + $("#email").change(function(e) { + $("#avatar").val("http://gravatar.com/avatar/" + md5($("#emailaddr").val()) + ".png?s=600"); + $.cookie("verto_demo_email", e.currentTarget.value, { + expires: 365 + }); + + }); + $("#login").change(function(e) { $("#cid").val(e.currentTarget.value); $.cookie("verto_demo_cid", e.currentTarget.value, { @@ -1199,6 +1400,7 @@ function init() { $("#logoutbtn").click(function() { verto.logout(); online(false); + $("#errordisplay").html(""); }); $("#loginbtn").click(function() { @@ -1212,7 +1414,7 @@ function init() { }); $("#xferdiv").hide(); -// $("#webcam").hide(); +// $("#" + video_screen).hide(); online(false); @@ -1245,18 +1447,48 @@ function init() { $(window).load(function() { var hash = window.location.hash.substring(1); var a = []; + var vars = []; if (hash && hash.indexOf("page-") == -1) { window.location.hash = ""; - $("#ext").val(hash); - autocall = true; + + if (vars = hash.split("&")) { + for (var i in vars) { + var v = vars[i]; + if (a = v.split("=")) { + var v_name = a[0]; + var v_val = a[1]; + + if (v_name === "sessid") { + sessid = v_val; + if (sessid === "random") { + sessid = $.verto.genUUID(); + } + save_settings = false; + $.verto.warnOnUnload = "WARNING: DO NOT RELOAD THIS PAGE! Please Close it Instead\n"; + $.verto.unloadJobs.push(function() { + exit_full_screen(); + verto.hangup(); + cur_call = null; + }); + } else if (v_name === "master") { + master = v_val; + } else if (v_name === "canvas_id") { + canvas_id = v_val; + } else if (v_name === "autocall") { + $("#ext").val(v_val); + autocall = true; + } + } + } + } } - if (hash && (a = hash.split("&"))) { - window.location.hash = a[0]; - } + //if (hash && (a = hash.split("&"))) { + // window.location.hash = a[0]; + // } - $("#webcam").hide(); + $("#" + video_screen).hide(); $("#camdiv").hide(); $('#demos').hide(); $('#devices').hide(); @@ -1283,8 +1515,11 @@ $(window).load(function() { } }); - - $.verto.init({}, init); + $("#search").show(); + goto_page("enum"); + setTimeout(function() { + $.verto.init({}, init); + }, 500); }); diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 598c8efe5e..5900c8deea 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -119,9 +119,11 @@ static int EC = 0; #define VIDEO_LAYOUT_SCALE 360.0f #define CONFERENCE_MUX_DEFAULT_LAYOUT "group:grid" +#define CONFERENCE_MUX_DEFAULT_SUPER_LAYOUT "grid" #define CONFERENCE_CANVAS_DEFAULT_WIDTH 1280 #define CONFERENCE_CANVAS_DEFAULT_HIGHT 720 - +#define MAX_CANVASES 20 +#define SUPER_CANVAS_ID MAX_CANVASES #define test_eflag(conference, flag) ((conference)->eflags & flag) typedef enum { @@ -148,13 +150,100 @@ static struct { struct conference_member; typedef struct conference_member conference_member_t; +struct caller_control_actions; + +typedef struct caller_control_actions { + char *binded_dtmf; + char *data; + char *expanded_data; +} caller_control_action_t; + +typedef struct caller_control_menu_info { + switch_ivr_menu_t *stack; + char *name; +} caller_control_menu_info_t; + +typedef enum { + MFLAG_RUNNING, + MFLAG_CAN_SPEAK, + MFLAG_CAN_HEAR, + MFLAG_KICKED, + MFLAG_ITHREAD, + MFLAG_NOCHANNEL, + MFLAG_INTREE, + MFLAG_NO_MINIMIZE_ENCODING, + MFLAG_FLUSH_BUFFER, + MFLAG_ENDCONF, + MFLAG_HAS_AUDIO, + MFLAG_TALKING, + MFLAG_RESTART, + MFLAG_MINTWO, + MFLAG_MUTE_DETECT, + MFLAG_DIST_DTMF, + MFLAG_MOD, + MFLAG_INDICATE_MUTE, + MFLAG_INDICATE_UNMUTE, + MFLAG_NOMOH, + MFLAG_VIDEO_BRIDGE, + MFLAG_INDICATE_MUTE_DETECT, + MFLAG_PAUSE_RECORDING, + MFLAG_ACK_VIDEO, + MFLAG_GHOST, + MFLAG_JOIN_ONLY, + MFLAG_POSITIONAL, + MFLAG_NO_POSITIONAL, + MFLAG_JOIN_VID_FLOOR, + MFLAG_RECEIVING_VIDEO, + MFLAG_CAN_BE_SEEN, + MFLAG_SECOND_SCREEN, + MFLAG_SILENT, + /////////////////////////// + MFLAG_MAX +} member_flag_t; + +typedef enum { + CFLAG_RUNNING, + CFLAG_DYNAMIC, + CFLAG_ENFORCE_MIN, + CFLAG_DESTRUCT, + CFLAG_LOCKED, + CFLAG_ANSWERED, + CFLAG_BRIDGE_TO, + CFLAG_WAIT_MOD, + CFLAG_VID_FLOOR, + CFLAG_WASTE_FLAG, + CFLAG_OUTCALL, + CFLAG_INHASH, + CFLAG_EXIT_SOUND, + CFLAG_ENTER_SOUND, + CFLAG_USE_ME, + CFLAG_AUDIO_ALWAYS, + CFLAG_ENDCONF_FORCED, + CFLAG_RFC4579, + CFLAG_FLOOR_CHANGE, + CFLAG_VID_FLOOR_LOCK, + CFLAG_JSON_EVENTS, + CFLAG_LIVEARRAY_SYNC, + CFLAG_CONF_RESTART_AUTO_RECORD, + CFLAG_POSITIONAL, + CFLAG_TRANSCODE_VIDEO, + CFLAG_VIDEO_MUXING, + CFLAG_MINIMIZE_VIDEO_ENCODING, + CFLAG_MANAGE_INBOUND_VIDEO_BITRATE, + CFLAG_JSON_STATUS, + CFLAG_VIDEO_BRIDGE_FIRST_TWO, + CFLAG_VIDEO_REQUIRED_FOR_CANVAS, + CFLAG_PERSONAL_CANVAS, + ///////////////////////////////// + CFLAG_MAX +} conference_flag_t; typedef struct conference_cdr_node_s { switch_caller_profile_t *cp; char *record_path; switch_time_t join_time; switch_time_t leave_time; - uint32_t flags; + member_flag_t mflags[MFLAG_MAX]; uint32_t id; conference_member_t *member; switch_event_t *var_event; @@ -188,84 +277,7 @@ struct call_list { }; typedef struct call_list call_list_t; -struct caller_control_actions; -typedef struct caller_control_actions { - char *binded_dtmf; - char *data; - char *expanded_data; -} caller_control_action_t; - -typedef struct caller_control_menu_info { - switch_ivr_menu_t *stack; - char *name; -} caller_control_menu_info_t; - -typedef enum { - MFLAG_RUNNING = (1 << 0), - MFLAG_CAN_SPEAK = (1 << 1), - MFLAG_CAN_HEAR = (1 << 2), - MFLAG_KICKED = (1 << 3), - MFLAG_ITHREAD = (1 << 4), - MFLAG_NOCHANNEL = (1 << 5), - MFLAG_INTREE = (1 << 6), - MFLAG_NO_MINIMIZE_ENCODING = (1 << 7), - MFLAG_FLUSH_BUFFER = (1 << 8), - MFLAG_ENDCONF = (1 << 9), - MFLAG_HAS_AUDIO = (1 << 10), - MFLAG_TALKING = (1 << 11), - MFLAG_RESTART = (1 << 12), - MFLAG_MINTWO = (1 << 13), - MFLAG_MUTE_DETECT = (1 << 14), - MFLAG_DIST_DTMF = (1 << 15), - MFLAG_MOD = (1 << 16), - MFLAG_INDICATE_MUTE = (1 << 17), - MFLAG_INDICATE_UNMUTE = (1 << 18), - MFLAG_NOMOH = (1 << 19), - MFLAG_VIDEO_BRIDGE = (1 << 20), - MFLAG_INDICATE_MUTE_DETECT = (1 << 21), - MFLAG_PAUSE_RECORDING = (1 << 22), - MFLAG_ACK_VIDEO = (1 << 23), - MFLAG_GHOST = (1 << 24), - MFLAG_JOIN_ONLY = (1 << 25), - MFLAG_POSITIONAL = (1 << 26), - MFLAG_NO_POSITIONAL = (1 << 27), - MFLAG_JOIN_VID_FLOOR = (1 << 28), - MFLAG_RECEIVING_VIDEO = (1 << 29), - MFLAG_CAN_BE_SEEN = (1 << 30) -} member_flag_t; - -typedef enum { - CFLAG_RUNNING = (1 << 0), - CFLAG_DYNAMIC = (1 << 1), - CFLAG_ENFORCE_MIN = (1 << 2), - CFLAG_DESTRUCT = (1 << 3), - CFLAG_LOCKED = (1 << 4), - CFLAG_ANSWERED = (1 << 5), - CFLAG_BRIDGE_TO = (1 << 6), - CFLAG_WAIT_MOD = (1 << 7), - CFLAG_VID_FLOOR = (1 << 8), - CFLAG_WASTE_FLAG = (1 << 9), - CFLAG_OUTCALL = (1 << 10), - CFLAG_INHASH = (1 << 11), - CFLAG_EXIT_SOUND = (1 << 12), - CFLAG_ENTER_SOUND = (1 << 13), - CFLAG_USE_ME = (1 << 14), - CFLAG_AUDIO_ALWAYS = (1 << 15), - CFLAG_ENDCONF_FORCED = (1 << 16), - CFLAG_RFC4579 = (1 << 17), - CFLAG_FLOOR_CHANGE = (1 << 18), - CFLAG_VID_FLOOR_LOCK = (1 << 19), - CFLAG_JSON_EVENTS = (1 << 20), - CFLAG_LIVEARRAY_SYNC = (1 << 21), - CFLAG_CONF_RESTART_AUTO_RECORD = (1 << 22), - CFLAG_POSITIONAL = (1 << 23), - CFLAG_TRANSCODE_VIDEO = (1 << 24), - CFLAG_VIDEO_MUXING = (1 << 25), - CFLAG_MINIMIZE_VIDEO_ENCODING = (1 << 26), - CFLAG_MANAGE_INBOUND_VIDEO_BITRATE = (1 << 27), - CFLAG_JSON_STATUS = (1 << 28) -} conf_flag_t; typedef enum { RFLAG_CAN_SPEAK = (1 << 0), @@ -335,6 +347,7 @@ typedef struct al_handle_s { switch_mutex_t *mutex; } al_handle_t; #endif +struct conference_obj; typedef struct conference_file_node { switch_file_handle_t fh; @@ -351,6 +364,8 @@ typedef struct conference_file_node { uint32_t member_id; al_handle_t *al; int layer_id; + int canvas_id; + struct conference_obj *conference; } conference_file_node_t; typedef enum { @@ -389,6 +404,8 @@ typedef struct mcu_layer_def_s { mcu_layer_geometry_t layers[MCU_MAX_LAYERS]; } mcu_layer_def_t; +struct mcu_canvas_s; + typedef struct mcu_layer_s { mcu_layer_geometry_t geometry; int member_id; @@ -401,6 +418,7 @@ typedef struct mcu_layer_s { int y_pos; int banner_patched; int mute_patched; + int avatar_patched; int refresh; int is_avatar; switch_img_position_t logo_pos; @@ -412,6 +430,7 @@ typedef struct mcu_layer_s { switch_image_t *mute_img; switch_img_txt_handle_t *txthandle; conference_file_node_t *fnode; + struct mcu_canvas_s *canvas; } mcu_layer_t; typedef struct video_layout_s { @@ -448,10 +467,14 @@ typedef struct mcu_canvas_s { switch_memory_pool_t *pool; video_layout_t *vlayout; video_layout_t *new_vlayout; + int canvas_id; + struct conference_obj *conference; + switch_thread_t *video_muxing_thread; + int video_timer_reset; + switch_queue_t *video_queue; + int32_t video_write_bandwidth; } mcu_canvas_t; -struct conference_obj; - /* Record Node */ typedef struct conference_record { struct conference_obj *conference; @@ -501,12 +524,12 @@ typedef struct conference_obj { char *video_layout_name; char *video_layout_group; char *video_canvas_bgcolor; + char *video_super_canvas_bgcolor; char *video_letterbox_bgcolor; char *no_video_avatar; conf_video_mode_t conf_video_mode; int members_with_video; - int video_timer_reset; - int32_t video_write_bandwidth; + int members_with_avatar; switch_codec_settings_t video_codec_settings; uint32_t canvas_width; uint32_t canvas_height; @@ -525,8 +548,8 @@ typedef struct conference_obj { char *caller_controls; char *moderator_controls; switch_live_array_t *la; - uint32_t flags; - member_flag_t mflags; + conference_flag_t flags[CFLAG_MAX]; + member_flag_t mflags[MFLAG_MAX]; switch_call_cause_t bridge_hangup_cause; switch_mutex_t *flag_mutex; uint32_t rate; @@ -588,8 +611,13 @@ typedef struct conference_obj { struct vid_helper mh; conference_record_t *rec_node_head; int last_speech_channels; - switch_thread_t *video_muxing_thread; mcu_canvas_t *canvas; + mcu_canvas_t *canvases[MAX_CANVASES+1]; + int canvas_count; + int super_canvas_label_layers; + int super_canvas_show_all_layers; + int canvas_running_count; + switch_mutex_t *canvas_mutex; switch_hash_t *layout_hash; switch_hash_t *layout_group_hash; struct conf_fps video_fps; @@ -615,7 +643,7 @@ struct conference_member { switch_buffer_t *audio_buffer; switch_buffer_t *mux_buffer; switch_buffer_t *resample_buffer; - uint32_t flags; + member_flag_t flags[MFLAG_MAX]; uint32_t score; uint32_t last_score; uint32_t score_iir; @@ -674,6 +702,8 @@ struct conference_member { al_handle_t *al; int last_speech_channels; int video_layer_id; + int canvas_id; + int watching_canvas_id; int video_codec_index; int video_codec_id; char *video_banner_text; @@ -691,6 +721,8 @@ struct conference_member { int good_img; int auto_avatar; int avatar_patched; + mcu_canvas_t *canvas; + switch_image_t *pcanvas_img; }; typedef enum { @@ -722,6 +754,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe static switch_status_t conference_del_member(conference_obj_t *conference, conference_member_t *member); static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *obj); static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj); +static void *SWITCH_THREAD_FUNC conference_super_video_muxing_thread_run(switch_thread_t *thread, void *obj); static void conference_loop_output(conference_member_t *member); static uint32_t conference_stop_file(conference_obj_t *conference, file_stop_t stop); static switch_status_t conference_play_file(conference_obj_t *conference, char *file, uint32_t leadin, switch_channel_t *channel, uint8_t async); @@ -733,19 +766,96 @@ static void member_bind_controls(conference_member_t *member, const char *contro static void conference_send_presence(conference_obj_t *conference); static void conference_set_video_floor_holder(conference_obj_t *conference, conference_member_t *member, switch_bool_t force); static void canvas_del_fnode_layer(conference_obj_t *conference, conference_file_node_t *fnode); -static void canvas_set_fnode_layer(conference_obj_t *conference, conference_file_node_t *fnode, int idx); +static void canvas_set_fnode_layer(mcu_canvas_t *canvas, conference_file_node_t *fnode, int idx); + + +static inline void conference_set_flag(conference_obj_t *conference, conference_flag_t flag) +{ + conference->flags[flag] = 1; +} +static inline void conference_set_flag_locked(conference_obj_t *conference, conference_flag_t flag) +{ + switch_mutex_lock(conference->flag_mutex); + conference->flags[flag] = 1; + switch_mutex_unlock(conference->flag_mutex); +} +static inline void conference_clear_flag(conference_obj_t *conference, conference_flag_t flag) +{ + conference->flags[flag] = 0; +} +static inline void conference_clear_flag_locked(conference_obj_t *conference, conference_flag_t flag) +{ + switch_mutex_lock(conference->flag_mutex); + conference->flags[flag] = 0; + switch_mutex_unlock(conference->flag_mutex); +} +static inline switch_bool_t conference_test_flag(conference_obj_t *conference, conference_flag_t flag) +{ + return !!conference->flags[flag]; +} +static inline void conference_set_mflag(conference_obj_t *conference, member_flag_t mflag) +{ + conference->mflags[mflag] = 1; +} +static inline void conference_clear_mflag(conference_obj_t *conference, member_flag_t mflag) +{ + conference->mflags[mflag] = 0; +} +static inline switch_bool_t conference_test_mflag(conference_obj_t *conference, member_flag_t mflag) +{ + return !!conference->mflags[mflag]; +} +static inline switch_bool_t cdr_test_mflag(conference_cdr_node_t *np, member_flag_t mflag) +{ + return !!np->mflags[mflag]; +} +static inline void member_set_flag(conference_member_t *member, member_flag_t flag) +{ + member->flags[flag] = 1; +} +static inline void member_set_flag_locked(conference_member_t *member, member_flag_t flag) +{ + switch_mutex_lock(member->flag_mutex); + member->flags[flag] = 1; + switch_mutex_unlock(member->flag_mutex); +} +static inline void member_clear_flag(conference_member_t *member, member_flag_t flag) +{ + member->flags[flag] = 0; +} +static inline void member_clear_flag_locked(conference_member_t *member, member_flag_t flag) +{ + switch_mutex_lock(member->flag_mutex); + member->flags[flag] = 0; + switch_mutex_unlock(member->flag_mutex); +} +static inline switch_bool_t member_test_flag(conference_member_t *member, member_flag_t flag) +{ + return !!member->flags[flag]; +} + + + + SWITCH_STANDARD_API(conf_api_main); static int conference_set_fps(conference_obj_t *conference, float fps) { - int i = 0; + int i = 0, j = 0; for (i = 0; FPS_VALS[i].ms; i++) { if (FPS_VALS[i].fps == fps) { + conference->video_fps = FPS_VALS[i]; - conference->video_timer_reset = 1; + + for (j = 0; j <= conference->canvas_count; j++) { + if (conference->canvases[j]) { + conference->canvases[j]->video_timer_reset = 1; + } + } + return 1; } } @@ -768,7 +878,7 @@ static switch_status_t conference_outcall_bg(conference_obj_t *conference, switch_core_session_t *session, char *bridgeto, uint32_t timeout, const char *flags, const char *cid_name, const char *cid_num, const char *call_uuid, const char *profile, switch_call_cause_t *cancel_cause, switch_event_t **var_event); SWITCH_STANDARD_APP(conference_function); -static void launch_conference_video_muxing_thread(conference_obj_t *conference); +static void launch_conference_video_muxing_thread(conference_obj_t *conference, mcu_canvas_t *canvas, int super); static void launch_conference_thread(conference_obj_t *conference); static void launch_conference_video_muxing_write_thread(conference_member_t *member); static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj); @@ -1022,14 +1132,14 @@ static void reset_image(switch_image_t *img, switch_rgb_color_t *color) /* clear layer and reset_layer called inside lock always */ -static void clear_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) +static void clear_layer(mcu_layer_t *layer) { - switch_img_fill(canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &canvas->bgcolor); + switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &layer->canvas->bgcolor); layer->banner_patched = 0; layer->refresh = 1; } -static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) +static void reset_layer(mcu_layer_t *layer) { layer->tagged = 0; @@ -1042,35 +1152,35 @@ static void reset_layer(mcu_canvas_t *canvas, mcu_layer_t *layer) layer->is_avatar = 0; if (layer->geometry.overlap) { - canvas->refresh = 1; + layer->canvas->refresh = 1; } switch_img_free(&layer->img); layer->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, layer->screen_w, layer->screen_h, 1); switch_assert(layer->img); - clear_layer(canvas, layer); + clear_layer(layer); switch_img_free(&layer->cur_img); } -static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze) +static void scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze) { switch_image_t *IMG, *img; - switch_mutex_lock(conference->canvas->mutex); + switch_mutex_lock(layer->canvas->mutex); - IMG = conference->canvas->img; + IMG = layer->canvas->img; img = ximg ? ximg : layer->cur_img; switch_assert(IMG); if (!img) { - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(layer->canvas->mutex); return; } if (layer->refresh) { - switch_img_fill(conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &conference->canvas->letterbox_bgcolor); + switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &layer->canvas->letterbox_bgcolor); layer->refresh = 0; } @@ -1101,7 +1211,7 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw if (layer->img && (layer->img->d_w != img_w || layer->img->d_h != img_h)) { switch_img_free(&layer->img); layer->banner_patched = 0; - clear_layer(conference->canvas, layer); + clear_layer(layer); } if (!layer->img) { @@ -1109,7 +1219,7 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw } if (layer->banner_img && !layer->banner_patched) { - switch_img_fill(conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &conference->canvas->letterbox_bgcolor); + switch_img_fill(layer->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &layer->canvas->letterbox_bgcolor); switch_img_patch(IMG, layer->banner_img, layer->x_pos, layer->y_pos + (layer->screen_h - layer->banner_img->d_h)); if (!freeze) { @@ -1124,13 +1234,14 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw if (switch_img_scale(img, &layer->img, img_w, img_h) == SWITCH_STATUS_SUCCESS) { if (layer->bugged && layer->member_id > -1) { conference_member_t *member; - if ((member = conference_member_get(conference, layer->member_id))) { + if ((member = conference_member_get(layer->canvas->conference, layer->member_id))) { switch_frame_t write_frame = { 0 }; write_frame.img = layer->img; switch_core_media_bug_patch_video(member->session, &write_frame); switch_thread_rwlock_unlock(member->rwlock); } } + switch_img_patch(IMG, layer->img, x_pos, y_pos); } @@ -1154,8 +1265,7 @@ static void scale_and_patch(conference_obj_t *conference, mcu_layer_t *layer, sw switch_img_patch(IMG, img, 0, 0); } - switch_mutex_unlock(conference->canvas->mutex); - + switch_mutex_unlock(layer->canvas->mutex); } static void set_canvas_bgcolor(mcu_canvas_t *canvas, char *color) @@ -1169,16 +1279,16 @@ static void set_canvas_letterbox_bgcolor(mcu_canvas_t *canvas, char *color) switch_color_set_rgb(&canvas->letterbox_bgcolor, color); } -static void check_used_layers(conference_obj_t *conference) +static void check_used_layers(mcu_canvas_t *canvas) { int i; - if (!conference->canvas) return; + if (!canvas) return; - conference->canvas->layers_used = 0; - for (i = 0; i < conference->canvas->total_layers; i++) { - if (conference->canvas->layers[i].member_id) { - conference->canvas->layers_used++; + canvas->layers_used = 0; + for (i = 0; i < canvas->total_layers; i++) { + if (canvas->layers[i].member_id) { + canvas->layers_used++; } } } @@ -1186,14 +1296,21 @@ static void check_used_layers(conference_obj_t *conference) static void detach_video_layer(conference_member_t *member) { mcu_layer_t *layer = NULL; + mcu_canvas_t *canvas = NULL; - if (!member->conference->canvas || member->video_layer_id < 0) { - return; + switch_mutex_lock(member->conference->canvas_mutex); + + if (member->canvas_id < 0) goto end; + + canvas = member->conference->canvases[member->canvas_id]; + + if (!canvas || member->video_layer_id < 0) { + goto end; } - switch_mutex_lock(member->conference->canvas->mutex); + switch_mutex_lock(canvas->mutex); - layer = &member->conference->canvas->layers[member->video_layer_id]; + layer = &canvas->layers[member->video_layer_id]; if (layer->geometry.audio_position) { conf_api_sub_position(member, NULL, "0:0:0"); @@ -1203,12 +1320,20 @@ static void detach_video_layer(conference_member_t *member) switch_img_txt_handle_destroy(&layer->txthandle); } - reset_layer(member->conference->canvas, layer); + reset_layer(layer); layer->member_id = 0; member->video_layer_id = -1; + //member->canvas_id = 0; + //member->watching_canvas_id = -1; member->avatar_patched = 0; - check_used_layers(member->conference); - switch_mutex_unlock(member->conference->canvas->mutex); + check_used_layers(canvas); + canvas->send_keyframe = 1; + switch_mutex_unlock(canvas->mutex); + + end: + + switch_mutex_unlock(member->conference->canvas_mutex); + } @@ -1221,7 +1346,7 @@ static void layer_set_logo(conference_member_t *member, mcu_layer_t *layer, cons char *tmp; switch_img_position_t pos = POS_LEFT_TOP; - switch_mutex_lock(member->conference->canvas->mutex); + switch_mutex_lock(layer->canvas->mutex); if (!path) { path = member->video_logo; @@ -1293,7 +1418,7 @@ static void layer_set_logo(conference_member_t *member, mcu_layer_t *layer, cons end: - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(layer->canvas->mutex); } @@ -1310,8 +1435,7 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co const char *var, *tmp = NULL; char *dup = NULL; - - switch_mutex_lock(member->conference->canvas->mutex); + switch_mutex_lock(layer->canvas->mutex); if (!text) { text = member->video_banner_text; @@ -1408,7 +1532,7 @@ static void layer_set_banner(conference_member_t *member, mcu_layer_t *layer, co switch_safe_free(dup); - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(layer->canvas->mutex); } static void reset_video_bitrate_counters(conference_member_t *member) @@ -1419,7 +1543,7 @@ static void reset_video_bitrate_counters(conference_member_t *member) member->blanks = 0; } -static switch_status_t attach_video_layer(conference_member_t *member, int idx) +static switch_status_t attach_video_layer(conference_member_t *member, mcu_canvas_t *canvas, int idx) { mcu_layer_t *layer = NULL; switch_channel_t *channel = NULL; @@ -1439,9 +1563,11 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx) return SWITCH_STATUS_FALSE; } - switch_mutex_lock(member->conference->canvas->mutex); + switch_mutex_lock(member->conference->canvas_mutex); - layer = &member->conference->canvas->layers[idx]; + switch_mutex_lock(canvas->mutex); + + layer = &canvas->layers[idx]; layer->tagged = 0; @@ -1474,7 +1600,7 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx) detach_video_layer(member); } - reset_layer(member->conference->canvas, layer); + reset_layer(layer); switch_img_free(&layer->mute_img); member->avatar_patched = 0; @@ -1495,48 +1621,51 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx) layer->member_id = member->id; member->video_layer_id = idx; - check_used_layers(member->conference); + member->canvas_id = canvas->canvas_id; + canvas->send_keyframe = 1; + + //member->watching_canvas_id = canvas->canvas_id; + check_used_layers(canvas); if (layer->geometry.audio_position) { conf_api_sub_position(member, NULL, layer->geometry.audio_position); } - - switch_img_fill(member->conference->canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, - &member->conference->canvas->letterbox_bgcolor); - + switch_img_fill(canvas->img, layer->x_pos, layer->y_pos, layer->screen_w, layer->screen_h, &canvas->letterbox_bgcolor); reset_video_bitrate_counters(member); end: - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); + + switch_mutex_unlock(member->conference->canvas_mutex); return status; } -static void init_canvas_layers(conference_obj_t *conference, video_layout_t *vlayout) +static void init_canvas_layers(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout) { int i = 0; - if (!conference->canvas) return; + if (!canvas) return; - switch_mutex_lock(conference->canvas->mutex); - conference->canvas->layout_floor_id = -1; + switch_mutex_lock(canvas->mutex); + canvas->layout_floor_id = -1; if (!vlayout) { - vlayout = conference->canvas->new_vlayout; - conference->canvas->new_vlayout = NULL; + vlayout = canvas->new_vlayout; + canvas->new_vlayout = NULL; } if (!vlayout) { + switch_mutex_unlock(canvas->mutex); return; } - conference->canvas->vlayout = vlayout; + canvas->vlayout = vlayout; for (i = 0; i < vlayout->layers; i++) { - mcu_layer_t *layer = &conference->canvas->layers[i]; - + mcu_layer_t *layer = &canvas->layers[i]; layer->geometry.x = vlayout->images[i].x; layer->geometry.y = vlayout->images[i].y; layer->geometry.scale = vlayout->images[i].scale; @@ -1545,18 +1674,18 @@ static void init_canvas_layers(conference_obj_t *conference, video_layout_t *vla layer->idx = i; layer->refresh = 1; - layer->screen_w = conference->canvas->img->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE; - layer->screen_h = conference->canvas->img->d_h * layer->geometry.scale / VIDEO_LAYOUT_SCALE; + layer->screen_w = canvas->img->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE; + layer->screen_h = canvas->img->d_h * layer->geometry.scale / VIDEO_LAYOUT_SCALE; // if (layer->screen_w % 2) layer->screen_w++; // round to even // if (layer->screen_h % 2) layer->screen_h++; // round to even - layer->x_pos = conference->canvas->img->d_w * layer->geometry.x / VIDEO_LAYOUT_SCALE; - layer->y_pos = conference->canvas->img->d_h * layer->geometry.y / VIDEO_LAYOUT_SCALE; + layer->x_pos = canvas->img->d_w * layer->geometry.x / VIDEO_LAYOUT_SCALE; + layer->y_pos = canvas->img->d_h * layer->geometry.y / VIDEO_LAYOUT_SCALE; if (layer->geometry.floor) { - conference->canvas->layout_floor_id = i; + canvas->layout_floor_id = i; } /* if we ever decided to reload layers config on demand the pointer assignment below will lead to segs but we @@ -1565,57 +1694,113 @@ static void init_canvas_layers(conference_obj_t *conference, video_layout_t *vla layer->geometry.audio_position = vlayout->images[i].audio_position; } - reset_image(conference->canvas->img, &conference->canvas->bgcolor); + reset_image(canvas->img, &canvas->bgcolor); for (i = 0; i < MCU_MAX_LAYERS; i++) { - mcu_layer_t *layer = &conference->canvas->layers[i]; + mcu_layer_t *layer = &canvas->layers[i]; layer->member_id = 0; layer->tagged = 0; layer->banner_patched = 0; layer->refresh = 1; - reset_layer(conference->canvas, layer); - + layer->canvas = canvas; + reset_layer(layer); } - conference->canvas->layers_used = 0; - conference->canvas->total_layers = vlayout->layers; - conference->canvas->send_keyframe = 1; + canvas->layers_used = 0; + canvas->total_layers = vlayout->layers; + canvas->send_keyframe = 1; - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id, vlayout->name); } -static void init_canvas(conference_obj_t *conference, video_layout_t *vlayout) +static switch_status_t attach_canvas(conference_obj_t *conference, mcu_canvas_t *canvas, int super) { - if (!conference->canvas) { - conference->canvas = switch_core_alloc(conference->pool, sizeof(*conference->canvas)); - conference->canvas->pool = conference->pool; - switch_mutex_init(&conference->canvas->mutex, SWITCH_MUTEX_NESTED, conference->pool); - conference->canvas->layout_floor_id = -1; + if (conference->canvas_count >= MAX_CANVASES + 1) { + return SWITCH_STATUS_FALSE; } - switch_img_free(&conference->canvas->img); + canvas->canvas_id = conference->canvas_count; - conference->canvas->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvas_width, conference->canvas_height, 0); + if (!super) { + conference->canvas_count++; + + if (!conference->canvas) { + conference->canvas = canvas; + } + } + + conference->canvases[canvas->canvas_id] = canvas; - switch_assert(conference->canvas->img); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas attached to position %d\n", canvas->canvas_id); - conference->canvas->width = conference->canvas_width; - conference->canvas->height = conference->canvas_height; - - switch_mutex_lock(conference->canvas->mutex); - set_canvas_bgcolor(conference->canvas, conference->video_canvas_bgcolor); - set_canvas_letterbox_bgcolor(conference->canvas, conference->video_letterbox_bgcolor); - init_canvas_layers(conference, vlayout); - switch_mutex_unlock(conference->canvas->mutex); + return SWITCH_STATUS_SUCCESS; } +static switch_status_t init_canvas(conference_obj_t *conference, video_layout_t *vlayout, mcu_canvas_t **canvasP) +{ + mcu_canvas_t *canvas; + + if (conference->canvas_count >= MAX_CANVASES) { + return SWITCH_STATUS_FALSE; + } + + canvas = switch_core_alloc(conference->pool, sizeof(*canvas)); + canvas->conference = conference; + canvas->pool = conference->pool; + switch_mutex_init(&canvas->mutex, SWITCH_MUTEX_NESTED, conference->pool); + canvas->layout_floor_id = -1; + + switch_img_free(&canvas->img); + + canvas->width = conference->canvas_width; + canvas->height = conference->canvas_height; + + canvas->img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, canvas->width, canvas->height, 0); + switch_queue_create(&canvas->video_queue, 200, canvas->pool); + + switch_assert(canvas->img); + + switch_mutex_lock(canvas->mutex); + set_canvas_bgcolor(canvas, conference->video_canvas_bgcolor); + set_canvas_letterbox_bgcolor(canvas, conference->video_letterbox_bgcolor); + init_canvas_layers(conference, canvas, vlayout); + switch_mutex_unlock(canvas->mutex); + + canvas->canvas_id = -1; + *canvasP = canvas; + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Layout set to %s\n", vlayout->name); + + return SWITCH_STATUS_SUCCESS; +} + +static int flush_video_queue(switch_queue_t *q) +{ + switch_image_t *img; + void *pop; + int r = 0; + + if (!q) return 0; + + while (switch_queue_size(q) > 1 && switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS && pop) { + img = (switch_image_t *)pop; + switch_img_free(&img); + r++; + } + + return r + switch_queue_size(q); +} + + static void destroy_canvas(mcu_canvas_t **canvasP) { int i; mcu_canvas_t *canvas = *canvasP; switch_img_free(&canvas->img); + flush_video_queue(canvas->video_queue); for (i = 0; i < MCU_MAX_LAYERS; i++) { switch_img_free(&canvas->layers[i].img); @@ -1630,7 +1815,7 @@ typedef struct codec_set_s { uint8_t *packet; } codec_set_t; -static void write_canvas_image_to_codec_group(conference_obj_t *conference, codec_set_t *codec_set, +static void write_canvas_image_to_codec_group(conference_obj_t *conference, mcu_canvas_t *canvas, codec_set_t *codec_set, int codec_index, uint32_t timestamp, switch_bool_t need_refresh, switch_bool_t need_keyframe, switch_bool_t need_reset) @@ -1684,10 +1869,14 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code for (imember = conference->members; imember; imember = imember->next) { switch_frame_t *dupframe; - if (switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + if (imember->watching_canvas_id != canvas->canvas_id) { continue; } + if (member_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + continue; + } + if (imember->video_codec_index != codec_index) { continue; } @@ -1703,7 +1892,7 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code //switch_core_session_write_encoded_video_frame(imember->session, frame, 0, 0); switch_set_flag(frame, SFF_ENCODED); - + if (switch_frame_buffer_dup(imember->fb, frame, &dupframe) == SWITCH_STATUS_SUCCESS) { switch_queue_push(imember->mux_out_queue, dupframe); dupframe = NULL; @@ -1721,12 +1910,14 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code #define MAX_MUX_CODECS 10 -static video_layout_t *find_best_layout(conference_obj_t *conference, layout_group_t *lg) +static video_layout_t *find_best_layout(conference_obj_t *conference, layout_group_t *lg, uint32_t count) { video_layout_node_t *vlnode = NULL, *last = NULL; + if (!count) count = conference->members_with_video + conference->members_with_avatar; + for (vlnode = lg->layouts; vlnode; vlnode = vlnode->next) { - if (vlnode->vlayout->layers >= conference->count) { + if (vlnode->vlayout->layers >= count) { break; } @@ -1736,16 +1927,16 @@ static video_layout_t *find_best_layout(conference_obj_t *conference, layout_gro return vlnode? vlnode->vlayout : last ? last->vlayout : NULL; } -static video_layout_t *get_layout(conference_obj_t *conference) +static video_layout_t *get_layout(conference_obj_t *conference, const char *video_layout_name, const char *video_layout_group) { layout_group_t *lg = NULL; video_layout_t *vlayout = NULL; - if (conference->video_layout_group) { - lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group); - vlayout = find_best_layout(conference, lg); + if (video_layout_group) { + lg = switch_core_hash_find(conference->layout_group_hash, video_layout_group); + vlayout = find_best_layout(conference, lg, 0); } else { - vlayout = switch_core_hash_find(conference->layout_hash, conference->video_layout_name); + vlayout = switch_core_hash_find(conference->layout_hash, video_layout_name); } return vlayout; @@ -1753,11 +1944,16 @@ static video_layout_t *get_layout(conference_obj_t *conference) static void vmute_snap(conference_member_t *member, switch_bool_t clear) { - if (member->conference->canvas && member->video_layer_id > -1) { - mcu_layer_t *layer = NULL; - switch_mutex_lock(member->conference->canvas->mutex); - layer = &member->conference->canvas->layers[member->video_layer_id]; + + if (member->canvas_id > -1 && member->video_layer_id > -1) { + mcu_layer_t *layer = NULL; + mcu_canvas_t *canvas = NULL; + + canvas = member->conference->canvases[member->canvas_id]; + + switch_mutex_lock(canvas->mutex); + layer = &canvas->layers[member->video_layer_id]; switch_img_free(&layer->mute_img); switch_img_free(&member->video_mute_img); @@ -1766,7 +1962,7 @@ static void vmute_snap(conference_member_t *member, switch_bool_t clear) switch_img_copy(layer->cur_img, &layer->mute_img); } - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); } } @@ -1776,10 +1972,10 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_write_thread_run(switch_ void *pop; int loops = 0; - while(switch_test_flag(member, MFLAG_RUNNING) || switch_queue_size(member->mux_out_queue)) { + while(member_test_flag(member, MFLAG_RUNNING) || switch_queue_size(member->mux_out_queue)) { switch_frame_t *frame; - if (switch_test_flag(member, MFLAG_RUNNING)) { + if (member_test_flag(member, MFLAG_RUNNING)) { if (switch_queue_pop(member->mux_out_queue, &pop) == SWITCH_STATUS_SUCCESS) { if (!pop) continue; @@ -1835,35 +2031,30 @@ static void check_video_recording(conference_obj_t *conference, switch_frame_t * } -static int flush_video_queue(switch_queue_t *q) -{ - switch_image_t *img; - void *pop; - int r = 0; - - if (!q) return 0; - - while (switch_queue_size(q) > 1 && switch_queue_trypop(q, &pop) == SWITCH_STATUS_SUCCESS && pop) { - img = (switch_image_t *)pop; - switch_img_free(&img); - r++; - } - - return r + switch_queue_size(q); -} - static void check_avatar(conference_member_t *member, switch_bool_t force) { const char *avatar = NULL, *var = NULL; + mcu_canvas_t *canvas; - if (member->conference->canvas) { - switch_mutex_lock(member->conference->canvas->mutex); + if (member->canvas_id < 0) { + return; + } + + canvas = member->conference->canvases[member->canvas_id]; + + if (conference_test_flag(member->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS) && + (!switch_channel_test_flag(member->channel, CF_VIDEO) || member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY)) { + return; + } + + if (canvas) { + switch_mutex_lock(canvas->mutex); } member->avatar_patched = 0; if (!force && switch_channel_test_flag(member->channel, CF_VIDEO) && member->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { - switch_set_flag_locked(member, MFLAG_ACK_VIDEO); + member_set_flag_locked(member, MFLAG_ACK_VIDEO); } else { if (member->conference->no_video_avatar) { avatar = member->conference->no_video_avatar; @@ -1888,8 +2079,8 @@ static void check_avatar(conference_member_t *member, switch_bool_t force) switch_img_copy(member->video_mute_img, &member->avatar_png_img); } - if (member->conference->canvas) { - switch_mutex_unlock(member->conference->canvas->mutex); + if (canvas) { + switch_mutex_unlock(canvas->mutex); } } @@ -1914,10 +2105,10 @@ static void check_flush(conference_member_t *member) } } -static void patch_fnode(conference_obj_t *conference, conference_file_node_t *fnode) +static void patch_fnode(mcu_canvas_t *canvas, conference_file_node_t *fnode) { if (fnode && fnode->layer_id > -1) { - mcu_layer_t *layer = &conference->canvas->layers[fnode->layer_id]; + mcu_layer_t *layer = &canvas->layers[fnode->layer_id]; switch_frame_t file_frame = { 0 }; switch_status_t status = switch_core_file_read_video(&fnode->fh, &file_frame, SVR_FLUSH); @@ -1926,34 +2117,198 @@ static void patch_fnode(conference_obj_t *conference, conference_file_node_t *fn layer->cur_img = file_frame.img; layer->tagged = 1; } else if (status == SWITCH_STATUS_IGNORE) { - if (conference->canvas && fnode->layer_id > -1 ) { - canvas_del_fnode_layer(conference, fnode); + if (canvas && fnode->layer_id > -1 ) { + canvas_del_fnode_layer(canvas->conference, fnode); } } } } -static void fnode_check_video(conference_obj_t *conference, conference_file_node_t *fnode) { +static void fnode_check_video(conference_file_node_t *fnode) { + mcu_canvas_t *canvas = fnode->conference->canvases[fnode->canvas_id]; + if (switch_core_file_has_video(&fnode->fh) && switch_core_file_read_video(&fnode->fh, NULL, SVR_CHECK) == SWITCH_STATUS_BREAK) { int full_screen = 0; - if (fnode->fh.params) { + if (fnode->fh.params && fnode->conference->canvas_count == 1) { full_screen = switch_true(switch_event_get_header(fnode->fh.params, "full-screen")); } if (full_screen) { - conference->canvas->play_file = 1; - conference->playing_video_file = 1; + canvas->play_file = 1; + canvas->conference->playing_video_file = 1; } else { - canvas_set_fnode_layer(conference, fnode, -1); + canvas_set_fnode_layer(canvas, fnode, -1); } } } +static switch_status_t find_layer(conference_obj_t *conference, mcu_canvas_t *canvas, conference_member_t *member, mcu_layer_t **layerP) +{ + uint32_t avatar_layers = 0; + mcu_layer_t *layer = NULL; + int i; + + switch_mutex_lock(conference->canvas_mutex); + + for (i = 0; i < canvas->total_layers; i++) { + mcu_layer_t *xlayer = &canvas->layers[i]; + + if (xlayer->is_avatar && xlayer->member_id != conference->video_floor_holder) { + avatar_layers++; + } + } + + if (!layer && + (canvas->layers_used < canvas->total_layers || + (avatar_layers && !member->avatar_png_img) || member_test_flag(member, MFLAG_MOD)) && + (member->avatar_png_img || member->video_flow != SWITCH_MEDIA_FLOW_SENDONLY)) { + /* find an empty layer */ + for (i = 0; i < canvas->total_layers; i++) { + mcu_layer_t *xlayer = &canvas->layers[i]; + + if (xlayer->geometry.res_id) { + if (member->video_reservation_id && !strcmp(xlayer->geometry.res_id, member->video_reservation_id)) { + layer = xlayer; + attach_video_layer(member, canvas, i); + break; + } + } else if (xlayer->geometry.flooronly && !xlayer->fnode) { + if (member->id == conference->video_floor_holder) { + layer = xlayer; + attach_video_layer(member, canvas, i); + break; + } + } else if ((!xlayer->member_id || (!member->avatar_png_img && + xlayer->is_avatar && + xlayer->member_id != conference->video_floor_holder)) && + !xlayer->fnode && !xlayer->geometry.fileonly) { + switch_status_t lstatus; + + lstatus = attach_video_layer(member, canvas, i); + + if (lstatus == SWITCH_STATUS_SUCCESS || lstatus == SWITCH_STATUS_BREAK) { + layer = xlayer; + break; + } + } + } + } + + switch_mutex_unlock(conference->canvas_mutex); + + if (layer) { + *layerP = layer; + return SWITCH_STATUS_SUCCESS; + } + + return SWITCH_STATUS_FALSE; + +} + +static void next_canvas(conference_member_t *imember) +{ + if (imember->canvas_id == imember->conference->canvas_count - 1) { + imember->canvas_id = 0; + } else { + imember->canvas_id++; + } +} + +static void pop_next_image(conference_member_t *member, switch_image_t **imgP) +{ + switch_image_t *img = *imgP; + int size = 0; + void *pop; + + if (!member->avatar_png_img && switch_channel_test_flag(member->channel, CF_VIDEO)) { + do { + if (switch_queue_trypop(member->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { + switch_img_free(&img); + img = (switch_image_t *)pop; + member->blanks = 0; + } else { + break; + } + size = switch_queue_size(member->video_queue); + } while(size > member->conference->video_fps.fps / 2); + + if (member_test_flag(member, MFLAG_CAN_BE_SEEN) && member->video_layer_id > -1 && member->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { + if (img) { + member->good_img++; + if ((member->good_img % (int)(member->conference->video_fps.fps * 10)) == 0) { + reset_video_bitrate_counters(member); + } + } else { + member->blanks++; + member->good_img = 0; + + if (member->blanks == member->conference->video_fps.fps || (member->blanks % (int)(member->conference->video_fps.fps * 10)) == 0) { + member->managed_kps = 0; + switch_core_session_request_video_refresh(member->session); + } + + if (member->blanks == member->conference->video_fps.fps * 5) { + member->blackouts++; + check_avatar(member, SWITCH_TRUE); + member->managed_kps = 0; + + if (member->avatar_png_img) { + //if (layer) { + //layer->is_avatar = 1; + //} + + member->auto_avatar = 1; + } + } + } + } + } else { + check_flush(member); + } + + *imgP = img; +} + +static void check_auto_bitrate(conference_member_t *member, mcu_layer_t *layer) +{ + if (conference_test_flag(member->conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE) && !member->managed_kps) { + switch_core_session_message_t msg = { 0 }; + int kps; + int w = 320; + int h = 240; + + if (layer) { + if (layer->screen_w > 320 && layer->screen_h > 240) { + w = layer->screen_w; + h = layer->screen_h; + } + } + + if (!layer || !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", + switch_channel_get_name(member->channel), kps); + } else { + kps = switch_calc_bitrate(w, h, 2, 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); + } + + 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; + } +} + static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj) { - conference_obj_t *conference = (conference_obj_t *) obj; + mcu_canvas_t *canvas = (mcu_canvas_t *) obj; + conference_obj_t *conference = canvas->conference; conference_member_t *imember; switch_codec_t *check_codec = NULL; codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 }; @@ -1965,67 +2320,193 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_frame_t write_frame = { 0 }; uint8_t *packet = NULL; switch_image_t *write_img = NULL, *file_img = NULL; - uint32_t timestamp = 0, avatar_layers = 0; - video_layout_t *vlayout = get_layout(conference); + uint32_t timestamp = 0; + //video_layout_t *vlayout = get_layout(conference); + int members_with_video = 0, members_with_avatar = 0; + int do_refresh = 0; + int last_file_count = 0; - if (!vlayout) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot find layout\n"); - conference->video_layout_name = conference->video_layout_group = NULL; - switch_clear_flag(conference, CFLAG_VIDEO_MUXING); - return NULL; - } - - init_canvas(conference, vlayout); - - conference->video_timer_reset = 1; + canvas->video_timer_reset = 1; packet = switch_core_alloc(conference->pool, SWITCH_RTP_MAX_BUF_LEN); - while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT) && switch_test_flag(conference, CFLAG_VIDEO_MUXING)) { + while (globals.running && !conference_test_flag(conference, CFLAG_DESTRUCT) && conference_test_flag(conference, CFLAG_VIDEO_MUXING)) { switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE, need_reset = SWITCH_FALSE; switch_time_t now; int min_members = 0; + int count_changed = 0; + int file_count = 0, check_async_file = 0, check_file = 0; + switch_image_t *async_file_img = NULL, *normal_file_img = NULL, *file_imgs[2] = { 0 }; + switch_frame_t file_frame = { 0 }; + int j = 0; - - switch_mutex_lock(conference->canvas->mutex); - if (conference->canvas->new_vlayout) { - init_canvas_layers(conference, NULL); + switch_mutex_lock(canvas->mutex); + if (canvas->new_vlayout) { + init_canvas_layers(conference, canvas, NULL); } - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); - if (conference->video_timer_reset) { - conference->video_timer_reset = 0; + if (canvas->video_timer_reset) { + canvas->video_timer_reset = 0; - if (conference->canvas->timer.interval) { - switch_core_timer_destroy(&conference->canvas->timer); + if (canvas->timer.interval) { + switch_core_timer_destroy(&canvas->timer); } - switch_core_timer_init(&conference->canvas->timer, "soft", conference->video_fps.ms, conference->video_fps.samples, NULL); - conference->canvas->send_keyframe = 1; + switch_core_timer_init(&canvas->timer, "soft", conference->video_fps.ms, conference->video_fps.samples, NULL); + canvas->send_keyframe = 1; } if (!conference->playing_video_file) { - switch_core_timer_next(&conference->canvas->timer); + switch_core_timer_next(&canvas->timer); } now = switch_micro_time_now(); + if (members_with_video != conference->members_with_video) { + do_refresh = 100; + count_changed = 1; + } + + if (members_with_avatar != conference->members_with_avatar) { + count_changed = 1; + } + + if (count_changed && !conference_test_flag(conference, CFLAG_PERSONAL_CANVAS)) { + layout_group_t *lg = NULL; + video_layout_t *vlayout = NULL; + int canvas_count = 0; + + switch_mutex_lock(conference->member_mutex); + for (imember = conference->members; imember; imember = imember->next) { + if (imember->canvas_id == canvas->canvas_id || imember->canvas_id == -1) { + canvas_count++; + } + } + switch_mutex_unlock(conference->member_mutex); + + if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) { + if ((vlayout = find_best_layout(conference, lg, canvas_count))) { + switch_mutex_lock(conference->member_mutex); + conference->canvas->new_vlayout = vlayout; + switch_mutex_unlock(conference->member_mutex); + } + } + } + + if (count_changed) { + need_refresh = 1; + need_keyframe = 1; + do_refresh = 100; + } + + if (conference->async_fnode && switch_core_file_has_video(&conference->async_fnode->fh)) { + check_async_file = 1; + file_count++; + } + + if (conference->fnode && switch_core_file_has_video(&conference->fnode->fh)) { + check_file = 1; + file_count++; + } + + if (file_count != last_file_count) { + count_changed = 1; + } + + last_file_count = file_count; + + if (do_refresh) { + if ((do_refresh % 50) == 0) { + switch_mutex_lock(conference->member_mutex); + + for (imember = conference->members; imember; imember = imember->next) { + if (imember->canvas_id != canvas->canvas_id) continue; + + if (imember->session && switch_channel_test_flag(imember->channel, CF_VIDEO)) { + switch_core_session_request_video_refresh(imember->session); + switch_core_media_gen_key_frame(imember->session); + } + } + switch_mutex_unlock(conference->member_mutex); + } + do_refresh--; + } + + members_with_video = conference->members_with_video; + members_with_avatar = conference->members_with_avatar; + + if (conference_test_flag(conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) { + if (conference->members_with_video < 3) { + switch_yield(20000); + continue; + } + } + switch_mutex_lock(conference->member_mutex); - for (imember = conference->members; imember; imember = imember->next) { - void *pop; switch_image_t *img = NULL; - int size = 0; int i; - + if (!imember->session || (!switch_channel_test_flag(imember->channel, CF_VIDEO) && !imember->avatar_png_img) || - switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + conference_test_flag(conference, CFLAG_PERSONAL_CANVAS) || switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { continue; - } + } - if (!switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + if (imember->watching_canvas_id == canvas->canvas_id && switch_channel_test_flag(imember->channel, CF_VIDEO_REFRESH_REQ)) { + switch_channel_clear_flag(imember->channel, CF_VIDEO_REFRESH_REQ); + need_keyframe = SWITCH_TRUE; + } + + if (conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && + imember->watching_canvas_id > -1 && imember->watching_canvas_id == canvas->canvas_id && + !member_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { min_members++; + + if (switch_channel_test_flag(imember->channel, CF_VIDEO)) { + if (imember->video_codec_index < 0 && (check_codec = switch_core_session_get_video_write_codec(imember->session))) { + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + if (check_codec->implementation->codec_id == write_codecs[i]->codec.implementation->codec_id) { + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + need_refresh = SWITCH_TRUE; + break; + } + } + + if (imember->video_codec_index < 0) { + write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t)); + + if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, + &conference->video_codec_settings, conference->pool) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i); + + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + need_refresh = SWITCH_TRUE; + write_codecs[i]->frame.packet = switch_core_alloc(conference->pool, buflen); + write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12; + write_codecs[i]->frame.packetlen = buflen; + write_codecs[i]->frame.buflen = buflen - 12; + switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP); + + } + } + } + + if (imember->video_codec_index < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Codec Error\n"); + switch_core_session_rwunlock(imember->session); + continue; + } + } + } + + if (imember->canvas_id > -1 && imember->canvas_id != canvas->canvas_id) { + switch_core_session_rwunlock(imember->session); + continue; } if (conference->playing_video_file) { @@ -2033,111 +2514,21 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread continue; } - if (conference->canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder && - imember->video_layer_id != conference->canvas->layout_floor_id) { - attach_video_layer(imember, conference->canvas->layout_floor_id); - } - - if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && switch_channel_test_flag(imember->channel, CF_VIDEO)) { - if (switch_channel_test_flag(imember->channel, CF_VIDEO_REFRESH_REQ)) { - switch_channel_clear_flag(imember->channel, CF_VIDEO_REFRESH_REQ); - need_refresh = SWITCH_TRUE; - } - - if (imember->video_codec_index < 0 && (check_codec = switch_core_session_get_video_write_codec(imember->session))) { - for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { - if (check_codec->implementation->codec_id == write_codecs[i]->codec.implementation->codec_id) { - imember->video_codec_index = i; - imember->video_codec_id = check_codec->implementation->codec_id; - break; - } - } - - if (imember->video_codec_index < 0) { - write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t)); - - if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, - &conference->video_codec_settings, conference->pool) == SWITCH_STATUS_SUCCESS) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, - "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i); - - imember->video_codec_index = i; - imember->video_codec_id = check_codec->implementation->codec_id; - - write_codecs[i]->frame.packet = switch_core_alloc(conference->pool, buflen); - write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12; - write_codecs[i]->frame.packetlen = buflen; - write_codecs[i]->frame.buflen = buflen - 12; - switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP); - - } - } - } - - if (imember->video_codec_index < 0) { - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Codec Error\n"); - switch_core_session_rwunlock(imember->session); - continue; - } - } - - img = NULL; - size = 0; - - if (!imember->avatar_png_img && switch_channel_test_flag(imember->channel, CF_VIDEO)) { - do { - if (switch_queue_trypop(imember->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { - switch_img_free(&img); - img = (switch_image_t *)pop; - imember->blanks = 0; - } else { - break; - } - size = switch_queue_size(imember->video_queue); - } while(size > 0); - - if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_layer_id > -1 && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { - if (img) { - imember->good_img++; - if ((imember->good_img % (int)(conference->video_fps.fps * 10)) == 0) { - reset_video_bitrate_counters(imember); - } - } else { - imember->blanks++; - imember->good_img = 0; - - if (imember->blanks == conference->video_fps.fps || (imember->blanks % (int)(conference->video_fps.fps * 10)) == 0) { - imember->managed_kps = 0; - switch_core_session_request_video_refresh(imember->session); - } - - if (imember->blanks == conference->video_fps.fps * 5) { - imember->blackouts++; - check_avatar(imember, SWITCH_TRUE); - imember->managed_kps = 0; - - if (imember->avatar_png_img) { - //if (layer) { - //layer->is_avatar = 1; - //} - - imember->auto_avatar = 1; - } - } - } - } - } else { - check_flush(imember); + //VIDFLOOR + if (conference->canvas_count == 1 && canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder && + imember->video_layer_id != canvas->layout_floor_id) { + attach_video_layer(imember, canvas, canvas->layout_floor_id); } + pop_next_image(imember, &img); layer = NULL; - switch_mutex_lock(conference->canvas->mutex); + switch_mutex_lock(canvas->mutex); //printf("MEMBER %d layer_id %d canvas: %d/%d\n", imember->id, imember->video_layer_id, - // conference->canvas->layers_used, conference->canvas->total_layers); + // canvas->layers_used, canvas->total_layers); if (imember->video_layer_id > -1) { - layer = &conference->canvas->layers[imember->video_layer_id]; + layer = &canvas->layers[imember->video_layer_id]; if (layer->member_id != imember->id) { layer = NULL; imember->video_layer_id = -1; @@ -2157,93 +2548,21 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_img_free(&img); } - - avatar_layers = 0; - for (i = 0; i < conference->canvas->total_layers; i++) { - mcu_layer_t *xlayer = &conference->canvas->layers[i]; - - if (xlayer->is_avatar && xlayer->member_id != conference->video_floor_holder) { - avatar_layers++; + if (!layer) { + if (find_layer(conference, canvas, imember, &layer) != SWITCH_STATUS_SUCCESS) { + next_canvas(imember); } } - if (!layer && - (conference->canvas->layers_used < conference->canvas->total_layers || - (avatar_layers && !imember->avatar_png_img) || switch_test_flag(imember, MFLAG_MOD)) && - (imember->avatar_png_img || imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY)) { - /* find an empty layer */ - for (i = 0; i < conference->canvas->total_layers; i++) { - mcu_layer_t *xlayer = &conference->canvas->layers[i]; + check_auto_bitrate(imember, layer); - if (xlayer->geometry.res_id) { - if (imember->video_reservation_id && !strcmp(xlayer->geometry.res_id, imember->video_reservation_id)) { - layer = xlayer; - attach_video_layer(imember, i); - break; - } - } else if (xlayer->geometry.flooronly && !xlayer->fnode) { - if (imember->id == conference->video_floor_holder) { - layer = xlayer; - attach_video_layer(imember, i); - break; - } - } else if ((!xlayer->member_id || (!imember->avatar_png_img && - xlayer->is_avatar && - xlayer->member_id != conference->video_floor_holder)) && - !xlayer->fnode && !xlayer->geometry.fileonly) { - switch_status_t lstatus; - - lstatus = attach_video_layer(imember, i); - - if (lstatus == SWITCH_STATUS_SUCCESS || lstatus == SWITCH_STATUS_BREAK) { - layer = xlayer; - break; - } - } - } - } - - if (switch_test_flag(imember->conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE) && !imember->managed_kps) { - switch_core_session_message_t msg = { 0 }; - int kps; - int w = 320; - int h = 240; - - if (layer) { - if (layer->screen_w > 320 && layer->screen_h > 240) { - w = layer->screen_w; - h = layer->screen_h; - } - } - - - - if (!layer || !switch_test_flag(imember, MFLAG_CAN_BE_SEEN) || imember->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", - switch_channel_get_name(imember->channel), kps); - } else { - kps = switch_calc_bitrate(w, h, 2, imember->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(imember->channel), kps, layer->screen_w, layer->screen_h); - } - - msg.message_id = SWITCH_MESSAGE_INDICATE_BITRATE_REQ; - msg.numeric_arg = kps * 1024; - msg.from = __FILE__; - - switch_core_session_receive_message(imember->session, &msg); - imember->managed_kps = kps; - } - - if (layer) { //if (layer->cur_img && layer->cur_img != imember->avatar_png_img) { // switch_img_free(&layer->cur_img); //} - if (switch_test_flag(imember, MFLAG_CAN_BE_SEEN)) { + if (member_test_flag(imember, MFLAG_CAN_BE_SEEN)) { layer->mute_patched = 0; } else { switch_image_t *tmp; @@ -2255,7 +2574,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread if (!layer->mute_patched) { if (imember->video_mute_img || layer->mute_img) { - clear_layer(conference->canvas, layer); + clear_layer(layer); if (!layer->mute_img && imember->video_mute_img) { //layer->mute_img = switch_img_read_png(imember->video_mute_png, SWITCH_IMG_FMT_I420); @@ -2263,13 +2582,13 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } if (layer->mute_img) { - scale_and_patch(conference, layer, layer->mute_img, SWITCH_FALSE); + scale_and_patch(layer, layer->mute_img, SWITCH_FALSE); } } tmp = switch_img_write_text_img(layer->screen_w, layer->screen_h, SWITCH_TRUE, "VIDEO MUTED"); - switch_img_patch(conference->canvas->img, tmp, layer->x_pos, layer->y_pos); + switch_img_patch(canvas->img, tmp, layer->x_pos, layer->y_pos); switch_img_free(&tmp); layer->mute_patched = 1; @@ -2294,7 +2613,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); if (img && img != imember->avatar_png_img) { switch_img_free(&img); @@ -2304,107 +2623,672 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_core_session_rwunlock(imember->session); } } - + switch_mutex_unlock(conference->member_mutex); - if (conference->async_fnode) { - if (conference->async_fnode->layer_id > -1) { - patch_fnode(conference, conference->async_fnode); - } else { - fnode_check_video(conference, conference->async_fnode); + if (conference_test_flag(conference, CFLAG_PERSONAL_CANVAS)) { + layout_group_t *lg = NULL; + video_layout_t *vlayout = NULL; + conference_member_t *omember; + + if (video_key_freq && (now - last_key_time) > video_key_freq) { + need_keyframe = SWITCH_TRUE; + last_key_time = now; } - } - if (conference->fnode) { - if (conference->fnode->layer_id > -1) { - patch_fnode(conference, conference->fnode); - } else { - fnode_check_video(conference, conference->fnode); - } - } - - if (!conference->playing_video_file) { - for (i = 0; i < conference->canvas->total_layers; i++) { - mcu_layer_t *layer = &conference->canvas->layers[i]; + switch_mutex_lock(conference->member_mutex); - if (!layer->mute_patched && (layer->member_id > -1 || layer->fnode) && layer->cur_img && (layer->tagged || layer->geometry.overlap)) { - if (conference->canvas->refresh) { - layer->refresh = 1; - conference->canvas->refresh++; - } + for (imember = conference->members; imember; imember = imember->next) { + + if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) || + switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } - if (layer->cur_img) { - scale_and_patch(conference, layer, NULL, SWITCH_FALSE); - } - - layer->tagged = 0; + if (switch_channel_test_flag(imember->channel, CF_VIDEO_REFRESH_REQ)) { + switch_channel_clear_flag(imember->channel, CF_VIDEO_REFRESH_REQ); + need_keyframe = SWITCH_TRUE; } - layer->bugged = 0; + if (count_changed) { + int total = conference->members_with_video; + + if (!conference_test_flag(conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS)) { + total += conference->members_with_avatar; + } + + if (imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { + total--; + } + + if (total < 1) total = 1; + + if (conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) { + if ((vlayout = find_best_layout(conference, lg, total + file_count))) { + init_canvas_layers(conference, imember->canvas, vlayout); + } + } + } + + if (imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { + pop_next_image(imember, &imember->pcanvas_img); + } + + switch_core_session_rwunlock(imember->session); } + + if (check_async_file) { + if (switch_core_file_read_video(&conference->async_fnode->fh, &file_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + if ((async_file_img = file_frame.img)) { + file_imgs[j++] = async_file_img; + } + } + } + + if (check_file) { + if (switch_core_file_read_video(&conference->fnode->fh, &file_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + if ((normal_file_img = file_frame.img)) { + file_imgs[j++] = normal_file_img; + } + } + } + + for (imember = conference->members; imember; imember = imember->next) { + int i = 0; + + if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO || imember->video_flow == SWITCH_MEDIA_FLOW_SENDONLY) || + switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } + + 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) || omember->video_flow == 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 != 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) { + conf_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))) { + 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))) { + layer_set_logo(omember, layer, var); + } + } + + layer->member_id = omember->id; + } + + if (!layer && omember->al) { + conf_api_sub_position(omember, NULL, "0:0:0"); + } + + use_img = omember->pcanvas_img; + + if (layer) { + + if (use_img && !omember->avatar_png_img) { + layer->avatar_patched = 0; + } else { + if (!layer->avatar_patched) { + scale_and_patch(layer, omember->avatar_png_img, SWITCH_FALSE); + layer->avatar_patched = 1; + } + use_img = NULL; + layer = NULL; + } + + if (layer) { + if (member_test_flag(imember, MFLAG_CAN_BE_SEEN)) { + layer->mute_patched = 0; + } else { + if (!layer->mute_patched) { + switch_image_t *tmp; + scale_and_patch(layer, imember->video_mute_img ? imember->video_mute_img : omember->pcanvas_img, SWITCH_FALSE); + tmp = switch_img_write_text_img(layer->screen_w, layer->screen_h, SWITCH_TRUE, "VIDEO MUTED"); + switch_img_patch(imember->canvas->img, tmp, layer->x_pos, layer->y_pos); + switch_img_free(&tmp); + layer->mute_patched = 1; + } + + use_img = NULL; + layer = NULL; + } + } + + if (layer && use_img) { + scale_and_patch(layer, use_img, SWITCH_FALSE); + } + } + + check_auto_bitrate(omember, layer); + } + + for (j = 0; j < file_count; j++) { + switch_image_t *img = file_imgs[j]; + + if (i < imember->canvas->total_layers) { + layer = &imember->canvas->layers[i++]; + scale_and_patch(layer, img, SWITCH_FALSE); + } + } + + switch_core_session_rwunlock(imember->session); + } + + switch_img_free(&normal_file_img); + switch_img_free(&async_file_img); + + for (imember = conference->members; imember; imember = imember->next) { + switch_frame_t *dupframe; + + if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) || + switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } + + if (need_refresh) { + switch_core_session_request_video_refresh(imember->session); + } + + if (need_keyframe) { + switch_core_media_gen_key_frame(imember->session); + } + + switch_set_flag(&write_frame, SFF_RAW_RTP); + write_frame.img = imember->canvas->img; + write_frame.packet = packet; + write_frame.data = ((uint8_t *)packet) + 12; + write_frame.datalen = 0; + write_frame.buflen = SWITCH_RTP_MAX_BUF_LEN - 12; + write_frame.packetlen = 0; + + if (switch_frame_buffer_dup(imember->fb, &write_frame, &dupframe) == SWITCH_STATUS_SUCCESS) { + switch_queue_push(imember->mux_out_queue, dupframe); + dupframe = NULL; + } + + switch_core_session_rwunlock(imember->session); + } + + switch_mutex_unlock(conference->member_mutex); + } else { + + if (canvas->canvas_id == 0) { + if (conference->async_fnode) { + if (conference->async_fnode->layer_id > -1) { + patch_fnode(canvas, conference->async_fnode); + } else { + fnode_check_video(conference->async_fnode); + } + } + + if (conference->fnode) { + if (conference->fnode->layer_id > -1) { + patch_fnode(canvas, conference->fnode); + } else { + fnode_check_video(conference->fnode); + } + } + } + + if (!conference->playing_video_file) { + for (i = 0; i < canvas->total_layers; i++) { + mcu_layer_t *layer = &canvas->layers[i]; + + if (!layer->mute_patched && (layer->member_id > -1 || layer->fnode) && layer->cur_img && (layer->tagged || layer->geometry.overlap)) { + if (canvas->refresh) { + layer->refresh = 1; + canvas->refresh++; + } + + if (layer->cur_img) { + scale_and_patch(layer, NULL, SWITCH_FALSE); + } + + layer->tagged = 0; + } + + layer->bugged = 0; + } + } + + if (canvas->refresh > 1) { + canvas->refresh = 0; + } + + if (canvas->send_keyframe > 0) { + if (canvas->send_keyframe == 1 || (canvas->send_keyframe % 10) == 0) { + need_keyframe = SWITCH_TRUE; + need_refresh = SWITCH_TRUE; + } + canvas->send_keyframe--; + } + + if (video_key_freq && (now - last_key_time) > video_key_freq) { + need_keyframe = SWITCH_TRUE; + last_key_time = now; + } + + write_img = canvas->img; + timestamp = canvas->timer.samplecount; + + if (conference->playing_video_file) { + if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { + switch_img_free(&file_img); + + 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_core_timer_sync(&canvas->timer); + timestamp = canvas->timer.samplecount; + } + } else if (file_img) { + switch_img_free(&file_img); + } + + write_frame.img = write_img; + + if (conference->canvas_count == 1) { + check_video_recording(conference, &write_frame); + } + + if (conference->canvas_count > 1) { + switch_image_t *img_copy = NULL; + + switch_img_copy(write_img, &img_copy); + + if (switch_queue_trypush(canvas->video_queue, img_copy) != SWITCH_STATUS_SUCCESS) { + switch_img_free(&img_copy); + } + } + + if (min_members && conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + write_codecs[i]->frame.img = write_img; + write_canvas_image_to_codec_group(conference, canvas, write_codecs[i], i, + timestamp, need_refresh, need_keyframe, need_reset); + + if (canvas->video_write_bandwidth) { + switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &canvas->video_write_bandwidth, NULL, NULL); + canvas->video_write_bandwidth = 0; + } + + } + } + + switch_mutex_lock(conference->member_mutex); + for (imember = conference->members; imember; imember = imember->next) { + switch_frame_t *dupframe; + + if (imember->watching_canvas_id != canvas->canvas_id) continue; + + if (conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && !member_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + continue; + } + + if (!imember->session || !switch_channel_test_flag(imember->channel, CF_VIDEO) || + switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } + + if (need_refresh) { + switch_core_session_request_video_refresh(imember->session); + } + + if (need_keyframe) { + switch_core_media_gen_key_frame(imember->session); + } + + switch_set_flag(&write_frame, SFF_RAW_RTP); + write_frame.img = write_img; + write_frame.packet = packet; + write_frame.data = ((uint8_t *)packet) + 12; + write_frame.datalen = 0; + write_frame.buflen = SWITCH_RTP_MAX_BUF_LEN - 12; + write_frame.packetlen = 0; + + //switch_core_session_write_video_frame(imember->session, &write_frame, SWITCH_IO_FLAG_NONE, 0); + + if (switch_frame_buffer_dup(imember->fb, &write_frame, &dupframe) == SWITCH_STATUS_SUCCESS) { + switch_queue_push(imember->mux_out_queue, dupframe); + dupframe = NULL; + } + + if (imember->session) { + switch_core_session_rwunlock(imember->session); + } + } + + switch_mutex_unlock(conference->member_mutex); + } // NOT PERSONAL + } + + switch_img_free(&file_img); + + for (i = 0; i < MCU_MAX_LAYERS; i++) { + layer = &canvas->layers[i]; + + switch_mutex_lock(canvas->mutex); + switch_img_free(&layer->cur_img); + switch_img_free(&layer->img); + layer->banner_patched = 0; + switch_img_free(&layer->banner_img); + switch_img_free(&layer->logo_img); + switch_img_free(&layer->logo_text_img); + switch_img_free(&layer->mute_img); + switch_mutex_unlock(canvas->mutex); + + if (layer->txthandle) { + switch_img_txt_handle_destroy(&layer->txthandle); + } + } + + for (i = 0; i < MAX_MUX_CODECS; i++) { + if (write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec)) { + switch_core_codec_destroy(&write_codecs[i]->codec); + } + } + + switch_core_timer_destroy(&canvas->timer); + destroy_canvas(&canvas); + + return NULL; +} + +static void pop_next_canvas_image(mcu_canvas_t *canvas, switch_image_t **imgP) +{ + switch_image_t *img = *imgP; + int size = 0; + void *pop; + + switch_img_free(&img); + + do { + if (switch_queue_trypop(canvas->video_queue, &pop) == SWITCH_STATUS_SUCCESS && pop) { + switch_img_free(&img); + img = (switch_image_t *)pop; + } else { + break; + } + size = switch_queue_size(canvas->video_queue); + } while(size > canvas->conference->video_fps.fps / 2); + + *imgP = img; +} + +static void *SWITCH_THREAD_FUNC conference_super_video_muxing_thread_run(switch_thread_t *thread, void *obj) +{ + mcu_canvas_t *canvas = (mcu_canvas_t *) obj; + conference_obj_t *conference = canvas->conference; + conference_member_t *imember; + switch_codec_t *check_codec = NULL; + codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 }; + int buflen = SWITCH_RTP_MAX_BUF_LEN; + int i = 0; + switch_time_t last_key_time = 0; + uint32_t video_key_freq = 10000000; + mcu_layer_t *layer = NULL; + switch_frame_t write_frame = { 0 }; + uint8_t *packet = NULL; + switch_image_t *write_img = NULL; + uint32_t timestamp = 0; + int last_used_canvases[MAX_CANVASES] = { 0 }; + + + canvas->video_timer_reset = 1; + + packet = switch_core_alloc(conference->pool, SWITCH_RTP_MAX_BUF_LEN); + + while (globals.running && !conference_test_flag(conference, CFLAG_DESTRUCT) && conference_test_flag(conference, CFLAG_VIDEO_MUXING)) { + switch_bool_t need_refresh = SWITCH_FALSE, need_keyframe = SWITCH_FALSE, need_reset = SWITCH_FALSE; + switch_time_t now; + int min_members = 0; + int count_changed = 0; + int layer_idx = 0, j = 0; + switch_image_t *img = NULL; + int used_canvases = 0; + + switch_mutex_lock(canvas->mutex); + if (canvas->new_vlayout) { + init_canvas_layers(conference, canvas, NULL); + } + switch_mutex_unlock(canvas->mutex); + + if (canvas->video_timer_reset) { + canvas->video_timer_reset = 0; + + if (canvas->timer.interval) { + switch_core_timer_destroy(&canvas->timer); + } + + switch_core_timer_init(&canvas->timer, "soft", conference->video_fps.ms, conference->video_fps.samples, NULL); + canvas->send_keyframe = 1; } - if (conference->canvas->refresh > 1) { - conference->canvas->refresh = 0; + if (!conference->playing_video_file) { + switch_core_timer_next(&canvas->timer); } - if (conference->canvas->send_keyframe) { - need_keyframe = SWITCH_TRUE; - need_refresh = SWITCH_TRUE; - conference->canvas->send_keyframe = 0; + now = switch_micro_time_now(); + + if (canvas->send_keyframe > 0) { + if (canvas->send_keyframe == 1 || (canvas->send_keyframe % 10) == 0) { + need_keyframe = SWITCH_TRUE; + need_refresh = SWITCH_TRUE; + } + canvas->send_keyframe--; } if (video_key_freq && (now - last_key_time) > video_key_freq) { need_keyframe = SWITCH_TRUE; last_key_time = now; } - - write_img = conference->canvas->img; - timestamp = conference->canvas->timer.samplecount; - if (conference->playing_video_file) { - if (switch_core_file_read_video(&conference->fnode->fh, &write_frame, SVR_BLOCK | SVR_FLUSH) == SWITCH_STATUS_SUCCESS) { - switch_img_free(&file_img); + for (j = 0; j < conference->canvas_count; j++) { + mcu_canvas_t *jcanvas = (mcu_canvas_t *) conference->canvases[j]; - if (conference->canvas->play_file) { - conference->canvas->send_keyframe = 1; - conference->canvas->play_file = 0; - - conference->canvas->timer.interval = 1; - conference->canvas->timer.samples = 90; - } - - write_img = file_img = write_frame.img; - - switch_core_timer_sync(&conference->canvas->timer); - timestamp = conference->canvas->timer.samplecount; + if (jcanvas->layers_used > 0 || conference->super_canvas_show_all_layers) { + used_canvases++; } - } else if (file_img) { - switch_img_free(&file_img); + + if (jcanvas->layers_used != last_used_canvases[j]) { + count_changed++; + } + + last_used_canvases[j] = jcanvas->layers_used; } + + if (count_changed) { + int total = used_canvases; + layout_group_t *lg = NULL; + video_layout_t *vlayout = NULL; - write_frame.img = write_img; - check_video_recording(conference, &write_frame); + if (total < 1) total = 1; - if (min_members && switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { - for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { - write_codecs[i]->frame.img = write_img; - write_canvas_image_to_codec_group(conference, write_codecs[i], i, - timestamp, need_refresh, need_keyframe, need_reset); - - if (conference->video_write_bandwidth) { - switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &conference->video_write_bandwidth, NULL, NULL); - conference->video_write_bandwidth = 0; + if ((lg = switch_core_hash_find(conference->layout_group_hash, CONFERENCE_MUX_DEFAULT_SUPER_LAYOUT))) { + if ((vlayout = find_best_layout(conference, lg, total))) { + init_canvas_layers(conference, canvas, vlayout); } - } } + switch_mutex_lock(conference->member_mutex); + + for (imember = conference->members; imember; imember = imember->next) { + int i; + + if (!imember->session || (!switch_channel_test_flag(imember->channel, CF_VIDEO) && !imember->avatar_png_img) || + conference_test_flag(conference, CFLAG_PERSONAL_CANVAS) || switch_core_session_read_lock(imember->session) != SWITCH_STATUS_SUCCESS) { + continue; + } + + if (imember->watching_canvas_id == canvas->canvas_id && switch_channel_test_flag(imember->channel, CF_VIDEO_REFRESH_REQ)) { + switch_channel_clear_flag(imember->channel, CF_VIDEO_REFRESH_REQ); + need_keyframe = SWITCH_TRUE; + } + + if (conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && + imember->watching_canvas_id > -1 && imember->watching_canvas_id == canvas->canvas_id && + !member_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + min_members++; + + if (switch_channel_test_flag(imember->channel, CF_VIDEO)) { + if (imember->video_codec_index < 0 && (check_codec = switch_core_session_get_video_write_codec(imember->session))) { + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + if (check_codec->implementation->codec_id == write_codecs[i]->codec.implementation->codec_id) { + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + need_refresh = SWITCH_TRUE; + break; + } + } + + if (imember->video_codec_index < 0) { + write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t)); + + if (switch_core_codec_copy(check_codec, &write_codecs[i]->codec, + &conference->video_codec_settings, conference->pool) == SWITCH_STATUS_SUCCESS) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, + "Setting up video write codec %s at slot %d\n", write_codecs[i]->codec.implementation->iananame, i); + + imember->video_codec_index = i; + imember->video_codec_id = check_codec->implementation->codec_id; + need_refresh = SWITCH_TRUE; + write_codecs[i]->frame.packet = switch_core_alloc(conference->pool, buflen); + write_codecs[i]->frame.data = ((uint8_t *)write_codecs[i]->frame.packet) + 12; + write_codecs[i]->frame.packetlen = buflen; + write_codecs[i]->frame.buflen = buflen - 12; + switch_set_flag((&write_codecs[i]->frame), SFF_RAW_RTP); + + } + } + } + + if (imember->video_codec_index < 0) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Write Codec Error\n"); + switch_core_session_rwunlock(imember->session); + continue; + } + } + } + + switch_core_session_rwunlock(imember->session); + } + + switch_mutex_unlock(conference->member_mutex); + + layer_idx = 0; + + for (j = 0; j < conference->canvas_count; j++) { + mcu_canvas_t *jcanvas = (mcu_canvas_t *) conference->canvases[j]; + + pop_next_canvas_image(jcanvas, &img); + + if (!jcanvas->layers_used && !conference->super_canvas_show_all_layers) { + switch_img_free(&img); + continue; + } + + if (layer_idx < canvas->total_layers) { + layer = &canvas->layers[layer_idx++]; + + if (layer->member_id != jcanvas->canvas_id) { + layer->member_id = jcanvas->canvas_id; + switch_img_free(&layer->cur_img); + } + + if (canvas->refresh) { + layer->refresh = 1; + canvas->refresh++; + } + + if (img) { + + if (conference->super_canvas_label_layers) { + char str[80] = ""; + switch_image_t *tmp; + const char *format = "#cccccc:#142e55:FreeSans.ttf:4%:"; + + switch_snprintf(str, sizeof(str), "%sCanvas %d", format, jcanvas->canvas_id + 1); + tmp = switch_img_write_text_img(img->d_w, img->d_h, SWITCH_TRUE, str); + switch_img_patch(img, tmp, 0, 0); + switch_img_free(&tmp); + } + + switch_img_free(&layer->cur_img); + layer->cur_img = img; + img = NULL; + } + + scale_and_patch(layer, NULL, SWITCH_FALSE); + } + + switch_img_free(&img); + } + + if (canvas->refresh > 1) { + canvas->refresh = 0; + } + + write_img = canvas->img; + timestamp = canvas->timer.samplecount; + + if (!write_img) continue; + + write_frame.img = write_img; + check_video_recording(conference, &write_frame); + + if (min_members && conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { + for (i = 0; write_codecs[i] && switch_core_codec_ready(&write_codecs[i]->codec) && i < MAX_MUX_CODECS; i++) { + write_codecs[i]->frame.img = write_img; + write_canvas_image_to_codec_group(conference, canvas, write_codecs[i], i, timestamp, need_refresh, need_keyframe, need_reset); + + if (canvas->video_write_bandwidth) { + switch_core_codec_control(&write_codecs[i]->codec, SCC_VIDEO_BANDWIDTH, SCCT_INT, &canvas->video_write_bandwidth, NULL, NULL); + canvas->video_write_bandwidth = 0; + } + } + } + switch_mutex_lock(conference->member_mutex); for (imember = conference->members; imember; imember = imember->next) { switch_frame_t *dupframe; - if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && !switch_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { + if (imember->watching_canvas_id != canvas->canvas_id) continue; + + if (conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING) && !member_test_flag(imember, MFLAG_NO_MINIMIZE_ENCODING)) { continue; } @@ -2441,15 +3325,13 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } - switch_mutex_unlock(conference->member_mutex); + switch_mutex_unlock(conference->member_mutex); } - switch_img_free(&file_img); - for (i = 0; i < MCU_MAX_LAYERS; i++) { - layer = &conference->canvas->layers[i]; + layer = &canvas->layers[i]; - switch_mutex_lock(conference->canvas->mutex); + switch_mutex_lock(canvas->mutex); switch_img_free(&layer->cur_img); switch_img_free(&layer->img); layer->banner_patched = 0; @@ -2457,7 +3339,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread switch_img_free(&layer->logo_img); switch_img_free(&layer->logo_text_img); switch_img_free(&layer->mute_img); - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); if (layer->txthandle) { switch_img_txt_handle_destroy(&layer->txthandle); @@ -2470,8 +3352,8 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread } } - switch_core_timer_destroy(&conference->canvas->timer); - destroy_canvas(&conference->canvas); + switch_core_timer_destroy(&canvas->timer); + destroy_canvas(&canvas); return NULL; } @@ -2513,14 +3395,14 @@ static void gen_arc(conference_obj_t *conference, switch_stream_handle_t *stream switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (member->channel && switch_test_flag(member, MFLAG_CAN_SPEAK) && !switch_test_flag(member, MFLAG_NO_POSITIONAL)) { + if (member->channel && member_test_flag(member, MFLAG_CAN_SPEAK) && !member_test_flag(member, MFLAG_NO_POSITIONAL)) { count++; } } if (count < 3) { for (member = conference->members; member; member = member->next) { - if (member->channel && !switch_test_flag(member, MFLAG_NO_POSITIONAL) && member->al) { + if (member->channel && !member_test_flag(member, MFLAG_NO_POSITIONAL) && member->al) { member->al->pos_x = 0; member->al->pos_y = 0; @@ -2547,14 +3429,14 @@ static void gen_arc(conference_obj_t *conference, switch_stream_handle_t *stream for (member = conference->members; member; member = member->next) { - if (!member->channel || switch_test_flag(member, MFLAG_NO_POSITIONAL) || !switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!member->channel || member_test_flag(member, MFLAG_NO_POSITIONAL) || !member_test_flag(member, MFLAG_CAN_SPEAK)) { continue; } if (!member->al) { member->al = create_al(member->pool); } - switch_set_flag(member, MFLAG_POSITIONAL); + member_set_flag(member, MFLAG_POSITIONAL); if (pos == 0) { x = 0; @@ -2680,7 +3562,7 @@ static void conference_cdr_del(conference_member_t *member) } if (member->cdr_node) { member->cdr_node->leave_time = switch_epoch_time_now(NULL); - member->cdr_node->flags = member->flags; + memcpy(member->cdr_node->mflags, member->flags, sizeof(member->flags)); member->cdr_node->member = NULL; } } @@ -2740,12 +3622,12 @@ static const char *audio_flow(conference_member_t *member) { const char *flow = "sendrecv"; - if (!switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!member_test_flag(member, MFLAG_CAN_SPEAK)) { flow = "recvonly"; } if (member->channel && switch_channel_test_flag(member->channel, CF_HOLD)) { - flow = switch_test_flag(member, MFLAG_CAN_SPEAK) ? "sendonly" : "inactive"; + flow = member_test_flag(member, MFLAG_CAN_SPEAK) ? "sendonly" : "inactive"; } return flow; @@ -3070,7 +3952,7 @@ static void conference_cdr_render(conference_obj_t *conference) if (!(x_ptr = switch_xml_add_child_d(x_conference, "end_time", conf_off++))) { abort(); } - switch_xml_set_attr_d(x_ptr, "endconf_forced", switch_test_flag(conference, CFLAG_ENDCONF_FORCED) ? "true" : "false"); + switch_xml_set_attr_d(x_ptr, "endconf_forced", conference_test_flag(conference, CFLAG_ENDCONF_FORCED) ? "true" : "false"); switch_xml_set_attr_d(x_ptr, "type", "UNIX-epoch"); switch_snprintf(str, sizeof(str), "%ld", (long)conference->end_time); switch_xml_set_txt_d(x_ptr, str); @@ -3112,16 +3994,16 @@ static void conference_cdr_render(conference_obj_t *conference) switch_assert(x_flags); x_tag = switch_xml_add_child_d(x_flags, "is_moderator", flag_off++); - switch_xml_set_txt_d(x_tag, switch_test_flag(np, MFLAG_MOD) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, cdr_test_mflag(np, MFLAG_MOD) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "end_conference", flag_off++); - switch_xml_set_txt_d(x_tag, switch_test_flag(np, MFLAG_ENDCONF) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, cdr_test_mflag(np, MFLAG_ENDCONF) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "was_kicked", flag_off++); - switch_xml_set_txt_d(x_tag, switch_test_flag(np, MFLAG_KICKED) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, cdr_test_mflag(np, MFLAG_KICKED) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "is_ghost", flag_off++); - switch_xml_set_txt_d(x_tag, switch_test_flag(np, MFLAG_GHOST) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, cdr_test_mflag(np, MFLAG_GHOST) ? "true" : "false"); if (!(x_cp = switch_xml_add_child_d(x_member, "caller_profile", member_off++))) { abort(); @@ -3429,7 +4311,7 @@ static void conference_mod_event_channel_handler(const char *event_channel, cJSO } } - switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ALERT, "conf %s CMD %s [%s] %d\n", conf_name, key, action, cid); + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "conf %s CMD %s [%s] %d\n", conf_name, key, action, cid); if (zstr(action)) { goto end; @@ -3443,21 +4325,26 @@ static void conference_mod_event_channel_handler(const char *event_channel, cJSO !strcasecmp(action, "tmute") || !strcasecmp(action, "vmute") || !strcasecmp(action, "unvmute") || - !strcasecmp(action, "tvmute") + !strcasecmp(action, "tvmute") ) { exec = switch_mprintf("%s %s %d", conf_name, action, cid); } else if (!strcasecmp(action, "volume_in") || !strcasecmp(action, "volume_out") || !strcasecmp(action, "vid-res-id") || !strcasecmp(action, "vid-floor") || + !strcasecmp(action, "vid-layer") || + !strcasecmp(action, "vid-canvas") || + !strcasecmp(action, "vid-watching-canvas") || !strcasecmp(action, "vid-banner")) { exec = switch_mprintf("%s %s %d %s", conf_name, action, cid, argv[0]); } else if (!strcasecmp(action, "play") || !strcasecmp(action, "stop")) { exec = switch_mprintf("%s %s %s", conf_name, action, argv[0]); } else if (!strcasecmp(action, "recording") || !strcasecmp(action, "vid-layout") || !strcasecmp(action, "vid-write-png")) { + if (!argv[1]) { argv[1] = "all"; } + exec = switch_mprintf("%s %s %s %s", conf_name, action, argv[0], argv[1]); } else if (!strcasecmp(action, "transfer") && cid) { @@ -3624,14 +4511,14 @@ static switch_status_t conference_add_event_member_data(conference_member_t *mem } - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hear", "%s", switch_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false" ); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "See", "%s", switch_test_flag(member, MFLAG_CAN_BE_SEEN) ? "true" : "false" ); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" ); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", switch_test_flag(member, MFLAG_TALKING) ? "true" : "false" ); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hear", "%s", member_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "See", "%s", member_test_flag(member, MFLAG_CAN_BE_SEEN) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", member_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", member_test_flag(member, MFLAG_TALKING) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", member_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" ); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", switch_test_flag(member, MFLAG_MOD) ? "moderator" : "member"); - switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Ghost", "%s", switch_test_flag(member, MFLAG_GHOST) ? "true" : "false"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", member_test_flag(member, MFLAG_MOD) ? "moderator" : "member"); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Ghost", "%s", member_test_flag(member, MFLAG_GHOST) ? "true" : "false"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Energy-Level", "%d", member->energy_level); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Current-Energy", "%d", member->score); @@ -3691,7 +4578,7 @@ static conference_member_t *conference_member_get(conference_obj_t *conference, switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_NOCHANNEL)) { continue; } @@ -3701,8 +4588,8 @@ static conference_member_t *conference_member_get(conference_obj_t *conference, } if (member) { - if (!switch_test_flag(member, MFLAG_INTREE) || - switch_test_flag(member, MFLAG_KICKED) || + if (!member_test_flag(member, MFLAG_INTREE) || + member_test_flag(member, MFLAG_KICKED) || (member->session && !switch_channel_up(switch_core_session_get_channel(member->session)))) { /* member is kicked or hanging up so forget it */ @@ -3731,15 +4618,15 @@ static switch_status_t conference_record_stop(conference_obj_t *conference, swit switch_assert(conference != NULL); switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { - if (!switch_test_flag(conference, CFLAG_CONF_RESTART_AUTO_RECORD) && member->rec && member->rec->autorec) { + if (member_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { + if (!conference_test_flag(conference, CFLAG_CONF_RESTART_AUTO_RECORD) && member->rec && member->rec->autorec) { stream->write_function(stream, "Stopped AUTO recording file %s (Auto Recording Now Disabled)\n", member->rec_path); conference->auto_record = 0; } else { stream->write_function(stream, "Stopped recording file %s\n", member->rec_path); } - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); count++; } @@ -3761,21 +4648,21 @@ static switch_status_t conference_record_action(conference_obj_t *conference, ch switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (switch_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) + if (member_test_flag(member, MFLAG_NOCHANNEL) && (!path || !strcmp(path, member->rec_path))) { //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Action: %d\n", action); switch (action) { case REC_ACTION_STOP: - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); count++; break; case REC_ACTION_PAUSE: - switch_set_flag_locked(member, MFLAG_PAUSE_RECORDING); + member_set_flag_locked(member, MFLAG_PAUSE_RECORDING); count = 1; break; case REC_ACTION_RESUME: - switch_clear_flag_locked(member, MFLAG_PAUSE_RECORDING); + member_clear_flag_locked(member, MFLAG_PAUSE_RECORDING); count = 1; break; } @@ -3833,9 +4720,9 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint } if ((rel->flags & RFLAG_CAN_SEND_VIDEO)) { - switch_clear_flag(member, MFLAG_RECEIVING_VIDEO); + member_clear_flag(member, MFLAG_RECEIVING_VIDEO); if ((omember = conference_member_get(member->conference, rel->id))) { - switch_clear_flag(omember, MFLAG_RECEIVING_VIDEO); + member_clear_flag(omember, MFLAG_RECEIVING_VIDEO); switch_thread_rwlock_unlock(omember->rwlock); } } @@ -3860,7 +4747,7 @@ static void send_json_event(conference_obj_t *conference) char *name = NULL, *domain = NULL, *dup_domain = NULL; char *event_channel = NULL; - if (!switch_test_flag(conference, CFLAG_JSON_EVENTS)) { + if (!conference_test_flag(conference, CFLAG_JSON_EVENTS)) { return; } @@ -3896,7 +4783,7 @@ static void send_rfc_event(conference_obj_t *conference) char *body; char *name = NULL, *domain = NULL, *dup_domain = NULL; - if (!switch_test_flag(conference, CFLAG_RFC4579)) { + if (!conference_test_flag(conference, CFLAG_RFC4579)) { return; } @@ -3935,7 +4822,7 @@ static void send_conference_notify(conference_obj_t *conference, const char *sta switch_event_t *event; char *name = NULL, *domain = NULL, *dup_domain = NULL; - if (!switch_test_flag(conference, CFLAG_RFC4579)) { + if (!conference_test_flag(conference, CFLAG_RFC4579)) { return; } @@ -3978,18 +4865,19 @@ static void 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)) { + if (!member->conference->la || !member->json || + !member->status_field || switch_channel_test_flag(member->channel, CF_VIDEO_ONLY) || member_test_flag(member, MFLAG_SECOND_SCREEN)) { return; } switch_live_array_lock(member->conference->la); - if (switch_test_flag(member->conference, CFLAG_JSON_STATUS)) { + if (conference_test_flag(member->conference, CFLAG_JSON_STATUS)) { json = cJSON_CreateObject(); audio = cJSON_CreateObject(); - cJSON_AddItemToObject(audio, "muted", cJSON_CreateBool(!switch_test_flag(member, MFLAG_CAN_SPEAK))); + cJSON_AddItemToObject(audio, "muted", cJSON_CreateBool(!member_test_flag(member, MFLAG_CAN_SPEAK))); cJSON_AddItemToObject(audio, "onHold", cJSON_CreateBool(switch_channel_test_flag(member->channel, CF_HOLD))); - cJSON_AddItemToObject(audio, "talking", cJSON_CreateBool(switch_test_flag(member, MFLAG_TALKING))); + cJSON_AddItemToObject(audio, "talking", cJSON_CreateBool(member_test_flag(member, MFLAG_TALKING))); cJSON_AddItemToObject(audio, "floor", cJSON_CreateBool(member == member->conference->floor_holder)); cJSON_AddItemToObject(audio, "energyScore", cJSON_CreateNumber(member->score)); cJSON_AddItemToObject(json, "audio", audio); @@ -3998,9 +4886,9 @@ static void member_update_status_field(conference_member_t *member) video = cJSON_CreateObject(); cJSON_AddItemToObject(video, "avatarPresented", cJSON_CreateBool(!!member->avatar_png_img)); cJSON_AddItemToObject(video, "mediaFlow", cJSON_CreateString(member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY ? "sendOnly" : "sendRecv")); - cJSON_AddItemToObject(video, "muted", cJSON_CreateBool(!switch_test_flag(member, MFLAG_CAN_BE_SEEN))); + cJSON_AddItemToObject(video, "muted", cJSON_CreateBool(!member_test_flag(member, MFLAG_CAN_BE_SEEN))); cJSON_AddItemToObject(video, "floor", cJSON_CreateBool(member && member->id == member->conference->video_floor_holder)); - if (member && member->id == member->conference->video_floor_holder && switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) { + if (member && member->id == member->conference->video_floor_holder && conference_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) { cJSON_AddItemToObject(video, "floorLocked", cJSON_CreateTrue()); } cJSON_AddItemToObject(video, "reservationID", member->video_reservation_id ? @@ -4016,24 +4904,24 @@ static void member_update_status_field(conference_member_t *member) json_display = cJSON_PrintUnformatted(json); cJSON_Delete(json); } else { - if (!switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!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 (switch_test_flag(member, MFLAG_TALKING)) { + if (member_test_flag(member, MFLAG_TALKING)) { str = "TALKING (FLOOR)"; } else { str = "FLOOR"; } - } else if (switch_test_flag(member, MFLAG_TALKING)) { + } else if (member_test_flag(member, MFLAG_TALKING)) { str = "TALKING"; } else { str = "ACTIVE"; } if (switch_channel_test_flag(member->channel, CF_VIDEO)) { - if (!switch_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (!member_test_flag(member, MFLAG_CAN_BE_SEEN)) { vstr = " VIDEO (BLIND)"; } else { vstr = " VIDEO"; @@ -4059,11 +4947,20 @@ static void member_update_status_field(conference_member_t *member) static void adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join) { - if (conference && conference->la && member->session && !switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) { + + //if (member->video_flow == 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)) { 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"); const char *event_channel = cookie ? cookie : uuid; + switch_event_t *variables; + switch_event_header_t *hp; msg = cJSON_CreateObject(); data = json_add_child_obj(msg, "pvtData", NULL); @@ -4074,12 +4971,29 @@ static void adv_la(conference_obj_t *conference, conference_member_t *member, sw cJSON_AddItemToObject(data, "action", cJSON_CreateString(join ? "conference-liveArray-join" : "conference-liveArray-part")); cJSON_AddItemToObject(data, "laChannel", cJSON_CreateString(conference->la_event_channel)); cJSON_AddItemToObject(data, "laName", cJSON_CreateString(conference->la_name)); - cJSON_AddItemToObject(data, "role", cJSON_CreateString(switch_test_flag(member, MFLAG_MOD) ? "moderator" : "participant")); + cJSON_AddItemToObject(data, "role", cJSON_CreateString(member_test_flag(member, MFLAG_MOD) ? "moderator" : "participant")); cJSON_AddItemToObject(data, "chatID", cJSON_CreateString(conference->chat_id)); - if (switch_test_flag(member, MFLAG_MOD)) { + cJSON_AddItemToObject(data, "canvasCount", cJSON_CreateNumber(conference->canvas_count)); + + if (member_test_flag(member, MFLAG_SECOND_SCREEN)) { + cJSON_AddItemToObject(data, "secondScreen", cJSON_CreateTrue()); + } + + if (member_test_flag(member, MFLAG_MOD)) { cJSON_AddItemToObject(data, "modChannel", cJSON_CreateString(conference->mod_event_channel)); } + switch_core_get_variables(&variables); + for (hp = variables->headers; hp; hp = hp->next) { + if (!strncasecmp(hp->name, "conf_verto_", 11)) { + char *var = hp->name + 11; + if (var) { + cJSON_AddItemToObject(data, var, cJSON_CreateString(hp->value)); + } + } + } + switch_event_destroy(&variables); + switch_event_channel_broadcast(event_channel, &msg, modname, globals.event_channel_id); if (cookie) { @@ -4144,8 +5058,6 @@ static void find_video_floor(conference_member_t *member, switch_bool_t entering { conference_member_t *imember; conference_obj_t *conference = member->conference; - layout_group_t *lg = NULL; - video_layout_t *vlayout = NULL; if (!entering) { if (member->id == conference->video_floor_holder) { @@ -4196,17 +5108,14 @@ static void find_video_floor(conference_member_t *member, switch_bool_t entering if (conference->last_video_floor_holder == conference->video_floor_holder) { conference->last_video_floor_holder = 0; } - - if (conference->canvas && conference->video_layout_group && (lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group))) { - if ((vlayout = find_best_layout(conference, lg))) { - switch_mutex_lock(conference->member_mutex); - conference->canvas->new_vlayout = vlayout; - switch_mutex_unlock(conference->member_mutex); - } - } - } +static void reset_member_codec_index(conference_member_t *member) +{ + member->video_codec_index = -1; +} + + /* Gain exclusive access and add the member to the list */ static switch_status_t conference_add_member(conference_obj_t *conference, conference_member_t *member) { @@ -4238,24 +5147,39 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe member->score_iir = 0; member->verbose_events = conference->verbose_events; member->video_layer_id = -1; - member->video_codec_index = -1; + switch_queue_create(&member->dtmf_queue, 100, member->pool); + if (conference_test_flag(conference, CFLAG_PERSONAL_CANVAS)) { + video_layout_t *vlayout = NULL; + + switch_mutex_lock(conference->canvas_mutex); + if ((vlayout = get_layout(conference, conference->video_layout_name, conference->video_layout_group))) { + init_canvas(conference, vlayout, &member->canvas); + init_canvas_layers(conference, member->canvas, vlayout); + } + switch_mutex_unlock(conference->canvas_mutex); + } + + if (member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY) { + member_clear_flag_locked(member, MFLAG_CAN_BE_SEEN); + } + conference->members = member; - switch_set_flag_locked(member, MFLAG_INTREE); + member_set_flag_locked(member, MFLAG_INTREE); switch_mutex_unlock(conference->member_mutex); conference_cdr_add(member); - if (!switch_test_flag(member, MFLAG_NOCHANNEL)) { - if (switch_test_flag(member, MFLAG_GHOST)) { + if (!member_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_GHOST)) { conference->count_ghosts++; } else { conference->count++; } - if (switch_test_flag(member, MFLAG_ENDCONF)) { + if (member_test_flag(member, MFLAG_ENDCONF)) { if (conference->end_count++) { conference->endconf_time = 0; } @@ -4268,6 +5192,27 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe check_avatar(member, SWITCH_FALSE); + if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_canvas", SWITCH_FALSE, -1))) { + int id = atoi(var) - 1; + if (id < conference->canvas_count) { + member->canvas_id = id; + } + } + + if ((var = switch_channel_get_variable_dup(member->channel, "video_initial_watching_canvas", SWITCH_FALSE, -1))) { + int id = atoi(var) - 1; + + if (id == 0) { + id = conference->canvas_count; + } + + if (id <= conference->canvas_count && conference->canvases[id]) { + member->watching_canvas_id = id; + } + } + + reset_member_codec_index(member); + if ((var = switch_channel_get_variable_dup(member->channel, "video_mute_png", SWITCH_FALSE, -1))) { member->video_mute_png = switch_core_strdup(member->pool, var); member->video_mute_img = switch_img_read_png(member->video_mute_png, SWITCH_IMG_FMT_I420); @@ -4278,12 +5223,12 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe } if ((var = switch_channel_get_variable(channel, "video_use_dedicated_encoder")) && switch_true(var)) { - switch_set_flag_locked(member, MFLAG_NO_MINIMIZE_ENCODING); + member_set_flag_locked(member, MFLAG_NO_MINIMIZE_ENCODING); } switch_channel_set_variable_printf(channel, "conference_member_id", "%d", member->id); - switch_channel_set_variable_printf(channel, "conference_moderator", "%s", switch_test_flag(member, MFLAG_MOD) ? "true" : "false"); - switch_channel_set_variable_printf(channel, "conference_ghost", "%s", switch_test_flag(member, MFLAG_GHOST) ? "true" : "false"); + switch_channel_set_variable_printf(channel, "conference_moderator", "%s", member_test_flag(member, MFLAG_MOD) ? "true" : "false"); + switch_channel_set_variable_printf(channel, "conference_ghost", "%s", member_test_flag(member, MFLAG_GHOST) ? "true" : "false"); switch_channel_set_variable(channel, "conference_recording", conference->record_filename); switch_channel_set_variable(channel, CONFERENCE_UUID_VARIABLE, conference->uuid_str); @@ -4299,20 +5244,20 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe } - if (switch_test_flag(conference, CFLAG_WAIT_MOD) && switch_test_flag(member, MFLAG_MOD)) { - switch_clear_flag(conference, CFLAG_WAIT_MOD); + if (conference_test_flag(conference, CFLAG_WAIT_MOD) && member_test_flag(member, MFLAG_MOD)) { + conference_clear_flag(conference, CFLAG_WAIT_MOD); } if (conference->count > 1) { - if ((conference->moh_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) || - (switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")))) { + if ((conference->moh_sound && !conference_test_flag(conference, CFLAG_WAIT_MOD)) || + (conference_test_flag(conference, CFLAG_WAIT_MOD) && !switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")))) { /* stop MoH if any */ conference_stop_file(conference, FILE_STOP_ASYNC); } if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ) && !zstr(conference->enter_sound)) { - const char * enter_sound = switch_channel_get_variable(channel, "conference_enter_sound"); - if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) { + const char * enter_sound = switch_channel_get_variable(channel, "conference_enter_sound"); + if (conference_test_flag(conference, CFLAG_ENTER_SOUND) && !member_test_flag(member, MFLAG_SILENT)) { if (!zstr(enter_sound)) { conference_play_file(conference, (char *)enter_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), 0); @@ -4337,10 +5282,10 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if (conference->count >= conference->announce_count && conference->announce_count > 1) { switch_snprintf(msg, sizeof(msg), "There are %d callers", conference->count); conference_member_say(member, msg, CONF_DEFAULT_LEADIN); - } else if (conference->count == 1 && !conference->perpetual_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD)) { + } else if (conference->count == 1 && !conference->perpetual_sound && !conference_test_flag(conference, CFLAG_WAIT_MOD)) { /* as long as its not a bridge_to conference, announce if person is alone */ - if (!switch_test_flag(conference, CFLAG_BRIDGE_TO)) { - if (conference->alone_sound && !switch_test_flag(member, MFLAG_GHOST)) { + if (!conference_test_flag(conference, CFLAG_BRIDGE_TO)) { + if (conference->alone_sound && !member_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); conference_play_file(conference, conference->alone_sound, CONF_DEFAULT_LEADIN, switch_core_session_get_channel(member->session), 0); @@ -4354,7 +5299,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe } if (conference->min && conference->count >= conference->min) { - switch_set_flag(conference, CFLAG_ENFORCE_MIN); + conference_set_flag(conference, CFLAG_ENFORCE_MIN); } if (!switch_channel_test_app_flag_key("conf_silent", channel, CONF_SILENT_REQ) && @@ -4371,7 +5316,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe if ((position = switch_channel_get_variable(channel, "conference_position"))) { if (conference->channels == 2) { - if (switch_test_flag(member, MFLAG_NO_POSITIONAL)) { + if (member_test_flag(member, MFLAG_NO_POSITIONAL)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "%s has positional audio blocked.\n", switch_channel_get_name(channel)); } else { @@ -4381,7 +5326,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "%s position data set\n", switch_channel_get_name(channel)); } - switch_set_flag(member, MFLAG_POSITIONAL); + member_set_flag(member, MFLAG_POSITIONAL); member->al = create_al(member->pool); } } else { @@ -4394,7 +5339,7 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe controls = switch_channel_get_variable(channel, "conference_controls"); if (zstr(controls)) { - if (!switch_test_flag(member, MFLAG_MOD) || !conference->moderator_controls) { + if (!member_test_flag(member, MFLAG_MOD) || !conference->moderator_controls) { controls = conference->caller_controls; } else { controls = conference->moderator_controls; @@ -4418,33 +5363,38 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe switch_mutex_unlock(member->audio_in_mutex); if (conference->la && member->channel && !switch_channel_test_flag(member->channel, CF_VIDEO_ONLY)) { - member->json = cJSON_CreateArray(); - cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%0.4d", member->id)); - cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_number"))); - cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_name"))); - - cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%s@%s", - switch_channel_get_variable(member->channel, "original_read_codec"), - switch_channel_get_variable(member->channel, "original_read_rate") - )); + if (!member_test_flag(member, MFLAG_SECOND_SCREEN)) { + member->json = cJSON_CreateArray(); + cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%0.4d", member->id)); + cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_number"))); + cJSON_AddItemToArray(member->json, cJSON_CreateString(switch_channel_get_variable(member->channel, "caller_id_name"))); + + cJSON_AddItemToArray(member->json, cJSON_CreateStringPrintf("%s@%s", + 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); + + cJSON_AddItemToArray(member->json, cJSON_CreateNull()); + + member_update_status_field(member); + //switch_live_array_add_alias(conference->la, switch_core_session_get_uuid(member->session), "conference"); + } - member->status_field = cJSON_CreateString(""); - cJSON_AddItemToArray(member->json, member->status_field); - - cJSON_AddItemToArray(member->json, cJSON_CreateNull()); - - member_update_status_field(member); - //switch_live_array_add_alias(conference->la, switch_core_session_get_uuid(member->session), "conference"); adv_la(conference, member, SWITCH_TRUE); - switch_live_array_add(conference->la, switch_core_session_get_uuid(member->session), -1, &member->json, SWITCH_FALSE); + if (!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); + } } - if (switch_test_flag(conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(conference, CFLAG_POSITIONAL)) { gen_arc(conference, NULL); } @@ -4458,9 +5408,9 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe find_video_floor(member, SWITCH_TRUE); - if (switch_test_flag(member, MFLAG_JOIN_VID_FLOOR)) { + if (member_test_flag(member, MFLAG_JOIN_VID_FLOOR)) { conference_set_video_floor_holder(conference, member, SWITCH_TRUE); - switch_set_flag(member->conference, CFLAG_VID_FLOOR_LOCK); + conference_set_flag(member->conference, CFLAG_VID_FLOOR_LOCK); if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "conference %s OK video floor %d %s\n", @@ -4479,10 +5429,10 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf uint32_t old_member = 0; if (!member) { - switch_clear_flag(conference, CFLAG_VID_FLOOR_LOCK); + conference_clear_flag(conference, CFLAG_VID_FLOOR_LOCK); } - if ((!force && switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK))) { + if ((!force && conference_test_flag(conference, CFLAG_VID_FLOOR_LOCK))) { return; } @@ -4501,8 +5451,8 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf if (conference->last_video_floor_holder && (imember = conference_member_get(conference, conference->last_video_floor_holder))) { switch_core_session_request_video_refresh(imember->session); - if (switch_test_flag(imember, MFLAG_VIDEO_BRIDGE)) { - switch_set_flag(conference, CFLAG_VID_FLOOR_LOCK); + if (member_test_flag(imember, MFLAG_VIDEO_BRIDGE)) { + conference_set_flag(conference, CFLAG_VID_FLOOR_LOCK); } switch_thread_rwlock_unlock(imember->rwlock); imember = NULL; @@ -4525,8 +5475,9 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf switch_mutex_unlock(conference->member_mutex); } - if (member && conference->canvas && conference->canvas->layout_floor_id > -1) { - attach_video_layer(member, conference->canvas->layout_floor_id); + //VIDFLOOR + if (conference->canvas_count == 1 && member && conference->canvas && conference->canvas->layout_floor_id > -1) { + attach_video_layer(member, conference->canvas, conference->canvas->layout_floor_id); } if (member) { @@ -4564,7 +5515,7 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf } switch_mutex_unlock(conference->member_mutex); - switch_set_flag(conference, CFLAG_FLOOR_CHANGE); + conference_set_flag(conference, CFLAG_FLOOR_CHANGE); if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) { switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT); @@ -4620,7 +5571,7 @@ static void conference_set_floor_holder(conference_obj_t *conference, conference old_member->floor_packets = 0; } - switch_set_flag(conference, CFLAG_FLOOR_CHANGE); + conference_set_flag(conference, CFLAG_FLOOR_CHANGE); switch_mutex_unlock(conference->mutex); if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) { @@ -4762,6 +5713,10 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe } #endif + if (member->canvas) { + destroy_canvas(&member->canvas); + } + member_fnode = member->fnode; member_sh = member->sh; member->fnode = NULL; @@ -4775,13 +5730,13 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe member->avatar_patched = 0; switch_img_free(&member->avatar_png_img); switch_img_free(&member->video_mute_img); - + switch_img_free(&member->pcanvas_img); switch_mutex_lock(conference->mutex); switch_mutex_lock(conference->member_mutex); switch_mutex_lock(member->audio_in_mutex); switch_mutex_lock(member->audio_out_mutex); lock_member(member); - switch_clear_flag(member, MFLAG_INTREE); + member_clear_flag(member, MFLAG_INTREE); if (member->rec) { conference->recording_members--; @@ -4830,7 +5785,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe } if (member->id == member->conference->video_floor_holder) { - switch_clear_flag(member->conference, CFLAG_VID_FLOOR_LOCK); + conference_clear_flag(member->conference, CFLAG_VID_FLOOR_LOCK); if (member->conference->last_video_floor_holder) { member->conference->video_floor_holder = member->conference->last_video_floor_holder; member->conference->last_video_floor_holder = 0; @@ -4838,17 +5793,17 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe member->conference->video_floor_holder = 0; } - if (!switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (!member_test_flag(member, MFLAG_NOCHANNEL)) { switch_channel_t *channel = switch_core_session_get_channel(member->session); - if (switch_test_flag(member, MFLAG_GHOST)) { + if (member_test_flag(member, MFLAG_GHOST)) { conference->count_ghosts--; } else { conference->count--; } - if (switch_test_flag(member, MFLAG_ENDCONF)) { + if (member_test_flag(member, MFLAG_ENDCONF)) { if (!--conference->end_count) { - //switch_set_flag_locked(conference, CFLAG_DESTRUCT); + //conference_set_flag_locked(conference, CFLAG_DESTRUCT); conference->endconf_time = switch_epoch_time_now(NULL); } } @@ -4856,18 +5811,18 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe conference_send_presence(conference); switch_channel_set_variable(channel, "conference_call_key", NULL); - if ((conference->min && switch_test_flag(conference, CFLAG_ENFORCE_MIN) && (conference->count + conference->count_ghosts) < conference->min) - || (switch_test_flag(conference, CFLAG_DYNAMIC) && (conference->count + conference->count_ghosts == 0))) { - switch_set_flag(conference, CFLAG_DESTRUCT); + if ((conference->min && conference_test_flag(conference, CFLAG_ENFORCE_MIN) && (conference->count + conference->count_ghosts) < conference->min) + || (conference_test_flag(conference, CFLAG_DYNAMIC) && (conference->count + conference->count_ghosts == 0))) { + conference_set_flag(conference, CFLAG_DESTRUCT); } else { - if (!switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")) && switch_test_flag(conference, CFLAG_WAIT_MOD)) { + if (!switch_true(switch_channel_get_variable(channel, "conference_permanent_wait_mod_moh")) && conference_test_flag(conference, CFLAG_WAIT_MOD)) { /* Stop MOH if any */ conference_stop_file(conference, FILE_STOP_ASYNC); } - if (!exit_sound && conference->exit_sound && switch_test_flag(conference, CFLAG_EXIT_SOUND)) { + if (!exit_sound && conference->exit_sound && conference_test_flag(conference, CFLAG_EXIT_SOUND) && !member_test_flag(member, MFLAG_SILENT)) { conference_play_file(conference, conference->exit_sound, 0, channel, 0); } - if (conference->count == 1 && conference->alone_sound && !switch_test_flag(conference, CFLAG_WAIT_MOD) && !switch_test_flag(member, MFLAG_GHOST)) { + if (conference->count == 1 && conference->alone_sound && !conference_test_flag(conference, CFLAG_WAIT_MOD) && !member_test_flag(member, MFLAG_GHOST)) { conference_stop_file(conference, FILE_STOP_ASYNC); conference_play_file(conference, conference->alone_sound, 0, channel, 0); } @@ -4902,7 +5857,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe send_rfc_event(conference); send_json_event(conference); - if (switch_test_flag(conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(conference, CFLAG_POSITIONAL)) { gen_arc(conference, NULL); } @@ -4927,10 +5882,27 @@ static void conference_write_video_frame(conference_obj_t *conference, conferenc return; } - if (switch_test_flag(conference, CFLAG_FLOOR_CHANGE)) { - switch_clear_flag(conference, CFLAG_FLOOR_CHANGE); + if (conference_test_flag(conference, CFLAG_FLOOR_CHANGE)) { + conference_clear_flag(conference, CFLAG_FLOOR_CHANGE); } + if (vid_frame->img && conference->canvas) { + switch_image_t *frame_img = NULL, *tmp_img = NULL; + int x,y; + + switch_img_copy(vid_frame->img, &tmp_img); + switch_img_fit(&tmp_img, conference->canvas->width, conference->canvas->height); + frame_img = switch_img_alloc(NULL, SWITCH_IMG_FMT_I420, conference->canvas->width, conference->canvas->height, 1); + reset_image(frame_img, &conference->canvas->bgcolor); + switch_img_find_position(POS_CENTER_MID, frame_img->d_w, frame_img->d_h, tmp_img->d_w, tmp_img->d_h, &x, &y); + switch_img_patch(frame_img, tmp_img, x, y); + tmp_frame.packet = buf; + tmp_frame.data = buf + 12; + tmp_frame.img = frame_img; + switch_img_free(&tmp_img); + } + + switch_mutex_lock(conference->member_mutex); for (imember = conference->members; imember; imember = imember->next) { switch_core_session_t *isession = imember->session; @@ -4945,12 +5917,28 @@ static void conference_write_video_frame(conference_obj_t *conference, conferenc } if (isession && switch_channel_test_flag(imember->channel, CF_VIDEO)) { - if (!switch_test_flag(imember, MFLAG_RECEIVING_VIDEO) && - (switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK) || - !(imember->id == imember->conference->video_floor_holder && imember->conference->last_video_floor_holder))) { + int send_frame = 0; + if (conference->canvas && conference_test_flag(imember->conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) { + if (switch_channel_test_flag(imember->channel, CF_VIDEO) && (conference->members_with_video == 1 || imember != floor_holder)) { + send_frame = 1; + } + } else if (!member_test_flag(imember, MFLAG_RECEIVING_VIDEO) && + (conference_test_flag(conference, CFLAG_VID_FLOOR_LOCK) || + !(imember->id == imember->conference->video_floor_holder && imember->conference->last_video_floor_holder))) { + send_frame = 1; + } + + if (send_frame) { if (vid_frame->img) { - switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0); + if (conference->canvas) { + tmp_frame.packet = buf; + tmp_frame.packetlen = sizeof(buf) - 12; + tmp_frame.data = buf + 12; + switch_core_session_write_video_frame(imember->session, &tmp_frame, SWITCH_IO_FLAG_NONE, 0); + } else { + switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0); + } } else { switch_assert(vid_frame->packetlen <= SWITCH_RTP_MAX_BUF_LEN); tmp_frame = *vid_frame; @@ -4968,6 +5956,8 @@ static void conference_write_video_frame(conference_obj_t *conference, conferenc } switch_mutex_unlock(conference->member_mutex); + switch_img_free(&tmp_frame.img); + if (want_refresh && floor_holder->session) { switch_core_session_request_video_refresh(floor_holder->session); } @@ -4991,10 +5981,21 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi return SWITCH_STATUS_FALSE; } - if (switch_test_flag(member->conference, CFLAG_VIDEO_MUXING)) { + + if (conference_test_flag(member->conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) { + if (member->conference->members_with_video < 3) { + conference_write_video_frame(member->conference, member, frame); + check_video_recording(member->conference, frame); + switch_thread_rwlock_unlock(member->conference->rwlock); + return SWITCH_STATUS_SUCCESS; + } + } + + + if (conference_test_flag(member->conference, CFLAG_VIDEO_MUXING)) { switch_image_t *img_copy = NULL; - if (frame->img && member->video_layer_id > -1 && switch_test_flag(member, MFLAG_CAN_BE_SEEN) && + if (frame->img && (member->video_layer_id > -1 || member->canvas) && member_test_flag(member, MFLAG_CAN_BE_SEEN) && !member->conference->playing_video_file && switch_queue_size(member->video_queue) < member->conference->video_fps.fps) { switch_img_copy(frame->img, &img_copy); switch_queue_push(member->video_queue, img_copy); @@ -5008,7 +6009,7 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi conference_member_t *imember; if (!(rel->flags & RFLAG_CAN_SEND_VIDEO)) continue; - if ((imember = conference_member_get(member->conference, rel->id)) && switch_test_flag(imember, MFLAG_RECEIVING_VIDEO)) { + if ((imember = conference_member_get(member->conference, rel->id)) && member_test_flag(imember, MFLAG_RECEIVING_VIDEO)) { //switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s %d->%d %d\n", name, member->id, imember->id, frame->datalen); switch_core_session_write_video_frame(imember->session, frame, SWITCH_IO_FLAG_NONE, 0); switch_thread_rwlock_unlock(imember->rwlock); @@ -5034,7 +6035,7 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi if (member->id == member->conference->video_floor_holder) { conference_write_video_frame(member->conference, member, frame); check_video_recording(member->conference, frame); - } else if (!switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK) && member->id == member->conference->last_video_floor_holder) { + } else if (!conference_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK) && member->id == member->conference->last_video_floor_holder) { conference_member_t *fmember; if ((fmember = conference_member_get(member->conference, member->conference->video_floor_holder))) { @@ -5100,7 +6101,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create"); switch_event_fire(&event); - if (switch_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) { + if (conference_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) { char *p; if (strchr(conference->name, '@')) { @@ -5122,17 +6123,17 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } - while (globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) { + while (globals.running && !conference_test_flag(conference, CFLAG_DESTRUCT)) { switch_size_t file_sample_len = samples; switch_size_t file_data_len = samples * 2 * conference->channels; - int has_file_data = 0, members_with_video = 0; + int has_file_data = 0, members_with_video = 0, members_with_avatar = 0; uint32_t conf_energy = 0; int nomoh = 0; conference_member_t *floor_holder; /* Sync the conference to a single timing source */ if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) { - switch_set_flag(conference, CFLAG_DESTRUCT); + conference_set_flag(conference, CFLAG_DESTRUCT); break; } @@ -5147,36 +6148,41 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v total++; imember->read = 0; - if (switch_test_flag(imember, MFLAG_RUNNING) && imember->session) { + if (member_test_flag(imember, MFLAG_RUNNING) && imember->session) { switch_channel_t *channel = switch_core_session_get_channel(imember->session); if ((!floor_holder || (imember->score_iir > SCORE_IIR_SPEAKING_MAX && (floor_holder->score_iir < SCORE_IIR_SPEAKING_MIN)))) {// && - //(!switch_test_flag(conference, CFLAG_VID_FLOOR) || switch_channel_test_flag(channel, CF_VIDEO))) { + //(!conference_test_flag(conference, CFLAG_VID_FLOOR) || switch_channel_test_flag(channel, CF_VIDEO))) { floor_holder = imember; } - if (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_VIDEO)) { + if (switch_channel_ready(channel) && switch_channel_test_flag(channel, CF_VIDEO) && imember->video_flow != SWITCH_MEDIA_FLOW_SENDONLY) { members_with_video++; } - if (switch_test_flag(imember, MFLAG_NOMOH)) { + if (imember->avatar_png_img && !switch_channel_test_flag(channel, CF_VIDEO)) { + members_with_avatar++; + } + + if (member_test_flag(imember, MFLAG_NOMOH)) { nomoh++; } } - switch_clear_flag_locked(imember, MFLAG_HAS_AUDIO); + member_clear_flag_locked(imember, MFLAG_HAS_AUDIO); switch_mutex_lock(imember->audio_in_mutex); if (switch_buffer_inuse(imember->audio_buffer) >= bytes && (buf_read = (uint32_t) switch_buffer_read(imember->audio_buffer, imember->frame, bytes))) { imember->read = buf_read; - switch_set_flag_locked(imember, MFLAG_HAS_AUDIO); + member_set_flag_locked(imember, MFLAG_HAS_AUDIO); ready++; } switch_mutex_unlock(imember->audio_in_mutex); } conference->members_with_video = members_with_video; + conference->members_with_avatar = members_with_avatar; if (floor_holder != conference->floor_holder) { conference_set_floor_holder(conference, floor_holder); @@ -5185,7 +6191,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v if (conference->perpetual_sound && !conference->async_fnode) { conference_play_file(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1); } else if (conference->moh_sound && ((nomoh == 0 && conference->count == 1) - || switch_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode && !conference->fnode) { + || conference_test_flag(conference, CFLAG_WAIT_MOD)) && !conference->async_fnode && !conference->fnode) { conference_play_file(conference, conference->moh_sound, CONF_DEFAULT_LEADIN, NULL, 1); } @@ -5203,7 +6209,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } if (is_talking == 0) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Conference has been idle for over %d seconds, terminating\n", conference->terminate_on_silence); - switch_set_flag(conference, CFLAG_DESTRUCT); + conference_set_flag(conference, CFLAG_DESTRUCT); } } @@ -5343,12 +6349,12 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v for (omember = conference->members; omember; omember = omember->next) { conference->member_loop_count++; - if (!(switch_test_flag(omember, MFLAG_RUNNING) && switch_test_flag(omember, MFLAG_HAS_AUDIO))) { + if (!(member_test_flag(omember, MFLAG_RUNNING) && member_test_flag(omember, MFLAG_HAS_AUDIO))) { continue; } if (conference->agc_level) { - if (switch_test_flag(omember, MFLAG_TALKING) && switch_test_flag(omember, MFLAG_CAN_SPEAK)) { + if (member_test_flag(omember, MFLAG_TALKING) && member_test_flag(omember, MFLAG_CAN_SPEAK)) { member_score_sum += omember->score; conference->mux_loop_count++; } @@ -5384,11 +6390,11 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v for (omember = conference->members; omember; omember = omember->next) { switch_size_t ok = 1; - if (!switch_test_flag(omember, MFLAG_RUNNING)) { + if (!member_test_flag(omember, MFLAG_RUNNING)) { continue; } - if (!switch_test_flag(omember, MFLAG_CAN_HEAR)) { + if (!member_test_flag(omember, MFLAG_CAN_HEAR)) { switch_mutex_lock(omember->audio_out_mutex); memset(write_frame, 255, bytes); ok = switch_buffer_write(omember->mux_buffer, write_frame, bytes); @@ -5402,7 +6408,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v z = main_frame[x]; /* bptr[x] represents my own contribution to this audio sample */ - if (switch_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) { + if (member_test_flag(omember, MFLAG_HAS_AUDIO) && x <= omember->read / 2) { z -= (int32_t) bptr[x]; } @@ -5411,7 +6417,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v */ if (conference->relationship_total) { for (imember = conference->members; imember; imember = imember->next) { - if (imember != omember && switch_test_flag(imember, MFLAG_HAS_AUDIO)) { + if (imember != omember && member_test_flag(imember, MFLAG_HAS_AUDIO)) { conference_relationship_t *rel; switch_size_t found = 0; int16_t *rptr = (int16_t *) imember->frame; @@ -5461,7 +6467,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v for (omember = conference->members; omember; omember = omember->next) { switch_size_t ok = 1; - if (!switch_test_flag(omember, MFLAG_RUNNING)) { + if (!member_test_flag(omember, MFLAG_RUNNING)) { continue; } @@ -5505,7 +6511,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v conference->fnode = conference->fnode->next; if (conference->fnode) { - fnode_check_video(conference, conference->fnode); + fnode_check_video(conference->fnode); } @@ -5518,7 +6524,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_epoch_time_now(NULL) - conference->endconf_time > conference->endconf_grace_time) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Conference %s: endconf grace time exceeded (%u)\n", conference->name, conference->endconf_grace_time); - switch_set_flag(conference, CFLAG_DESTRUCT | CFLAG_ENDCONF_FORCED); + conference_set_flag(conference, CFLAG_DESTRUCT | CFLAG_ENDCONF_FORCED); } switch_mutex_unlock(conference->mutex); @@ -5526,7 +6532,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v /* Rinse ... Repeat */ end: - if (switch_test_flag(conference, CFLAG_OUTCALL)) { + if (conference_test_flag(conference, CFLAG_OUTCALL)) { conference->cancel_cause = SWITCH_CAUSE_ORIGINATOR_CANCEL; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_NOTICE, "Ending pending outcall channels for Conference: '%s'\n", conference->name); while(conference->originating) { @@ -5579,13 +6585,13 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v for (imember = conference->members; imember; imember = imember->next) { switch_channel_t *channel; - if (!switch_test_flag(imember, MFLAG_NOCHANNEL)) { + if (!member_test_flag(imember, MFLAG_NOCHANNEL)) { channel = switch_core_session_get_channel(imember->session); if (!switch_false(switch_channel_get_variable(channel, "hangup_after_conference"))) { /* add this little bit to preserve the bridge cause code in case of an early media call that */ /* never answers */ - if (switch_test_flag(conference, CFLAG_ANSWERED)) { + if (conference_test_flag(conference, CFLAG_ANSWERED)) { switch_channel_hangup(channel, SWITCH_CAUSE_NORMAL_CLEARING); } else { /* put actual cause code from outbound channel hangup here */ @@ -5594,7 +6600,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v } } - switch_clear_flag_locked(imember, MFLAG_RUNNING); + member_clear_flag_locked(imember, MFLAG_RUNNING); } switch_mutex_unlock(conference->member_mutex); switch_mutex_unlock(conference->mutex); @@ -5618,21 +6624,24 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v switch_core_timer_destroy(&timer); switch_mutex_lock(globals.hash_mutex); - if (switch_test_flag(conference, CFLAG_INHASH)) { + if (conference_test_flag(conference, CFLAG_INHASH)) { switch_core_hash_delete(globals.conference_hash, conference->name); } switch_mutex_unlock(globals.hash_mutex); - switch_clear_flag(conference, CFLAG_VIDEO_MUXING); - if (conference->video_muxing_thread) { - switch_status_t st = 0; - switch_thread_join(&st, conference->video_muxing_thread); - conference->video_muxing_thread = NULL; + conference_clear_flag(conference, CFLAG_VIDEO_MUXING); + + for (x = 0; x <= conference->canvas_count; x++) { + if (conference->canvases[x] && conference->canvases[x]->video_muxing_thread) { + switch_status_t st = 0; + switch_thread_join(&st, conference->canvases[x]->video_muxing_thread); + conference->canvases[x]->video_muxing_thread = NULL; + } } /* Wait till everybody is out */ - switch_clear_flag_locked(conference, CFLAG_RUNNING); + conference_clear_flag_locked(conference, CFLAG_RUNNING); switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Lock ON\n"); switch_thread_rwlock_wrlock(conference->rwlock); switch_thread_rwlock_unlock(conference->rwlock); @@ -5700,11 +6709,11 @@ static void conference_loop_fn_mute_toggle(conference_member_t *member, caller_c if (member == NULL) return; - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_CAN_SPEAK)) { conf_api_sub_mute(member, NULL, NULL); } else { conf_api_sub_unmute(member, NULL, NULL); - if (!switch_test_flag(member, MFLAG_CAN_HEAR)) { + if (!member_test_flag(member, MFLAG_CAN_HEAR)) { conf_api_sub_undeaf(member, NULL, NULL); } } @@ -5712,16 +6721,16 @@ static void conference_loop_fn_mute_toggle(conference_member_t *member, caller_c static void conference_loop_fn_mute_on(conference_member_t *member, caller_control_action_t *action) { - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_CAN_SPEAK)) { conf_api_sub_mute(member, NULL, NULL); } } static void conference_loop_fn_mute_off(conference_member_t *member, caller_control_action_t *action) { - if (!switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!member_test_flag(member, MFLAG_CAN_SPEAK)) { conf_api_sub_unmute(member, NULL, NULL); - if (!switch_test_flag(member, MFLAG_CAN_HEAR)) { + if (!member_test_flag(member, MFLAG_CAN_HEAR)) { conf_api_sub_undeaf(member, NULL, NULL); } } @@ -5742,7 +6751,7 @@ static void conference_loop_fn_vmute_toggle(conference_member_t *member, caller_ if (member == NULL) return; - if (switch_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (member_test_flag(member, MFLAG_CAN_BE_SEEN)) { conf_api_sub_vmute(member, NULL, NULL); } else { conf_api_sub_unvmute(member, NULL, NULL); @@ -5751,14 +6760,14 @@ static void conference_loop_fn_vmute_toggle(conference_member_t *member, caller_ static void conference_loop_fn_vmute_on(conference_member_t *member, caller_control_action_t *action) { - if (switch_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (member_test_flag(member, MFLAG_CAN_BE_SEEN)) { conf_api_sub_vmute(member, NULL, NULL); } } static void conference_loop_fn_vmute_off(conference_member_t *member, caller_control_action_t *action) { - if (!switch_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (!member_test_flag(member, MFLAG_CAN_BE_SEEN)) { conf_api_sub_unvmute(member, NULL, NULL); } } @@ -5770,15 +6779,15 @@ static void conference_loop_fn_lock_toggle(conference_member_t *member, caller_c if (member == NULL) return; - if (switch_test_flag(member->conference, CFLAG_WAIT_MOD) && !switch_test_flag(member, MFLAG_MOD) ) + if (conference_test_flag(member->conference, CFLAG_WAIT_MOD) && !member_test_flag(member, MFLAG_MOD) ) return; - if (!switch_test_flag(member->conference, CFLAG_LOCKED)) { + if (!conference_test_flag(member->conference, CFLAG_LOCKED)) { if (member->conference->is_locked_sound) { conference_play_file(member->conference, member->conference->is_locked_sound, CONF_DEFAULT_LEADIN, NULL, 0); } - switch_set_flag_locked(member->conference, CFLAG_LOCKED); + conference_set_flag_locked(member->conference, CFLAG_LOCKED); if (test_eflag(member->conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(member->conference, event); @@ -5790,7 +6799,7 @@ static void conference_loop_fn_lock_toggle(conference_member_t *member, caller_c conference_play_file(member->conference, member->conference->is_unlocked_sound, CONF_DEFAULT_LEADIN, NULL, 0); } - switch_clear_flag_locked(member->conference, CFLAG_LOCKED); + conference_clear_flag_locked(member->conference, CFLAG_LOCKED); if (test_eflag(member->conference, EFLAG_UNLOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(member->conference, event); @@ -5806,14 +6815,14 @@ static void conference_loop_fn_deafmute_toggle(conference_member_t *member, call if (member == NULL) return; - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_CAN_SPEAK)) { conf_api_sub_mute(member, NULL, NULL); - if (switch_test_flag(member, MFLAG_CAN_HEAR)) { + if (member_test_flag(member, MFLAG_CAN_HEAR)) { conf_api_sub_deaf(member, NULL, NULL); } } else { conf_api_sub_unmute(member, NULL, NULL); - if (!switch_test_flag(member, MFLAG_CAN_HEAR)) { + if (!member_test_flag(member, MFLAG_CAN_HEAR)) { conf_api_sub_undeaf(member, NULL, NULL); } } @@ -6134,7 +7143,7 @@ static void conference_loop_fn_transfer(conference_member_t *member, caller_cont switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Dialplan", action->expanded_data); switch_event_fire(&event); } - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); if ((mydata = switch_core_session_strdup(member->session, action->expanded_data))) { if ((argc = switch_separate_string(mydata, ' ', argv, (sizeof(argv) / sizeof(argv[0]))))) { @@ -6225,7 +7234,7 @@ static void conference_loop_fn_exec_app(conference_member_t *member, caller_cont static void conference_loop_fn_hangup(conference_member_t *member, caller_control_action_t *action) { - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); } @@ -6288,7 +7297,7 @@ static void check_agc_levels(conference_member_t *member) static void member_check_channels(switch_frame_t *frame, conference_member_t *member, switch_bool_t in) { - if (member->conference->channels != member->read_impl.number_of_channels || switch_test_flag(member, MFLAG_POSITIONAL)) { + if (member->conference->channels != member->read_impl.number_of_channels || member_test_flag(member, MFLAG_POSITIONAL)) { uint32_t rlen; int from, to; @@ -6302,7 +7311,7 @@ static void member_check_channels(switch_frame_t *frame, conference_member_t *me rlen = frame->datalen / 2 / from; - if (in && frame->rate == 48000 && ((from == 1 && to == 2) || (from == 2 && to == 2)) && switch_test_flag(member, MFLAG_POSITIONAL)) { + if (in && frame->rate == 48000 && ((from == 1 && to == 2) || (from == 2 && to == 2)) && member_test_flag(member, MFLAG_POSITIONAL)) { if (from == 2 && to == 2) { switch_mux_channels((int16_t *) frame->data, rlen, 2, 1); frame->datalen /= 2; @@ -6338,7 +7347,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_assert(member != NULL); - switch_clear_flag_locked(member, MFLAG_TALKING); + member_clear_flag_locked(member, MFLAG_TALKING); channel = switch_core_session_get_channel(session); @@ -6351,7 +7360,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v /* As long as we have a valid read, feed that data into an input buffer where the conference thread will take it and mux it with any audio from other channels. */ - while (switch_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) { + while (member_test_flag(member, MFLAG_RUNNING) && switch_channel_ready(channel)) { if (switch_channel_ready(channel) && switch_channel_test_app_flag(channel, CF_APP_TAGGED)) { switch_yield(100000); @@ -6364,17 +7373,17 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_mutex_lock(member->read_mutex); /* end the loop, if appropriate */ - if (!SWITCH_READ_ACCEPTABLE(status) || !switch_test_flag(member, MFLAG_RUNNING)) { + if (!SWITCH_READ_ACCEPTABLE(status) || !member_test_flag(member, MFLAG_RUNNING)) { switch_mutex_unlock(member->read_mutex); break; } - if (switch_channel_test_flag(channel, CF_VIDEO) && !switch_test_flag(member, MFLAG_ACK_VIDEO)) { - switch_set_flag_locked(member, MFLAG_ACK_VIDEO); + if (switch_channel_test_flag(channel, CF_VIDEO) && !member_test_flag(member, MFLAG_ACK_VIDEO)) { + member_set_flag_locked(member, MFLAG_ACK_VIDEO); check_avatar(member, SWITCH_FALSE); switch_core_session_video_reinit(member->session); conference_set_video_floor_holder(member->conference, member, SWITCH_FALSE); - } else if (switch_test_flag(member, MFLAG_ACK_VIDEO) && !switch_channel_test_flag(channel, CF_VIDEO)) { + } else if (member_test_flag(member, MFLAG_ACK_VIDEO) && !switch_channel_test_flag(channel, CF_VIDEO)) { check_avatar(member, SWITCH_FALSE); } @@ -6384,7 +7393,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v switch_channel_dequeue_dtmf_string(channel, dtmf, sizeof(dtmf)); - if (switch_test_flag(member, MFLAG_DIST_DTMF)) { + if (member_test_flag(member, MFLAG_DIST_DTMF)) { conference_send_all_dtmf(member, member->conference, dtmf); } else if (member->dmachine) { char *p; @@ -6417,10 +7426,10 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v if (hangunder_hits) { hangunder_hits--; } - if (switch_test_flag(member, MFLAG_TALKING)) { + if (member_test_flag(member, MFLAG_TALKING)) { if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; - switch_clear_flag_locked(member, MFLAG_TALKING); + member_clear_flag_locked(member, MFLAG_TALKING); member_update_status_field(member); check_agc_levels(member); clear_avg(member); @@ -6453,7 +7462,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v /* if the member can speak, compute the audio energy level and */ /* generate events when the level crosses the threshold */ - if ((switch_test_flag(member, MFLAG_CAN_SPEAK) || switch_test_flag(member, MFLAG_MUTE_DETECT))) { + if ((member_test_flag(member, MFLAG_CAN_SPEAK) || member_test_flag(member, MFLAG_MUTE_DETECT))) { uint32_t energy = 0, i = 0, samples = 0, j = 0; int16_t *data; int agc_period = (member->read_impl.actual_samples_per_second / member->read_impl.samples_per_packet) / 4; @@ -6484,7 +7493,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v } if (member->conference->agc_level && member->score && - switch_test_flag(member, MFLAG_CAN_SPEAK) && + member_test_flag(member, MFLAG_CAN_SPEAK) && noise_gate_check(member) ) { int last_shift = abs((int)(member->last_score - member->score)); @@ -6543,22 +7552,22 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v hangover_hits = hangunder_hits = 0; member->last_talking = switch_epoch_time_now(NULL); - if (!switch_test_flag(member, MFLAG_TALKING)) { - switch_set_flag_locked(member, MFLAG_TALKING); + if (!member_test_flag(member, MFLAG_TALKING)) { + member_set_flag_locked(member, MFLAG_TALKING); member_update_status_field(member); member->floor_packets = 0; - if (test_eflag(member->conference, EFLAG_START_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK) && + if (test_eflag(member->conference, EFLAG_START_TALKING) && member_test_flag(member, MFLAG_CAN_SPEAK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_member_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-talking"); switch_event_fire(&event); } - if (switch_test_flag(member, MFLAG_MUTE_DETECT) && !switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_MUTE_DETECT) && !member_test_flag(member, MFLAG_CAN_SPEAK)) { if (!zstr(member->conference->mute_detect_sound)) { - switch_set_flag(member, MFLAG_INDICATE_MUTE_DETECT); + member_set_flag(member, MFLAG_INDICATE_MUTE_DETECT); } if (test_eflag(member->conference, EFLAG_MUTE_DETECT) && @@ -6579,11 +7588,11 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v member->nt_tally++; } - if (switch_test_flag(member, MFLAG_TALKING) && switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_TALKING) && member_test_flag(member, MFLAG_CAN_SPEAK)) { switch_event_t *event; if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; - switch_clear_flag_locked(member, MFLAG_TALKING); + member_clear_flag_locked(member, MFLAG_TALKING); member_update_status_field(member); check_agc_levels(member); clear_avg(member); @@ -6626,8 +7635,8 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v } /* skip frames that are not actual media or when we are muted or silent */ - if ((switch_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || switch_test_flag(member->conference, CFLAG_AUDIO_ALWAYS)) - && switch_test_flag(member, MFLAG_CAN_SPEAK) && !switch_test_flag(member->conference, CFLAG_WAIT_MOD) + if ((member_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || conference_test_flag(member->conference, CFLAG_AUDIO_ALWAYS)) + && member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_test_flag(member->conference, CFLAG_WAIT_MOD) && (member->conference->count > 1 || (member->conference->record_count && member->conference->count >= member->conference->min_recording_participants))) { switch_audio_resampler_t *read_resampler = member->read_resampler; void *data; @@ -6692,7 +7701,7 @@ static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, v end: - switch_clear_flag_locked(member, MFLAG_ITHREAD); + member_clear_flag_locked(member, MFLAG_ITHREAD); return NULL; } @@ -6796,9 +7805,9 @@ static void launch_conference_loop_input(conference_member_t *member, switch_mem switch_threadattr_create(&thd_attr, pool); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_set_flag_locked(member, MFLAG_ITHREAD); + member_set_flag_locked(member, MFLAG_ITHREAD); if (switch_thread_create(&member->input_thread, thd_attr, conference_loop_input, member, pool) != SWITCH_STATUS_SUCCESS) { - switch_clear_flag_locked(member, MFLAG_ITHREAD); + member_clear_flag_locked(member, MFLAG_ITHREAD); } } @@ -6878,7 +7887,7 @@ static void conference_loop_output(conference_member_t *member) switch_channel_set_private(channel, "_conference_autocall_list_", NULL); - switch_set_flag(member->conference, CFLAG_OUTCALL); + conference_set_flag(member->conference, CFLAG_OUTCALL); if (toval) { to = atoi(toval); @@ -6934,20 +7943,20 @@ static void conference_loop_output(conference_member_t *member) conference_member_play_file(member, "tone_stream://%(500,0,640)", 0, SWITCH_TRUE); } - if (!switch_test_flag(member->conference, CFLAG_ANSWERED)) { + if (!conference_test_flag(member->conference, CFLAG_ANSWERED)) { switch_channel_answer(channel); } sanity = 2000; - while(!switch_test_flag(member, MFLAG_ITHREAD) && sanity > 0) { + while(!member_test_flag(member, MFLAG_ITHREAD) && sanity > 0) { switch_cond_next(); sanity--; } /* Fair WARNING, If you expect the caller to hear anything or for digit handling to be processed, */ /* you better not block this thread loop for more than the duration of member->conference->timer_name! */ - while (!member->loop_loop && switch_test_flag(member, MFLAG_RUNNING) && switch_test_flag(member, MFLAG_ITHREAD) + while (!member->loop_loop && member_test_flag(member, MFLAG_RUNNING) && member_test_flag(member, MFLAG_ITHREAD) && switch_channel_ready(channel)) { switch_event_t *event; int use_timer = 0; @@ -6988,13 +7997,13 @@ static void conference_loop_output(conference_member_t *member) if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_OUTBOUND) { /* test to see if outbound channel has answered */ - if (switch_channel_test_flag(channel, CF_ANSWERED) && !switch_test_flag(member->conference, CFLAG_ANSWERED)) { + if (switch_channel_test_flag(channel, CF_ANSWERED) && !conference_test_flag(member->conference, CFLAG_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "Outbound conference channel answered, setting CFLAG_ANSWERED\n"); - switch_set_flag(member->conference, CFLAG_ANSWERED); + conference_set_flag(member->conference, CFLAG_ANSWERED); } } else { - if (switch_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) { + if (conference_test_flag(member->conference, CFLAG_ANSWERED) && !switch_channel_test_flag(channel, CF_ANSWERED)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(member->session), SWITCH_LOG_DEBUG, "CLFAG_ANSWERED set, answering inbound channel\n"); switch_channel_answer(channel); } @@ -7009,16 +8018,16 @@ static void conference_loop_output(conference_member_t *member) if (mux_used < bytes) { if (++low_count >= 5) { /* partial frame sitting around this long is useless and builds delay */ - switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } } else if (mux_used > flush_len) { /* getting behind, clear the buffer */ - switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } } if (switch_channel_test_app_flag(channel, CF_APP_TAGGED)) { - switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); } else if (mux_used >= bytes) { /* Flush the output buffer and write all the data (presumably muxed) back to the channel */ switch_mutex_lock(member->audio_out_mutex); @@ -7030,7 +8039,7 @@ static void conference_loop_output(conference_member_t *member) if (write_frame.datalen) { write_frame.samples = write_frame.datalen / 2 / member->conference->channels; - if( !switch_test_flag(member, MFLAG_CAN_HEAR)) { + if( !member_test_flag(member, MFLAG_CAN_HEAR)) { memset(write_frame.data, 255, write_frame.datalen); } else if (member->volume_out_level) { /* Check for output volume adjustments */ switch_change_sln_volume(write_frame.data, write_frame.samples * member->conference->channels, member->volume_out_level); @@ -7054,19 +8063,19 @@ static void conference_loop_output(conference_member_t *member) switch_mutex_unlock(member->audio_out_mutex); } - if (switch_test_flag(member, MFLAG_FLUSH_BUFFER)) { + if (member_test_flag(member, MFLAG_FLUSH_BUFFER)) { if (switch_buffer_inuse(member->mux_buffer)) { switch_mutex_lock(member->audio_out_mutex); switch_buffer_zero(member->mux_buffer); switch_mutex_unlock(member->audio_out_mutex); } - switch_clear_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER); } switch_mutex_unlock(member->write_mutex); - if (switch_test_flag(member, MFLAG_INDICATE_MUTE)) { + if (member_test_flag(member, MFLAG_INDICATE_MUTE)) { if (!zstr(member->conference->muted_sound)) { conference_member_play_file(member, member->conference->muted_sound, 0, SWITCH_TRUE); } else { @@ -7075,10 +8084,10 @@ static void conference_loop_output(conference_member_t *member) switch_snprintf(msg, sizeof(msg), "Muted"); conference_member_say(member, msg, 0); } - switch_clear_flag(member, MFLAG_INDICATE_MUTE); + member_clear_flag(member, MFLAG_INDICATE_MUTE); } - if (switch_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) { + if (member_test_flag(member, MFLAG_INDICATE_MUTE_DETECT)) { if (!zstr(member->conference->mute_detect_sound)) { conference_member_play_file(member, member->conference->mute_detect_sound, 0, SWITCH_TRUE); } else { @@ -7087,10 +8096,10 @@ static void conference_loop_output(conference_member_t *member) switch_snprintf(msg, sizeof(msg), "Currently Muted"); conference_member_say(member, msg, 0); } - switch_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT); + member_clear_flag(member, MFLAG_INDICATE_MUTE_DETECT); } - if (switch_test_flag(member, MFLAG_INDICATE_UNMUTE)) { + if (member_test_flag(member, MFLAG_INDICATE_UNMUTE)) { if (!zstr(member->conference->unmuted_sound)) { conference_member_play_file(member, member->conference->unmuted_sound, 0, SWITCH_TRUE); } else { @@ -7099,14 +8108,14 @@ static void conference_loop_output(conference_member_t *member) switch_snprintf(msg, sizeof(msg), "Un-Muted"); conference_member_say(member, msg, 0); } - switch_clear_flag(member, MFLAG_INDICATE_UNMUTE); + member_clear_flag(member, MFLAG_INDICATE_UNMUTE); } if (switch_core_session_private_event_count(member->session)) { switch_channel_set_app_flag(channel, CF_APP_TAGGED); switch_ivr_parse_all_events(member->session); switch_channel_clear_app_flag(channel, CF_APP_TAGGED); - switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); switch_core_session_set_read_codec(member->session, &member->read_codec); } else { switch_ivr_parse_all_messages(member->session); @@ -7123,7 +8132,7 @@ static void conference_loop_output(conference_member_t *member) end: if (!member->loop_loop) { - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); /* Wait for the input thread to end */ if (member->input_thread) { @@ -7182,7 +8191,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th member = &smember; - member->flags = MFLAG_CAN_HEAR | MFLAG_NOCHANNEL | MFLAG_RUNNING; + member->flags[MFLAG_CAN_HEAR] = member->flags[MFLAG_NOCHANNEL] = member->flags[MFLAG_RUNNING] = 1; member->conference = conference; member->native_rate = conference->rate; @@ -7227,7 +8236,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th flags = SWITCH_FILE_FLAG_WRITE | SWITCH_FILE_DATA_SHORT; - if (conference->members_with_video && switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { + if (conference->members_with_video && conference_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { flags |= SWITCH_FILE_FLAG_VIDEO; if (conference->canvas) { char *orig_path = rec->path; @@ -7295,26 +8304,26 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th goto end; } - while (switch_test_flag(member, MFLAG_RUNNING) && switch_test_flag(conference, CFLAG_RUNNING) && (conference->count + conference->count_ghosts)) { + while (member_test_flag(member, MFLAG_RUNNING) && conference_test_flag(conference, CFLAG_RUNNING) && (conference->count + conference->count_ghosts)) { len = 0; mux_used = (uint32_t) switch_buffer_inuse(member->mux_buffer); - if (switch_test_flag(member, MFLAG_FLUSH_BUFFER)) { + if (member_test_flag(member, MFLAG_FLUSH_BUFFER)) { if (mux_used) { switch_mutex_lock(member->audio_out_mutex); switch_buffer_zero(member->mux_buffer); switch_mutex_unlock(member->audio_out_mutex); mux_used = 0; } - switch_clear_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_clear_flag_locked(member, MFLAG_FLUSH_BUFFER); } again: if (switch_test_flag((&member->rec->fh), SWITCH_FILE_PAUSE)) { - switch_set_flag_locked(member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(member, MFLAG_FLUSH_BUFFER); goto loop; } @@ -7340,10 +8349,10 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th len = (switch_size_t) samples; } - if (!switch_test_flag(member, MFLAG_PAUSE_RECORDING)) { + if (!member_test_flag(member, MFLAG_PAUSE_RECORDING)) { if (!len || switch_core_file_write(&member->rec->fh, data_buf, &len) != SWITCH_STATUS_SUCCESS) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Write Failed\n"); - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); } } @@ -7377,7 +8386,7 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th switch_buffer_destroy(&member->audio_buffer); switch_buffer_destroy(&member->mux_buffer); - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_clear_flag_locked(member, MFLAG_RUNNING); if (switch_test_flag((&member->rec->fh), SWITCH_FILE_OPEN)) { switch_mutex_lock(conference->mutex); switch_mutex_unlock(conference->mutex); @@ -7521,31 +8530,33 @@ static void conference_send_all_dtmf(conference_member_t *member, conference_obj static void canvas_del_fnode_layer(conference_obj_t *conference, conference_file_node_t *fnode) { - - switch_mutex_lock(conference->canvas->mutex); + mcu_canvas_t *canvas = conference->canvases[fnode->canvas_id]; + + switch_mutex_lock(canvas->mutex); if (fnode->layer_id > -1) { - mcu_layer_t *xlayer = &conference->canvas->layers[fnode->layer_id]; + mcu_layer_t *xlayer = &canvas->layers[fnode->layer_id]; fnode->layer_id = -1; + fnode->canvas_id = -1; xlayer->fnode = NULL; - reset_layer(conference->canvas, xlayer); + reset_layer(xlayer); } - switch_mutex_unlock(conference->canvas->mutex); + switch_mutex_unlock(canvas->mutex); } -static void canvas_set_fnode_layer(conference_obj_t *conference, conference_file_node_t *fnode, int idx) +static void canvas_set_fnode_layer(mcu_canvas_t *canvas, conference_file_node_t *fnode, int idx) { mcu_layer_t *layer = NULL; mcu_layer_t *xlayer = NULL; - switch_mutex_lock(conference->canvas->mutex); + switch_mutex_lock(canvas->mutex); if (idx == -1) { int i; - if (conference->canvas->layout_floor_id > -1) { - idx = conference->canvas->layout_floor_id; - xlayer = &conference->canvas->layers[idx]; + if (canvas->layout_floor_id > -1) { + idx = canvas->layout_floor_id; + xlayer = &canvas->layers[idx]; if (xlayer->fnode) { idx = -1; @@ -7553,8 +8564,8 @@ static void canvas_set_fnode_layer(conference_obj_t *conference, conference_file } if (idx < 0) { - for (i = 0; i < conference->canvas->total_layers; i++) { - xlayer = &conference->canvas->layers[i]; + for (i = 0; i < canvas->total_layers; i++) { + xlayer = &canvas->layers[i]; if (xlayer->fnode || xlayer->geometry.res_id || xlayer->member_id) { continue; @@ -7566,23 +8577,26 @@ static void canvas_set_fnode_layer(conference_obj_t *conference, conference_file } } - if (idx < 0) return; + if (idx < 0) goto end; - layer = &conference->canvas->layers[idx]; + layer = &canvas->layers[idx]; layer->fnode = fnode; fnode->layer_id = idx; + fnode->canvas_id = canvas->canvas_id; if (layer->member_id > -1) { conference_member_t *member; - if ((member = conference_member_get(conference, layer->member_id))) { + if ((member = conference_member_get(canvas->conference, layer->member_id))) { detach_video_layer(member); switch_thread_rwlock_unlock(member->rwlock); } } - switch_mutex_unlock(conference->canvas->mutex); + end: + + switch_mutex_unlock(canvas->mutex); } /* Play a file in the conference room */ @@ -7670,6 +8684,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char * goto done; } + fnode->conference = conference; fnode->layer_id = -1; fnode->type = NODE_TYPE_FILE; fnode->leadin = leadin; @@ -7683,7 +8698,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char * flags = SWITCH_FILE_FLAG_READ | SWITCH_FILE_DATA_SHORT; - if (conference->members_with_video && switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { + if (conference->members_with_video && conference_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { flags |= SWITCH_FILE_FLAG_VIDEO; } @@ -7739,7 +8754,7 @@ static switch_status_t conference_play_file(conference_obj_t *conference, char * fnode->file = switch_core_strdup(fnode->pool, file); if (!conference->fnode || (async && !conference->async_fnode)) { - fnode_check_video(conference, fnode); + fnode_check_video(fnode); } /* Queue the node */ @@ -7788,7 +8803,7 @@ static switch_status_t conference_member_play_file(conference_member_t *member, int channels = member->conference->channels; int bad_params = 0; - if (member == NULL || file == NULL || switch_test_flag(member, MFLAG_KICKED)) + if (member == NULL || file == NULL || member_test_flag(member, MFLAG_KICKED)) return status; if ((expanded = switch_channel_expand_variables(switch_core_session_get_channel(member->session), file)) != file) { @@ -7827,6 +8842,7 @@ static switch_status_t conference_member_play_file(conference_member_t *member, goto done; } + fnode->conference = member->conference; fnode->layer_id = -1; fnode->type = NODE_TYPE_FILE; fnode->leadin = leadin; @@ -7923,6 +8939,8 @@ static switch_status_t conference_member_say(conference_member_t *member, char * return SWITCH_STATUS_MEMERR; } + fnode->conference = conference; + fnode->layer_id = -1; if (*text == '{') { @@ -8065,6 +9083,7 @@ static switch_status_t conference_say(conference_obj_t *conference, const char * return SWITCH_STATUS_MEMERR; } + fnode->conference = conference; fnode->layer_id = -1; if (*text == '{') { @@ -8167,7 +9186,7 @@ static void chat_message_broadcast(conference_obj_t *conference, switch_event_t switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (member->session && !switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member->session && !member_test_flag(member, MFLAG_NOCHANNEL)) { const char *presence_id = switch_channel_get_variable(member->channel, "presence_id"); const char *chat_proto = switch_channel_get_variable(member->channel, "chat_proto"); switch_event_t *reply = NULL; @@ -8203,8 +9222,8 @@ static void conference_member_itterator(conference_obj_t *conference, switch_str switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (!(non_mod && switch_test_flag(member, MFLAG_MOD))) { - if (member->session && !switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (!(non_mod && member_test_flag(member, MFLAG_MOD))) { + if (member->session && !member_test_flag(member, MFLAG_NOCHANNEL)) { pfncallback(member, stream, data); } } else { @@ -8251,7 +9270,7 @@ static void conference_list_pretty(conference_obj_t *conference, switch_stream_h switch_channel_t *channel; switch_caller_profile_t *profile; - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_NOCHANNEL)) { continue; } channel = switch_core_session_get_channel(member->session); @@ -8280,7 +9299,7 @@ static void conference_list(conference_obj_t *conference, switch_stream_handle_t char *name; uint32_t count = 0; - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_NOCHANNEL)) { continue; } @@ -8292,17 +9311,17 @@ static void conference_list(conference_obj_t *conference, switch_stream_handle_t stream->write_function(stream, "%u%s%s%s%s%s%s%s%s%s", member->id, delim, name, delim, uuid, delim, profile->caller_id_name, delim, profile->caller_id_number, delim); - if (switch_test_flag(member, MFLAG_CAN_HEAR)) { + if (member_test_flag(member, MFLAG_CAN_HEAR)) { stream->write_function(stream, "hear"); count++; } - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_CAN_SPEAK)) { stream->write_function(stream, "%s%s", count ? "|" : "", "speak"); count++; } - if (switch_test_flag(member, MFLAG_TALKING)) { + if (member_test_flag(member, MFLAG_TALKING)) { stream->write_function(stream, "%s%s", count ? "|" : "", "talking"); count++; } @@ -8322,12 +9341,12 @@ static void conference_list(conference_obj_t *conference, switch_stream_handle_t count++; } - if (switch_test_flag(member, MFLAG_MOD)) { + if (member_test_flag(member, MFLAG_MOD)) { stream->write_function(stream, "%s%s", count ? "|" : "", "moderator"); count++; } - if (switch_test_flag(member, MFLAG_GHOST)) { + if (member_test_flag(member, MFLAG_GHOST)) { stream->write_function(stream, "%s%s", count ? "|" : "", "ghost"); count++; } @@ -8403,15 +9422,15 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str if (member == NULL) return SWITCH_STATUS_GENERR; - switch_clear_flag_locked(member, MFLAG_CAN_SPEAK); - switch_clear_flag_locked(member, MFLAG_TALKING); + member_clear_flag_locked(member, MFLAG_CAN_SPEAK); + member_clear_flag_locked(member, MFLAG_TALKING); - if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { + if (member->session && !member_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_TRUE); } if (!(data) || !strstr((char *) data, "quiet")) { - switch_set_flag(member, MFLAG_INDICATE_MUTE); + member_set_flag(member, MFLAG_INDICATE_MUTE); } member->score_iir = 0; @@ -8426,7 +9445,7 @@ static switch_status_t conf_api_sub_mute(conference_member_t *member, switch_str switch_event_fire(&event); } - if (switch_test_flag(member->conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(member->conference, CFLAG_POSITIONAL)) { gen_arc(member->conference, NULL); } @@ -8442,7 +9461,7 @@ static switch_status_t conf_api_sub_tmute(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; - if (switch_test_flag(member, MFLAG_CAN_SPEAK)) { + if (member_test_flag(member, MFLAG_CAN_SPEAK)) { return conf_api_sub_mute(member, stream, data); } @@ -8457,14 +9476,14 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s if (member == NULL) return SWITCH_STATUS_GENERR; - switch_set_flag_locked(member, MFLAG_CAN_SPEAK); + member_set_flag_locked(member, MFLAG_CAN_SPEAK); - if (member->session && !switch_test_flag(member, MFLAG_MUTE_DETECT)) { + if (member->session && !member_test_flag(member, MFLAG_MUTE_DETECT)) { switch_core_media_hard_mute(member->session, SWITCH_FALSE); } if (!(data) || !strstr((char *) data, "quiet")) { - switch_set_flag(member, MFLAG_INDICATE_UNMUTE); + member_set_flag(member, MFLAG_INDICATE_UNMUTE); } if (stream != NULL) { @@ -8478,7 +9497,7 @@ static switch_status_t conf_api_sub_unmute(conference_member_t *member, switch_s switch_event_fire(&event); } - if (switch_test_flag(member->conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(member->conference, CFLAG_POSITIONAL)) { gen_arc(member->conference, NULL); } @@ -8494,6 +9513,10 @@ static switch_status_t conf_api_sub_vmute_snap(conference_member_t *member, swit if (member == NULL) return SWITCH_STATUS_GENERR; + if (member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY) { + return SWITCH_STATUS_SUCCESS; + } + if (!member->conference->canvas) { stream->write_function(stream, "Conference is not in mixing mode\n"); return SWITCH_STATUS_SUCCESS; @@ -8519,7 +9542,11 @@ static switch_status_t conf_api_sub_vmute(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; - switch_clear_flag_locked(member, MFLAG_CAN_BE_SEEN); + if (member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY) { + return SWITCH_STATUS_SUCCESS; + } + + member_clear_flag_locked(member, MFLAG_CAN_BE_SEEN); reset_video_bitrate_counters(member); if (member->channel) { @@ -8529,7 +9556,7 @@ static switch_status_t conf_api_sub_vmute(conference_member_t *member, switch_st } if (!(data) || !strstr((char *) data, "quiet")) { - switch_set_flag(member, MFLAG_INDICATE_MUTE); + member_set_flag(member, MFLAG_INDICATE_MUTE); } if (stream != NULL) { @@ -8555,7 +9582,7 @@ static switch_status_t conf_api_sub_tvmute(conference_member_t *member, switch_s if (member == NULL) return SWITCH_STATUS_GENERR; - if (switch_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (member_test_flag(member, MFLAG_CAN_BE_SEEN)) { return conf_api_sub_vmute(member, stream, data); } @@ -8570,15 +9597,19 @@ static switch_status_t conf_api_sub_unvmute(conference_member_t *member, switch_ if (member == NULL) return SWITCH_STATUS_GENERR; + + if (member->video_flow == SWITCH_MEDIA_FLOW_SENDONLY) { + return SWITCH_STATUS_SUCCESS; + } if (member->conference->canvas) { switch_mutex_lock(member->conference->canvas->mutex); layer = &member->conference->canvas->layers[member->video_layer_id]; - clear_layer(member->conference->canvas, layer); + clear_layer(layer); switch_mutex_unlock(member->conference->canvas->mutex); } - switch_set_flag_locked(member, MFLAG_CAN_BE_SEEN); + member_set_flag_locked(member, MFLAG_CAN_BE_SEEN); reset_video_bitrate_counters(member); if (member->channel) { @@ -8587,7 +9618,7 @@ static switch_status_t conf_api_sub_unvmute(conference_member_t *member, switch_ } if (!(data) || !strstr((char *) data, "quiet")) { - switch_set_flag(member, MFLAG_INDICATE_UNMUTE); + member_set_flag(member, MFLAG_INDICATE_UNMUTE); } if (stream != NULL) { @@ -8614,7 +9645,7 @@ static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_str if (member == NULL) return SWITCH_STATUS_GENERR; - switch_clear_flag_locked(member, MFLAG_CAN_HEAR); + member_clear_flag_locked(member, MFLAG_CAN_HEAR); if (stream != NULL) { stream->write_function(stream, "OK deaf %u\n", member->id); } @@ -8624,7 +9655,7 @@ static switch_status_t conf_api_sub_deaf(conference_member_t *member, switch_str switch_event_fire(&event); } - if (switch_test_flag(member->conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(member->conference, CFLAG_POSITIONAL)) { gen_arc(member->conference, NULL); } @@ -8638,7 +9669,7 @@ static switch_status_t conf_api_sub_undeaf(conference_member_t *member, switch_s if (member == NULL) return SWITCH_STATUS_GENERR; - switch_set_flag_locked(member, MFLAG_CAN_HEAR); + member_set_flag_locked(member, MFLAG_CAN_HEAR); if (stream != NULL) { stream->write_function(stream, "OK undeaf %u\n", member->id); } @@ -8648,7 +9679,7 @@ static switch_status_t conf_api_sub_undeaf(conference_member_t *member, switch_s switch_event_fire(&event); } - if (switch_test_flag(member->conference, CFLAG_POSITIONAL)) { + if (conference_test_flag(member->conference, CFLAG_POSITIONAL)) { gen_arc(member->conference, NULL); } @@ -8663,7 +9694,7 @@ static switch_status_t conf_api_sub_hup(conference_member_t *member, switch_stre return SWITCH_STATUS_GENERR; } - switch_clear_flag(member, MFLAG_RUNNING); + member_clear_flag(member, MFLAG_RUNNING); if (member->conference && test_eflag(member->conference, EFLAG_HUP_MEMBER)) { if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { @@ -8684,8 +9715,8 @@ static switch_status_t conf_api_sub_kick(conference_member_t *member, switch_str return SWITCH_STATUS_GENERR; } - switch_clear_flag(member, MFLAG_RUNNING); - switch_set_flag_locked(member, MFLAG_KICKED); + member_clear_flag(member, MFLAG_RUNNING); + member_set_flag_locked(member, MFLAG_KICKED); switch_core_session_kill_channel(member->session, SWITCH_SIG_BREAK); if (data && member->session) { @@ -8750,6 +9781,196 @@ static switch_status_t conf_api_sub_dtmf(conference_member_t *member, switch_str return SWITCH_STATUS_SUCCESS; } +static int get_canvas_id(conference_member_t *member, const char *val, switch_bool_t watching) +{ + int index = -1; + int cur; + + if (watching) { + cur = member->watching_canvas_id; + } else { + cur = member->canvas_id; + } + + if (!val) { + return -1; + } + + if (switch_is_number(val)) { + index = atoi(val) - 1; + + if (index < 0) { + index = 0; + } + } else { + index = cur; + + if (!strcasecmp(val, "next")) { + index++; + } else if (!strcasecmp(val, "prev")) { + index--; + } + } + + if (watching) { + if (index > member->conference->canvas_count || !member->conference->canvases[index]) { + index = 0; + } else if (index < 0) { + index = member->conference->canvas_count; + } + } else { + if (index >= member->conference->canvas_count || !member->conference->canvases[index]) { + index = 0; + } else if (index < 0) { + index = member->conference->canvas_count; + } + } + + if (index > MAX_CANVASES || index < 0) { + return -1; + } + + if (member->conference->canvas_count > 1) { + if (index > member->conference->canvas_count) { + return -1; + } + } else { + if (index >= member->conference->canvas_count) { + return -1; + } + } + + return index; +} + +static switch_status_t conf_api_sub_watching_canvas(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + int index; + char *val = (char *) data; + + if (member->conference->canvas_count == 1) { + stream->write_function(stream, "-ERR Only 1 Canvas\n"); + return SWITCH_STATUS_SUCCESS; + } + + index = get_canvas_id(member, val, SWITCH_TRUE); + + if (index < 0) { + stream->write_function(stream, "-ERR Invalid DATA\n"); + return SWITCH_STATUS_SUCCESS; + } + + member->watching_canvas_id = index; + reset_member_codec_index(member); + switch_core_session_request_video_refresh(member->session); + switch_core_media_gen_key_frame(member->session); + member->conference->canvases[index]->send_keyframe = 10; + member->conference->canvases[index]->refresh = 1; + stream->write_function(stream, "+OK watching canvas %d\n", index + 1); + + return SWITCH_STATUS_SUCCESS; +} + +static switch_status_t conf_api_sub_canvas(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + int index; + char *val = (char *) data; + mcu_canvas_t *canvas = NULL; + + if (member->conference->canvas_count == 1) { + stream->write_function(stream, "-ERR Only 1 Canvas\n"); + return SWITCH_STATUS_SUCCESS; + } + + switch_mutex_lock(member->conference->canvas_mutex); + + index = get_canvas_id(member, val, SWITCH_FALSE); + + if (index < 0) { + stream->write_function(stream, "-ERR Invalid DATA\n"); + switch_mutex_unlock(member->conference->canvas_mutex); + return SWITCH_STATUS_SUCCESS; + } + + detach_video_layer(member); + member->canvas_id = index; + + canvas = member->conference->canvases[member->canvas_id]; + attach_video_layer(member, canvas, index); + reset_member_codec_index(member); + switch_mutex_unlock(member->conference->canvas_mutex); + + switch_core_session_request_video_refresh(member->session); + switch_core_media_gen_key_frame(member->session); + member->conference->canvases[index]->send_keyframe = 10; + member->conference->canvases[index]->refresh = 1; + stream->write_function(stream, "+OK canvas %d\n", member->canvas_id + 1); + + return SWITCH_STATUS_SUCCESS; +} + + + +static switch_status_t conf_api_sub_layer(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + int index = -1; + mcu_canvas_t *canvas = NULL; + char *val = (char *) data; + + if (!val) { + stream->write_function(stream, "-ERR Invalid DATA\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (member->canvas_id < 0) { + stream->write_function(stream, "-ERR Invalid Canvas\n"); + return SWITCH_STATUS_FALSE; + } + + + switch_mutex_lock(member->conference->canvas_mutex); + + if (switch_is_number(val)) { + index = atoi(val) - 1; + + if (index < 0) { + index = 0; + } + } else { + index = member->video_layer_id; + + if (index < 0) index = 0; + + if (!strcasecmp(val, "next")) { + index++; + } else if (!strcasecmp(val, "prev")) { + index--; + } + } + + canvas = member->conference->canvases[member->canvas_id]; + + if (index >= canvas->total_layers) { + index = 0; + } + + if (index < 0) { + index = canvas->total_layers - 1; + } + + attach_video_layer(member, canvas, index); + switch_mutex_unlock(member->conference->canvas_mutex); + + switch_core_session_request_video_refresh(member->session); + switch_core_media_gen_key_frame(member->session); + canvas->send_keyframe = 10; + canvas->refresh = 1; + stream->write_function(stream, "+OK layer %d\n", member->video_layer_id + 1); + + return SWITCH_STATUS_SUCCESS; +} + + static switch_status_t conf_api_sub_energy(conference_member_t *member, switch_stream_handle_t *stream, void *data) { switch_event_t *event; @@ -8802,18 +10023,18 @@ static switch_status_t conf_api_sub_auto_position(conference_obj_t *conference, if (!zstr(arg)) { if (!strcasecmp(arg, "on")) { - switch_set_flag(conference, CFLAG_POSITIONAL); + conference_set_flag(conference, CFLAG_POSITIONAL); set = 1; } else if (!strcasecmp(arg, "off")) { - switch_clear_flag(conference, CFLAG_POSITIONAL); + conference_clear_flag(conference, CFLAG_POSITIONAL); } } - if (set && switch_test_flag(conference, CFLAG_POSITIONAL)) { + if (set && conference_test_flag(conference, CFLAG_POSITIONAL)) { gen_arc(conference, stream); } - stream->write_function(stream, "+OK positioning %s\n", switch_test_flag(conference, CFLAG_POSITIONAL) ? "on" : "off"); + stream->write_function(stream, "+OK positioning %s\n", conference_test_flag(conference, CFLAG_POSITIONAL) ? "on" : "off"); #else stream->write_function(stream, "-ERR not supported\n"); @@ -8834,15 +10055,15 @@ static switch_status_t conf_api_sub_position(conference_member_t *member, switch return SWITCH_STATUS_GENERR; } - if (switch_test_flag(member, MFLAG_NO_POSITIONAL)) { + if (member_test_flag(member, MFLAG_NO_POSITIONAL)) { if (stream) stream->write_function(stream, "%s has positional audio blocked.\n", switch_channel_get_name(member->channel)); return SWITCH_STATUS_SUCCESS; } if (!member->al) { - if (!switch_test_flag(member, MFLAG_POSITIONAL) && member->conference->channels == 2) { - switch_set_flag(member, MFLAG_POSITIONAL); + if (!member_test_flag(member, MFLAG_POSITIONAL) && member->conference->channels == 2) { + member_set_flag(member, MFLAG_POSITIONAL); member->al = create_al(member->pool); } else { @@ -8954,7 +10175,9 @@ static switch_status_t conf_api_sub_volume_out(conference_member_t *member, swit static switch_status_t conf_api_sub_vid_bandwidth(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { - if (!switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { + int32_t i, video_write_bandwidth; + + if (!conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { stream->write_function(stream, "Bandwidth control not available.\n"); return SWITCH_STATUS_SUCCESS; } @@ -8964,8 +10187,14 @@ static switch_status_t conf_api_sub_vid_bandwidth(conference_obj_t *conference, return SWITCH_STATUS_SUCCESS; } - conference->video_write_bandwidth = switch_parse_bandwidth_string(argv[2]); - stream->write_function(stream, "Set Bandwidth %d\n", conference->video_write_bandwidth); + video_write_bandwidth = switch_parse_bandwidth_string(argv[2]); + for (i = 0; i >= conference->canvas_count; i++) { + if (conference->canvases[i]) { + conference->canvases[i]->video_write_bandwidth = video_write_bandwidth; + } + } + + stream->write_function(stream, "Set Bandwidth %d\n", video_write_bandwidth); return SWITCH_STATUS_SUCCESS; } @@ -8999,20 +10228,28 @@ static switch_status_t conf_api_sub_vid_fps(conference_obj_t *conference, switch static switch_status_t conf_api_sub_write_png(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { switch_status_t status = SWITCH_STATUS_FALSE; + mcu_canvas_t *canvas = NULL; if (!argv[2]) { stream->write_function(stream, "Invalid input\n"); return SWITCH_STATUS_SUCCESS; } - if (!conference->canvas) { + if (!conference->canvas_count) { stream->write_function(stream, "Conference is not in mixing mode\n"); return SWITCH_STATUS_SUCCESS; } - switch_mutex_lock(conference->canvas->mutex); - status = switch_img_write_png(conference->canvas->img, argv[2]); - switch_mutex_unlock(conference->canvas->mutex); + if (conference->canvas_count > 1) { + /* pick super canvas */ + canvas = conference->canvases[conference->canvas_count]; + } else { + canvas = conference->canvases[0]; + } + + switch_mutex_lock(canvas->mutex); + status = switch_img_write_png(canvas->img, argv[2]); + switch_mutex_unlock(canvas->mutex); stream->write_function(stream, "%s\n", status == SWITCH_STATUS_SUCCESS ? "+OK" : "-ERR"); @@ -9022,6 +10259,7 @@ static switch_status_t conf_api_sub_write_png(conference_obj_t *conference, swit static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv) { video_layout_t *vlayout = NULL; + int idx = 0; if (!argv[2]) { stream->write_function(stream, "Invalid input\n"); @@ -9052,21 +10290,28 @@ static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, swi return SWITCH_STATUS_SUCCESS; } else { if (((lg = switch_core_hash_find(conference->layout_group_hash, argv[3])))) { - vlayout = find_best_layout(conference, lg); + vlayout = find_best_layout(conference, lg, 0); } if (!vlayout) { stream->write_function(stream, "Invalid group layout [%s]\n", argv[3]); return SWITCH_STATUS_SUCCESS; } - + stream->write_function(stream, "Change to layout group [%s]\n", argv[3]); conference->video_layout_group = switch_core_strdup(conference->pool, argv[3]); + + if (argv[4]) { + idx = atoi(argv[4]); + } } } if (!vlayout && (vlayout = switch_core_hash_find(conference->layout_hash, argv[2]))) { conference->video_layout_group = NULL; + if (argv[3]) { + idx = atoi(argv[3]); + } } if (!vlayout) { @@ -9074,10 +10319,12 @@ static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, swi return SWITCH_STATUS_SUCCESS; } - stream->write_function(stream, "Change to layout [%s]\n", vlayout->name); + if (idx < 0 || idx > conference->canvas_count - 1) idx = 0; + + stream->write_function(stream, "Change canvas %d to layout [%s]\n", idx, vlayout->name); switch_mutex_lock(conference->member_mutex); - conference->canvas->new_vlayout = vlayout; + conference->canvases[idx]->new_vlayout = vlayout; switch_mutex_unlock(conference->member_mutex); return SWITCH_STATUS_SUCCESS; @@ -9128,59 +10375,59 @@ static switch_status_t conf_api_sub_list(conference_obj_t *conference, switch_st stream->write_function(stream, "Conference %s (%u member%s rate: %u%s flags: ", conference->name, conference->count, - conference->count == 1 ? "" : "s", conference->rate, switch_test_flag(conference, CFLAG_LOCKED) ? " locked" : ""); + conference->count == 1 ? "" : "s", conference->rate, conference_test_flag(conference, CFLAG_LOCKED) ? " locked" : ""); - if (switch_test_flag(conference, CFLAG_LOCKED)) { + if (conference_test_flag(conference, CFLAG_LOCKED)) { stream->write_function(stream, "%slocked", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_DESTRUCT)) { + if (conference_test_flag(conference, CFLAG_DESTRUCT)) { stream->write_function(stream, "%sdestruct", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_WAIT_MOD)) { + if (conference_test_flag(conference, CFLAG_WAIT_MOD)) { stream->write_function(stream, "%swait_mod", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_AUDIO_ALWAYS)) { + if (conference_test_flag(conference, CFLAG_AUDIO_ALWAYS)) { stream->write_function(stream, "%saudio_always", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_RUNNING)) { + if (conference_test_flag(conference, CFLAG_RUNNING)) { stream->write_function(stream, "%srunning", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_ANSWERED)) { + if (conference_test_flag(conference, CFLAG_ANSWERED)) { stream->write_function(stream, "%sanswered", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_ENFORCE_MIN)) { + if (conference_test_flag(conference, CFLAG_ENFORCE_MIN)) { stream->write_function(stream, "%senforce_min", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_BRIDGE_TO)) { + if (conference_test_flag(conference, CFLAG_BRIDGE_TO)) { stream->write_function(stream, "%sbridge_to", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_DYNAMIC)) { + if (conference_test_flag(conference, CFLAG_DYNAMIC)) { stream->write_function(stream, "%sdynamic", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_EXIT_SOUND)) { + if (conference_test_flag(conference, CFLAG_EXIT_SOUND)) { stream->write_function(stream, "%sexit_sound", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) { + if (conference_test_flag(conference, CFLAG_ENTER_SOUND)) { stream->write_function(stream, "%senter_sound", fcount ? "|" : ""); fcount++; } @@ -9190,16 +10437,66 @@ static switch_status_t conf_api_sub_list(conference_obj_t *conference, switch_st fcount++; } - if (switch_test_flag(conference, CFLAG_VID_FLOOR)) { + if (conference_test_flag(conference, CFLAG_VID_FLOOR)) { stream->write_function(stream, "%svideo_floor_only", fcount ? "|" : ""); fcount++; } - if (switch_test_flag(conference, CFLAG_RFC4579)) { + if (conference_test_flag(conference, CFLAG_RFC4579)) { stream->write_function(stream, "%svideo_rfc4579", fcount ? "|" : ""); fcount++; } + if (conference_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) { + stream->write_function(stream, "%slivearray_sync", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_VID_FLOOR_LOCK)) { + stream->write_function(stream, "%svideo_floor_lock", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { + stream->write_function(stream, "%stranscode_video", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_VIDEO_MUXING)) { + stream->write_function(stream, "%svideo_muxing", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) { + stream->write_function(stream, "%sminimize_video_encoding", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_MANAGE_INBOUND_VIDEO_BITRATE)) { + stream->write_function(stream, "%smanage_inbound_bitrate", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_JSON_STATUS)) { + stream->write_function(stream, "%sjson_status", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_VIDEO_BRIDGE_FIRST_TWO)) { + stream->write_function(stream, "%svideo_bridge_first_two", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS)) { + stream->write_function(stream, "%svideo_required_for_canvas", fcount ? "|" : ""); + fcount++; + } + + if (conference_test_flag(conference, CFLAG_PERSONAL_CANVAS)) { + stream->write_function(stream, "%spersonal_canvas", fcount ? "|" : ""); + fcount++; + } + if (!fcount) { stream->write_function(stream, "none"); } @@ -9269,7 +10566,7 @@ static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference { switch_mutex_lock(conference->mutex); - switch_clear_flag(conference, CFLAG_VID_FLOOR_LOCK); + conference_clear_flag(conference, CFLAG_VID_FLOOR_LOCK); //conference_set_video_floor_holder(conference, NULL); switch_mutex_unlock(conference->mutex); @@ -9288,14 +10585,14 @@ static switch_status_t conf_api_sub_vid_mute_img(conference_member_t *member, sw return SWITCH_STATUS_FALSE; } - switch_mutex_lock(member->conference->canvas->mutex); + switch_mutex_lock(layer->canvas->mutex); - if (member->video_layer_id == -1 || !member->conference->canvas) { + if (member->video_layer_id == -1 || !layer->canvas) { goto end; } member->video_mute_png = NULL; - layer = &member->conference->canvas->layers[member->video_layer_id]; + layer = &layer->canvas->layers[member->video_layer_id]; if (text) { switch_img_free(&layer->mute_img); @@ -9309,7 +10606,7 @@ static switch_status_t conf_api_sub_vid_mute_img(conference_member_t *member, sw stream->write_function(stream, "%s\n", member->video_mute_png ? member->video_mute_png : "_undef_"); - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(layer->canvas->mutex); return SWITCH_STATUS_SUCCESS; @@ -9332,9 +10629,11 @@ static switch_status_t conf_api_sub_vid_logo_img(conference_member_t *member, sw goto end; } - switch_mutex_lock(member->conference->canvas->mutex); + layer = &member->conference->canvas->layers[member->video_layer_id]; + + switch_mutex_lock(layer->canvas->mutex); if (strcasecmp(text, "clear")) { member->video_logo = switch_core_strdup(member->pool, text); @@ -9346,7 +10645,7 @@ static switch_status_t conf_api_sub_vid_logo_img(conference_member_t *member, sw stream->write_function(stream, "+OK\n"); - switch_mutex_unlock(member->conference->canvas->mutex); + switch_mutex_unlock(layer->canvas->mutex); return SWITCH_STATUS_SUCCESS; @@ -9454,8 +10753,8 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc force = 1; } - if (member->conference->video_floor_holder == member->id && switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) { - switch_clear_flag(member->conference, CFLAG_VID_FLOOR_LOCK); + if (member->conference->video_floor_holder == member->id && conference_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) { + conference_clear_flag(member->conference, CFLAG_VID_FLOOR_LOCK); conference_set_floor_holder(member->conference, member); if (stream == NULL) { @@ -9465,7 +10764,7 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc } } else if (force || member->conference->video_floor_holder == 0) { - switch_set_flag(member->conference, CFLAG_VID_FLOOR_LOCK); + conference_set_flag(member->conference, CFLAG_VID_FLOOR_LOCK); conference_set_video_floor_holder(member->conference, member, SWITCH_TRUE); if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE)) { if (stream == NULL) { @@ -9532,47 +10831,47 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer switch_xml_set_attr_d(x_conference, "rate", ival); switch_xml_set_attr_d(x_conference, "uuid", conference->uuid_str); - if (switch_test_flag(conference, CFLAG_LOCKED)) { + if (conference_test_flag(conference, CFLAG_LOCKED)) { switch_xml_set_attr_d(x_conference, "locked", "true"); } - if (switch_test_flag(conference, CFLAG_DESTRUCT)) { + if (conference_test_flag(conference, CFLAG_DESTRUCT)) { switch_xml_set_attr_d(x_conference, "destruct", "true"); } - if (switch_test_flag(conference, CFLAG_WAIT_MOD)) { + if (conference_test_flag(conference, CFLAG_WAIT_MOD)) { switch_xml_set_attr_d(x_conference, "wait_mod", "true"); } - if (switch_test_flag(conference, CFLAG_AUDIO_ALWAYS)) { + if (conference_test_flag(conference, CFLAG_AUDIO_ALWAYS)) { switch_xml_set_attr_d(x_conference, "audio_always", "true"); } - if (switch_test_flag(conference, CFLAG_RUNNING)) { + if (conference_test_flag(conference, CFLAG_RUNNING)) { switch_xml_set_attr_d(x_conference, "running", "true"); } - if (switch_test_flag(conference, CFLAG_ANSWERED)) { + if (conference_test_flag(conference, CFLAG_ANSWERED)) { switch_xml_set_attr_d(x_conference, "answered", "true"); } - if (switch_test_flag(conference, CFLAG_ENFORCE_MIN)) { + if (conference_test_flag(conference, CFLAG_ENFORCE_MIN)) { switch_xml_set_attr_d(x_conference, "enforce_min", "true"); } - if (switch_test_flag(conference, CFLAG_BRIDGE_TO)) { + if (conference_test_flag(conference, CFLAG_BRIDGE_TO)) { switch_xml_set_attr_d(x_conference, "bridge_to", "true"); } - if (switch_test_flag(conference, CFLAG_DYNAMIC)) { + if (conference_test_flag(conference, CFLAG_DYNAMIC)) { switch_xml_set_attr_d(x_conference, "dynamic", "true"); } - if (switch_test_flag(conference, CFLAG_EXIT_SOUND)) { + if (conference_test_flag(conference, CFLAG_EXIT_SOUND)) { switch_xml_set_attr_d(x_conference, "exit_sound", "true"); } - if (switch_test_flag(conference, CFLAG_ENTER_SOUND)) { + if (conference_test_flag(conference, CFLAG_ENTER_SOUND)) { switch_xml_set_attr_d(x_conference, "enter_sound", "true"); } @@ -9590,11 +10889,11 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer switch_xml_set_attr_d(x_conference, "endconf_grace_time", ival); } - if (switch_test_flag(conference, CFLAG_VID_FLOOR)) { + if (conference_test_flag(conference, CFLAG_VID_FLOOR)) { switch_xml_set_attr_d(x_conference, "video_floor_only", "true"); } - if (switch_test_flag(conference, CFLAG_RFC4579)) { + if (conference_test_flag(conference, CFLAG_RFC4579)) { switch_xml_set_attr_d(x_conference, "video_rfc4579", "true"); } @@ -9622,7 +10921,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer int toff = 0; char tmp[50] = ""; - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_NOCHANNEL)) { if (member->rec_path) { x_member = switch_xml_add_child_d(x_members, "member", moff++); switch_assert(x_member); @@ -9632,7 +10931,7 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer */ x_tag = switch_xml_add_child_d(x_member, "record_path", count++); - if (switch_test_flag(member, MFLAG_PAUSE_RECORDING)) { + if (member_test_flag(member, MFLAG_PAUSE_RECORDING)) { switch_xml_set_attr_d(x_tag, "status", "paused"); } switch_xml_set_txt_d(x_tag, member->rec_path); @@ -9682,34 +10981,34 @@ static void conference_xlist(conference_obj_t *conference, switch_xml_t x_confer switch_assert(x_flags); x_tag = switch_xml_add_child_d(x_flags, "can_hear", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "can_speak", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "mute_detect", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "talking", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_TALKING) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_TALKING) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "has_video", count++); switch_xml_set_txt_d(x_tag, switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "video_bridge", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_VIDEO_BRIDGE) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_VIDEO_BRIDGE) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "has_floor", count++); switch_xml_set_txt_d(x_tag, (member == member->conference->floor_holder) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "is_moderator", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_MOD) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_MOD) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "end_conference", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_ENDCONF) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_ENDCONF) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "is_ghost", count++); - switch_xml_set_txt_d(x_tag, switch_test_flag(member, MFLAG_GHOST) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, member_test_flag(member, MFLAG_GHOST) ? "true" : "false"); switch_snprintf(tmp, sizeof(tmp), "%d", member->volume_out_level); add_x_tag(x_member, "output-volume", tmp, toff++); @@ -10129,8 +11428,8 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_ other_member = conference_member_get(conference, oid); if (other_member) { - if (switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO)) { - switch_clear_flag(other_member, MFLAG_RECEIVING_VIDEO); + if (member_test_flag(other_member, MFLAG_RECEIVING_VIDEO)) { + member_clear_flag(other_member, MFLAG_RECEIVING_VIDEO); if (conference->floor_holder) { switch_core_session_request_video_refresh(conference->floor_holder->session); } @@ -10158,7 +11457,7 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_ if (member && other_member) { conference_relationship_t *rel = NULL; - if (sendvideo && switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO) && (! (nospeak || nohear))) { + if (sendvideo && member_test_flag(other_member, MFLAG_RECEIVING_VIDEO) && (! (nospeak || nohear))) { stream->write_function(stream, "member %d already receiving video", oid); goto skip; } @@ -10173,14 +11472,14 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_ switch_set_flag(rel, RFLAG_CAN_SPEAK | RFLAG_CAN_HEAR); if (nospeak) { switch_clear_flag(rel, RFLAG_CAN_SPEAK); - switch_clear_flag_locked(member, MFLAG_TALKING); + member_clear_flag_locked(member, MFLAG_TALKING); } if (nohear) { switch_clear_flag(rel, RFLAG_CAN_HEAR); } if (sendvideo) { switch_set_flag(rel, RFLAG_CAN_SEND_VIDEO); - switch_set_flag(other_member, MFLAG_RECEIVING_VIDEO); + member_set_flag(other_member, MFLAG_RECEIVING_VIDEO); switch_core_session_request_video_refresh(member->session); } @@ -10216,7 +11515,7 @@ static switch_status_t conf_api_sub_lock(conference_obj_t *conference, switch_st conference_play_file(conference, conference->is_locked_sound, CONF_DEFAULT_LEADIN, NULL, 0); } - switch_set_flag_locked(conference, CFLAG_LOCKED); + conference_set_flag_locked(conference, CFLAG_LOCKED); stream->write_function(stream, "OK %s locked\n", argv[0]); if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10238,7 +11537,7 @@ static switch_status_t conf_api_sub_unlock(conference_obj_t *conference, switch_ conference_play_file(conference, conference->is_unlocked_sound, CONF_DEFAULT_LEADIN, NULL, 0); } - switch_clear_flag_locked(conference, CFLAG_LOCKED); + conference_clear_flag_locked(conference, CFLAG_LOCKED); stream->write_function(stream, "OK %s unlocked\n", argv[0]); if (test_eflag(conference, EFLAG_UNLOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10262,7 +11561,7 @@ static switch_status_t conf_api_sub_exit_sound(conference_obj_t *conference, swi } if ( !strcasecmp(argv[2], "on") ) { - switch_set_flag_locked(conference, CFLAG_EXIT_SOUND); + conference_set_flag_locked(conference, CFLAG_EXIT_SOUND); stream->write_function(stream, "OK %s exit sounds on (%s)\n", argv[0], conference->exit_sound); if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10270,7 +11569,7 @@ static switch_status_t conf_api_sub_exit_sound(conference_obj_t *conference, swi switch_event_fire(&event); } } else if ( !strcasecmp(argv[2], "off") || !strcasecmp(argv[2], "none") ) { - switch_clear_flag_locked(conference, CFLAG_EXIT_SOUND); + conference_clear_flag_locked(conference, CFLAG_EXIT_SOUND); stream->write_function(stream, "OK %s exit sounds off (%s)\n", argv[0], conference->exit_sound); if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10313,7 +11612,7 @@ static switch_status_t conf_api_sub_enter_sound(conference_obj_t *conference, sw } if ( !strcasecmp(argv[2], "on") ) { - switch_set_flag_locked(conference, CFLAG_ENTER_SOUND); + conference_set_flag_locked(conference, CFLAG_ENTER_SOUND); stream->write_function(stream, "OK %s enter sounds on (%s)\n", argv[0], conference->enter_sound); if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10321,7 +11620,7 @@ static switch_status_t conf_api_sub_enter_sound(conference_obj_t *conference, sw switch_event_fire(&event); } } else if ( !strcasecmp(argv[2], "off") || !strcasecmp(argv[2], "none") ) { - switch_clear_flag_locked(conference, CFLAG_ENTER_SOUND); + conference_clear_flag_locked(conference, CFLAG_ENTER_SOUND); stream->write_function(stream, "OK %s enter sounds off (%s)\n", argv[0], conference->enter_sound); if (test_eflag(conference, EFLAG_LOCK) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_add_event_data(conference, event); @@ -10730,7 +12029,7 @@ static switch_status_t conf_api_sub_get(conference_obj_t *conference, conference->caller_id_number); } else if (strcasecmp(argv[2], "is_locked") == 0) { stream->write_function(stream, "%s", - switch_test_flag(conference, CFLAG_LOCKED) ? "locked" : ""); + conference_test_flag(conference, CFLAG_LOCKED) ? "locked" : ""); } else if (strcasecmp(argv[2], "endconf_grace_time") == 0) { stream->write_function(stream, "%d", conference->endconf_grace_time); @@ -10739,7 +12038,7 @@ static switch_status_t conf_api_sub_get(conference_obj_t *conference, conference->uuid_str); } else if (strcasecmp(argv[2], "wait_mod") == 0) { stream->write_function(stream, "%s", - switch_test_flag(conference, CFLAG_WAIT_MOD) ? "true" : ""); + conference_test_flag(conference, CFLAG_WAIT_MOD) ? "true" : ""); } else { ret_status = SWITCH_STATUS_FALSE; } @@ -10826,6 +12125,9 @@ static api_command_t conf_api_sub_commands[] = { {"list", (void_fn_t) & conf_api_sub_list, CONF_API_SUB_ARGS_SPLIT, "list", "[delim ]|[count]"}, {"xml_list", (void_fn_t) & conf_api_sub_xml_list, CONF_API_SUB_ARGS_SPLIT, "xml_list", ""}, {"energy", (void_fn_t) & conf_api_sub_energy, CONF_API_SUB_MEMBER_TARGET, "energy", " []"}, + {"vid-canvas", (void_fn_t) & conf_api_sub_canvas, CONF_API_SUB_MEMBER_TARGET, "vid-canvas", " []"}, + {"vid-watching-canvas", (void_fn_t) & conf_api_sub_watching_canvas, CONF_API_SUB_MEMBER_TARGET, "vid-watching-canvas", " []"}, + {"vid-layer", (void_fn_t) & conf_api_sub_layer, CONF_API_SUB_MEMBER_TARGET, "vid-layer", " []"}, {"volume_in", (void_fn_t) & conf_api_sub_volume_in, CONF_API_SUB_MEMBER_TARGET, "volume_in", " []"}, {"volume_out", (void_fn_t) & conf_api_sub_volume_out, CONF_API_SUB_MEMBER_TARGET, "volume_out", " []"}, {"position", (void_fn_t) & conf_api_sub_position, CONF_API_SUB_MEMBER_TARGET, "position", " ::"}, @@ -10875,7 +12177,7 @@ static api_command_t conf_api_sub_commands[] = { {"vid-logo-img", (void_fn_t) & conf_api_sub_vid_logo_img, CONF_API_SUB_MEMBER_TARGET, "vid-logo-img", " [|clear]"}, {"vid-res-id", (void_fn_t) & conf_api_sub_vid_res_id, CONF_API_SUB_MEMBER_TARGET, "vid-res-id", " |clear"}, {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""}, - {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", ""}, + {"vid-layout", (void_fn_t) & conf_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "|group []"}, {"vid-write-png", (void_fn_t) & conf_api_sub_write_png, CONF_API_SUB_ARGS_SPLIT, "vid-write-png", ""}, {"vid-fps", (void_fn_t) & conf_api_sub_vid_fps, CONF_API_SUB_ARGS_SPLIT, "vid-fps", ""}, {"vid-bandwidth", (void_fn_t) & conf_api_sub_vid_bandwidth, CONF_API_SUB_ARGS_SPLIT, "vid-bandwidth", ""} @@ -10942,7 +12244,7 @@ switch_status_t conf_api_dispatch(conference_obj_t *conference, switch_stream_ha } /* exec functio on last (oldest) member */ - if (last_member != NULL && last_member->session && !switch_test_flag(last_member, MFLAG_NOCHANNEL)) { + if (last_member != NULL && last_member->session && !member_test_flag(last_member, MFLAG_NOCHANNEL)) { conf_api_member_cmd_t pfn = (conf_api_member_cmd_t) conf_api_sub_commands[i].pfnapicmd; pfn(last_member, stream, argv[argn + 2]); } @@ -11181,7 +12483,7 @@ static switch_status_t conference_outcall(conference_obj_t *conference, peer_channel = switch_core_session_get_channel(peer_session); /* make sure the conference still exists */ - if (!switch_test_flag(conference, CFLAG_RUNNING)) { + if (!conference_test_flag(conference, CFLAG_RUNNING)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Conference is gone now, nevermind..\n"); if (caller_channel) { switch_channel_hangup(caller_channel, SWITCH_CAUSE_NO_ROUTE_DESTINATION); @@ -11438,7 +12740,7 @@ static void set_mflags(const char *flags, member_flag_t *f) char *argv[10] = { 0 }; int i, argc = 0; - *f |= MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR | MFLAG_CAN_BE_SEEN; + f[MFLAG_CAN_SPEAK] = f[MFLAG_CAN_HEAR] = f[MFLAG_CAN_BE_SEEN] = 1; for (p = dup; p && *p; p++) { if (*p == ',') { @@ -11450,36 +12752,42 @@ static void set_mflags(const char *flags, member_flag_t *f) for (i = 0; i < argc && argv[i]; i++) { if (!strcasecmp(argv[i], "mute")) { - *f &= ~MFLAG_CAN_SPEAK; - *f &= ~MFLAG_TALKING; + f[MFLAG_CAN_SPEAK] = 0; + f[MFLAG_TALKING] = 0; } else if (!strcasecmp(argv[i], "deaf")) { - *f &= ~MFLAG_CAN_HEAR; + f[MFLAG_CAN_HEAR] = 0; } else if (!strcasecmp(argv[i], "mute-detect")) { - *f |= MFLAG_MUTE_DETECT; + f[MFLAG_MUTE_DETECT] = 1; } else if (!strcasecmp(argv[i], "dist-dtmf")) { - *f |= MFLAG_DIST_DTMF; + f[MFLAG_DIST_DTMF] = 1; } else if (!strcasecmp(argv[i], "moderator")) { - *f |= MFLAG_MOD; + f[MFLAG_MOD] = 1; } else if (!strcasecmp(argv[i], "nomoh")) { - *f |= MFLAG_NOMOH; + f[MFLAG_NOMOH] = 1; } else if (!strcasecmp(argv[i], "endconf")) { - *f |= MFLAG_ENDCONF; + f[MFLAG_ENDCONF] = 1; } else if (!strcasecmp(argv[i], "mintwo")) { - *f |= MFLAG_MINTWO; + f[MFLAG_MINTWO] = 1; } else if (!strcasecmp(argv[i], "video-bridge")) { - *f |= MFLAG_VIDEO_BRIDGE; + f[MFLAG_VIDEO_BRIDGE] = 1; } else if (!strcasecmp(argv[i], "ghost")) { - *f |= MFLAG_GHOST; + f[MFLAG_GHOST] = 1; } else if (!strcasecmp(argv[i], "join-only")) { - *f |= MFLAG_JOIN_ONLY; + f[MFLAG_JOIN_ONLY] = 1; } else if (!strcasecmp(argv[i], "positional")) { - *f |= MFLAG_POSITIONAL; + f[MFLAG_POSITIONAL] = 1; } else if (!strcasecmp(argv[i], "no-positional")) { - *f |= MFLAG_NO_POSITIONAL; + f[MFLAG_NO_POSITIONAL] = 1; } else if (!strcasecmp(argv[i], "join-vid-floor")) { - *f |= MFLAG_JOIN_VID_FLOOR; + f[MFLAG_JOIN_VID_FLOOR] = 1; } else if (!strcasecmp(argv[i], "no-minimize-encoding")) { - *f |= MFLAG_NO_MINIMIZE_ENCODING; + f[MFLAG_NO_MINIMIZE_ENCODING] = 1; + } else if (!strcasecmp(argv[i], "second-screen")) { + f[MFLAG_SECOND_SCREEN] = 1; + f[MFLAG_CAN_SPEAK] = 0; + f[MFLAG_TALKING] = 0; + f[MFLAG_CAN_HEAR] = 0; + f[MFLAG_SILENT] = 1; } } @@ -11489,7 +12797,7 @@ static void set_mflags(const char *flags, member_flag_t *f) -static void set_cflags(const char *flags, uint32_t *f) +static void set_cflags(const char *flags, conference_flag_t *f) { if (flags) { char *dup = strdup(flags); @@ -11507,30 +12815,34 @@ static void set_cflags(const char *flags, uint32_t *f) for (i = 0; i < argc && argv[i]; i++) { if (!strcasecmp(argv[i], "wait-mod")) { - *f |= CFLAG_WAIT_MOD; + f[CFLAG_WAIT_MOD] = 1; } else if (!strcasecmp(argv[i], "video-floor-only")) { - *f |= CFLAG_VID_FLOOR; + f[CFLAG_VID_FLOOR] = 1; } else if (!strcasecmp(argv[i], "audio-always")) { - *f |= CFLAG_AUDIO_ALWAYS; + f[CFLAG_AUDIO_ALWAYS] = 1; } else if (!strcasecmp(argv[i], "restart-auto-record")) { - *f |= CFLAG_CONF_RESTART_AUTO_RECORD; + f[CFLAG_CONF_RESTART_AUTO_RECORD] = 1; } else if (!strcasecmp(argv[i], "json-events")) { - *f |= CFLAG_JSON_EVENTS; + f[CFLAG_JSON_EVENTS] = 1; } else if (!strcasecmp(argv[i], "livearray-sync")) { - *f |= CFLAG_LIVEARRAY_SYNC; + f[CFLAG_LIVEARRAY_SYNC] = 1; } else if (!strcasecmp(argv[i], "livearray-json-status")) { - *f |= CFLAG_JSON_STATUS; + f[CFLAG_JSON_STATUS] = 1; } else if (!strcasecmp(argv[i], "rfc-4579")) { - *f |= CFLAG_RFC4579; + f[CFLAG_RFC4579] = 1; } else if (!strcasecmp(argv[i], "auto-3d-position")) { - *f |= CFLAG_POSITIONAL; + f[CFLAG_POSITIONAL] = 1; } else if (!strcasecmp(argv[i], "minimize-video-encoding")) { - *f |= CFLAG_MINIMIZE_VIDEO_ENCODING; + f[CFLAG_MINIMIZE_VIDEO_ENCODING] = 1; + } else if (!strcasecmp(argv[i], "video-bridge-first-two")) { + f[CFLAG_VIDEO_BRIDGE_FIRST_TWO] = 1; + } else if (!strcasecmp(argv[i], "video-required-for-canvas")) { + f[CFLAG_VIDEO_REQUIRED_FOR_CANVAS] = 1; } else if (!strcasecmp(argv[i], "manage-inbound-video-bitrate")) { - *f |= CFLAG_MANAGE_INBOUND_VIDEO_BITRATE; + f[CFLAG_MANAGE_INBOUND_VIDEO_BITRATE] = 1; + } else if (!strcasecmp(argv[i], "video-muxing-personal-canvas")) { + f[CFLAG_PERSONAL_CANVAS] = 1; } - - } free(dup); @@ -11756,6 +13068,60 @@ static int setup_media(conference_member_t *member, conference_obj_t *conference } +static void merge_mflags(member_flag_t *a, member_flag_t *b) +{ + int x; + + for (x = 0; x < MFLAG_MAX; x++) { + if (b[x]) a[x] = 1; + } +} + + +static const char *combine_flag_var(switch_core_session_t *session, const char *var_name) +{ + switch_event_header_t *hp; + switch_event_t *event, *cevent; + char *ret = NULL; + switch_channel_t *channel = switch_core_session_get_channel(session); + + switch_core_get_variables(&event); + switch_channel_get_variables(channel, &cevent); + switch_event_merge(event, cevent); + + + for (hp = event->headers; hp; hp = hp->next) { + char *var = hp->name; + char *val = hp->value; + + if (!strcasecmp(var, var_name)) { + if (hp->idx) { + int i; + for (i = 0; i < hp->idx; i++) { + if (zstr(ret)) { + ret = switch_core_session_sprintf(session, "%s", hp->array[i]); + } else { + ret = switch_core_session_sprintf(session, "%s|%s", ret, hp->array[i]); + } + } + } else { + if (zstr(ret)) { + ret = switch_core_session_sprintf(session, "%s", val); + } else { + ret = switch_core_session_sprintf(session, "%s|%s", ret, val); + } + } + } + } + + + switch_event_destroy(&event); + switch_event_destroy(&cevent); + + return ret; + +} + #define validate_pin(buf, pin, mpin) \ pin_valid = (!zstr(pin) && strcmp(buf, pin) == 0); \ if (!pin_valid && !zstr(mpin) && strcmp(buf, mpin) == 0) { \ @@ -11780,7 +13146,7 @@ SWITCH_STANDARD_APP(conference_function) switch_xml_t cxml = NULL, cfg = NULL, profiles = NULL; const char *flags_str, *v_flags_str; const char *cflags_str, *v_cflags_str; - member_flag_t mflags = 0; + member_flag_t mflags[MFLAG_MAX] = { 0 }; switch_core_session_message_t msg = { 0 }; uint8_t rl = 0, isbr = 0; char *dpin = ""; @@ -11832,8 +13198,9 @@ SWITCH_STANDARD_APP(conference_function) *p = '\0'; } } - - if ((v_flags_str = switch_channel_get_variable(channel, "conference_member_flags"))) { + + //if ((v_flags_str = switch_channel_get_variable(channel, "conference_member_flags"))) { + if ((v_flags_str = combine_flag_var(session, "conference_member_flags"))) { if (zstr(flags_str)) { flags_str = v_flags_str; } else { @@ -11843,7 +13210,8 @@ SWITCH_STANDARD_APP(conference_function) cflags_str = flags_str; - if ((v_cflags_str = switch_channel_get_variable(channel, "conference_flags"))) { + //if ((v_cflags_str = switch_channel_get_variable(channel, "conference_flags"))) { + if ((v_cflags_str = combine_flag_var(session, "conference_flags"))) { if (zstr(cflags_str)) { cflags_str = v_cflags_str; } else { @@ -11941,7 +13309,7 @@ SWITCH_STANDARD_APP(conference_function) goto done; } - set_cflags(cflags_str, &conference->flags); + set_cflags(cflags_str, conference->flags); if (locked) { switch_mutex_unlock(globals.setup_mutex); @@ -11954,10 +13322,10 @@ SWITCH_STANDARD_APP(conference_function) conference->min = 2; /* Indicate the conference is dynamic */ - switch_set_flag_locked(conference, CFLAG_DYNAMIC); + conference_set_flag_locked(conference, CFLAG_DYNAMIC); /* Indicate the conference has a bridgeto party */ - switch_set_flag_locked(conference, CFLAG_BRIDGE_TO); + conference_set_flag_locked(conference, CFLAG_BRIDGE_TO); /* Start the conference thread for this conference */ launch_conference_thread(conference); @@ -11985,15 +13353,15 @@ SWITCH_STANDARD_APP(conference_function) /* no conference yet, so check for join-only flag */ if (flags_str) { - set_mflags(flags_str, &mflags); + set_mflags(flags_str, mflags); - if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_MUTE_DETECT)) { + if (!(mflags[MFLAG_CAN_SPEAK])) { + if (!(mflags[MFLAG_MUTE_DETECT])) { switch_core_media_hard_mute(session, SWITCH_TRUE); } } - if (mflags & MFLAG_JOIN_ONLY) { + if (mflags[MFLAG_JOIN_ONLY]) { switch_event_t *event; switch_xml_t jos_xml; char *val; @@ -12025,7 +13393,7 @@ SWITCH_STANDARD_APP(conference_function) goto done; } - set_cflags(cflags_str, &conference->flags); + set_cflags(cflags_str, conference->flags); if (locked) { switch_mutex_unlock(globals.setup_mutex); @@ -12083,7 +13451,7 @@ SWITCH_STANDARD_APP(conference_function) } /* Indicate the conference is dynamic */ - switch_set_flag_locked(conference, CFLAG_DYNAMIC); + conference_set_flag_locked(conference, CFLAG_DYNAMIC); /* acquire a read lock on the thread so it can't leave without us */ if (switch_thread_rwlock_tryrdlock(conference->rwlock) != SWITCH_STATUS_SUCCESS) { @@ -12209,7 +13577,7 @@ SWITCH_STANDARD_APP(conference_function) } /* don't allow more callers if the conference is locked, unless we invited them */ - if (switch_test_flag(conference, CFLAG_LOCKED) && enforce_security) { + if (conference_test_flag(conference, CFLAG_LOCKED) && enforce_security) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_NOTICE, "Conference %s is locked.\n", conf_name); conference_cdr_rejected(conference, channel, CDRR_LOCKED); if (conference->locked_sound) { @@ -12253,7 +13621,7 @@ SWITCH_STANDARD_APP(conference_function) /* if we're not using "bridge:" set the conference answered flag */ /* and this isn't an outbound channel, answer the call */ if (switch_channel_direction(channel) == SWITCH_CALL_DIRECTION_INBOUND) - switch_set_flag(conference, CFLAG_ANSWERED); + conference_set_flag(conference, CFLAG_ANSWERED); } member.session = session; @@ -12288,29 +13656,33 @@ SWITCH_STANDARD_APP(conference_function) /* Install our Signed Linear codec so we get the audio in that format */ switch_core_session_set_read_codec(member.session, &member.read_codec); + + memcpy(mflags, conference->mflags, sizeof(mflags)); + + set_mflags(flags_str, mflags); + mflags[MFLAG_RUNNING] = 1; - mflags = conference->mflags; - set_mflags(flags_str, &mflags); - mflags |= MFLAG_RUNNING; - - if (!(mflags & MFLAG_CAN_SPEAK)) { - if (!(mflags & MFLAG_MUTE_DETECT)) { + if (!(mflags[MFLAG_CAN_SPEAK])) { + if (!(mflags[MFLAG_MUTE_DETECT])) { switch_core_media_hard_mute(member.session, SWITCH_TRUE); } } if (mpin_matched) { - mflags |= MFLAG_MOD; + mflags[MFLAG_MOD] = 1; } - switch_set_flag_locked((&member), mflags); - if (mflags & MFLAG_MINTWO) { + merge_mflags(member.flags, mflags); + + + if (mflags[MFLAG_MINTWO]) { conference->min = 2; } + if (conference->conf_video_mode == CONF_VIDEO_MODE_MUX) { - switch_queue_create(&member.video_queue, 2000, member.pool); - switch_queue_create(&member.mux_out_queue, 2000, member.pool); + switch_queue_create(&member.video_queue, 200, member.pool); + switch_queue_create(&member.mux_out_queue, 200, member.pool); switch_frame_buffer_create(&member.fb); } @@ -12330,7 +13702,7 @@ SWITCH_STANDARD_APP(conference_function) msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE; switch_core_session_receive_message(session, &msg); - if (switch_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { + if (conference_test_flag(conference, CFLAG_TRANSCODE_VIDEO)) { switch_channel_set_flag(channel, CF_VIDEO_DECODED_READ); switch_core_media_gen_key_frame(session); } @@ -12339,7 +13711,7 @@ SWITCH_STANDARD_APP(conference_function) switch_core_session_set_video_read_callback(session, video_thread_callback, (void *)&member); if (switch_channel_test_flag(channel, CF_VIDEO_ONLY)) { - while(switch_test_flag((&member), MFLAG_RUNNING) && switch_channel_ready(channel)) { + while(member_test_flag((&member), MFLAG_RUNNING) && switch_channel_ready(channel)) { switch_yield(100000); } } else { @@ -12395,8 +13767,8 @@ SWITCH_STANDARD_APP(conference_function) if (conference) { switch_mutex_lock(conference->mutex); - if (switch_test_flag(conference, CFLAG_DYNAMIC) && conference->count == 0) { - switch_set_flag_locked(conference, CFLAG_DESTRUCT); + if (conference_test_flag(conference, CFLAG_DYNAMIC) && conference->count == 0) { + conference_set_flag_locked(conference, CFLAG_DESTRUCT); } switch_mutex_unlock(conference->mutex); } @@ -12406,7 +13778,7 @@ SWITCH_STANDARD_APP(conference_function) switch_xml_free(cxml); } - if (conference && switch_test_flag(&member, MFLAG_KICKED) && conference->kicked_sound) { + if (conference && member_test_flag(&member, MFLAG_KICKED) && conference->kicked_sound) { char *toplay = NULL; char *dfile = NULL; char *expanded = NULL; @@ -12466,17 +13838,18 @@ static void launch_conference_video_muxing_write_thread(conference_member_t *mem } switch_mutex_unlock(globals.hash_mutex); } -static void launch_conference_video_muxing_thread(conference_obj_t *conference) +static void launch_conference_video_muxing_thread(conference_obj_t *conference, mcu_canvas_t *canvas, int super) { switch_threadattr_t *thd_attr = NULL; + switch_mutex_lock(globals.hash_mutex); - if (!conference->video_muxing_thread) { - switch_set_flag_locked(conference, CFLAG_RUNNING); + if (!canvas->video_muxing_thread) { switch_threadattr_create(&thd_attr, conference->pool); switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_set_flag(conference, CFLAG_VIDEO_MUXING); - switch_thread_create(&conference->video_muxing_thread, thd_attr, conference_video_muxing_thread_run, conference, conference->pool); + conference_set_flag(conference, CFLAG_VIDEO_MUXING); + switch_thread_create(&canvas->video_muxing_thread, thd_attr, + super ? conference_super_video_muxing_thread_run : conference_video_muxing_thread_run, canvas, conference->pool); } switch_mutex_unlock(globals.hash_mutex); } @@ -12487,7 +13860,7 @@ static void launch_conference_thread(conference_obj_t *conference) switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; - switch_set_flag_locked(conference, CFLAG_RUNNING); + conference_set_flag_locked(conference, CFLAG_RUNNING); switch_threadattr_create(&thd_attr, conference->pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_priority_set(thd_attr, SWITCH_PRI_REALTIME); @@ -12604,9 +13977,9 @@ static conference_obj_t *conference_find(char *name, char *domain) switch_mutex_lock(globals.hash_mutex); if ((conference = switch_core_hash_find(globals.conference_hash, name))) { - if (switch_test_flag(conference, CFLAG_DESTRUCT)) { + if (conference_test_flag(conference, CFLAG_DESTRUCT)) { switch_core_hash_delete(globals.conference_hash, conference->name); - switch_clear_flag(conference, CFLAG_INHASH); + conference_clear_flag(conference, CFLAG_INHASH); conference = NULL; } else if (!zstr(domain) && conference->domain && strcasecmp(domain, conference->domain)) { conference = NULL; @@ -12665,6 +14038,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c char *video_layout_group = NULL; char *video_canvas_size = NULL; char *video_canvas_bgcolor = NULL; + char *video_super_canvas_bgcolor = NULL; char *video_letterbox_bgcolor = NULL; char *video_codec_bandwidth = NULL; char *no_video_avatar = NULL; @@ -12680,6 +14054,9 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c int pin_retries = 3; int ivr_dtmf_timeout = 500; int ivr_input_timeout = 0; + int video_canvas_count = 0; + int video_super_canvas_label_layers = 0; + int video_super_canvas_show_all_layers = 0; char *suppress_events = NULL; char *verbose_events = NULL; char *auto_record = NULL; @@ -12819,8 +14196,16 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c outcall_templ = val; } else if (!strcasecmp(var, "video-layout-name") && !zstr(val)) { video_layout_name = val; + } else if (!strcasecmp(var, "video-canvas-count") && !zstr(val)) { + video_canvas_count = atoi(val); + } else if (!strcasecmp(var, "video-super-canvas-label-layers") && !zstr(val)) { + video_super_canvas_label_layers = atoi(val); + } else if (!strcasecmp(var, "video-super-canvas-show-all-layers") && !zstr(val)) { + video_super_canvas_show_all_layers = atoi(val); } else if (!strcasecmp(var, "video-canvas-bgcolor") && !zstr(val)) { video_canvas_bgcolor= val; + } else if (!strcasecmp(var, "video-super-canvas-bgcolor") && !zstr(val)) { + video_super_canvas_bgcolor= val; } else if (!strcasecmp(var, "video-letterbox-bgcolor") && !zstr(val)) { video_letterbox_bgcolor= val; } else if (!strcasecmp(var, "video-canvas-size") && !zstr(val)) { @@ -13063,6 +14448,10 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c video_canvas_bgcolor = "#333333"; } + if (!video_super_canvas_bgcolor) { + video_super_canvas_bgcolor = "#068df3"; + } + if (!video_letterbox_bgcolor) { video_letterbox_bgcolor = "#000000"; } @@ -13072,6 +14461,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c } conference->video_canvas_bgcolor = switch_core_strdup(conference->pool, video_canvas_bgcolor); + conference->video_super_canvas_bgcolor = switch_core_strdup(conference->pool, video_super_canvas_bgcolor); conference->video_letterbox_bgcolor = switch_core_strdup(conference->pool, video_letterbox_bgcolor); if (fps) { @@ -13101,11 +14491,12 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c if (video_layout_name) { conference->video_layout_name = switch_core_strdup(conference->pool, video_layout_name); } + if (video_layout_group) { conference->video_layout_group = switch_core_strdup(conference->pool, video_layout_group); } - if (!get_layout(conference)) { + if (!get_layout(conference, video_layout_name, video_layout_group)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid video-layout-name specified, using " CONFERENCE_MUX_DEFAULT_LAYOUT "\n"); video_layout_name = CONFERENCE_MUX_DEFAULT_LAYOUT; video_layout_group = video_layout_name + 6; @@ -13113,7 +14504,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->video_layout_group = switch_core_strdup(conference->pool, video_layout_group); } - if (!get_layout(conference)) { + if (!get_layout(conference, video_layout_name, video_layout_group)) { conference->video_layout_name = conference->video_layout_group = video_layout_group = video_layout_name = NULL; conference->conf_video_mode = CONF_VIDEO_MODE_TRANSCODE; switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "Invalid conference layout settings, falling back to transcode mode\n"); @@ -13124,7 +14515,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c } if (conference->conf_video_mode == CONF_VIDEO_MODE_TRANSCODE || conference->conf_video_mode == CONF_VIDEO_MODE_MUX) { - switch_set_flag(conference, CFLAG_TRANSCODE_VIDEO); + conference_set_flag(conference, CFLAG_TRANSCODE_VIDEO); } if (outcall_templ) { @@ -13167,18 +14558,18 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->perpetual_sound = switch_core_strdup(conference->pool, perpetual_sound); } - conference->mflags = MFLAG_CAN_SPEAK | MFLAG_CAN_HEAR | MFLAG_CAN_BE_SEEN; + conference->mflags[MFLAG_CAN_SPEAK] = conference->mflags[MFLAG_CAN_HEAR] = conference->mflags[MFLAG_CAN_BE_SEEN] = 1; if (!zstr(moh_sound) && switch_is_moh(moh_sound)) { conference->moh_sound = switch_core_strdup(conference->pool, moh_sound); } if (member_flags) { - set_mflags(member_flags, &conference->mflags); + set_mflags(member_flags, conference->mflags); } if (conference_flags) { - set_cflags(conference_flags, &conference->flags); + set_cflags(conference_flags, conference->flags); } if (!zstr(sound_prefix)) { @@ -13343,22 +14734,60 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c conference->uuid_str = switch_core_strdup(conference->pool, uuid_str); /* Set enter sound and exit sound flags so that default is on */ - switch_set_flag(conference, CFLAG_ENTER_SOUND); - switch_set_flag(conference, CFLAG_EXIT_SOUND); + conference_set_flag(conference, CFLAG_ENTER_SOUND); + conference_set_flag(conference, CFLAG_EXIT_SOUND); /* Activate the conference mutex for exclusivity */ switch_mutex_init(&conference->mutex, SWITCH_MUTEX_NESTED, conference->pool); switch_mutex_init(&conference->flag_mutex, SWITCH_MUTEX_NESTED, conference->pool); switch_thread_rwlock_create(&conference->rwlock, conference->pool); switch_mutex_init(&conference->member_mutex, SWITCH_MUTEX_NESTED, conference->pool); + switch_mutex_init(&conference->canvas_mutex, SWITCH_MUTEX_NESTED, conference->pool); switch_mutex_lock(globals.hash_mutex); - switch_set_flag(conference, CFLAG_INHASH); + conference_set_flag(conference, CFLAG_INHASH); switch_core_hash_insert(globals.conference_hash, conference->name, conference); switch_mutex_unlock(globals.hash_mutex); - if (conference->conf_video_mode == CONF_VIDEO_MODE_MUX && !conference->video_muxing_thread) { - launch_conference_video_muxing_thread(conference); + conference->super_canvas_label_layers = video_super_canvas_label_layers; + conference->super_canvas_show_all_layers = video_super_canvas_show_all_layers; + + if (video_canvas_count < 1) video_canvas_count = 1; + + if (conference->conf_video_mode == CONF_VIDEO_MODE_MUX) { + video_layout_t *vlayout = get_layout(conference, conference->video_layout_name, conference->video_layout_group); + + if (!vlayout) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_CRIT, "Cannot find layout\n"); + conference->video_layout_name = conference->video_layout_group = NULL; + conference_clear_flag(conference, CFLAG_VIDEO_MUXING); + } else { + int j; + + for (j = 0; j < video_canvas_count; j++) { + mcu_canvas_t *canvas = NULL; + + switch_mutex_lock(conference->canvas_mutex); + init_canvas(conference, vlayout, &canvas); + attach_canvas(conference, canvas, 0); + launch_conference_video_muxing_thread(conference, canvas, 0); + switch_mutex_unlock(conference->canvas_mutex); + } + + if (conference->canvas_count > 1) { + video_layout_t *svlayout = get_layout(conference, NULL, CONFERENCE_MUX_DEFAULT_SUPER_LAYOUT); + mcu_canvas_t *canvas = NULL; + + if (svlayout) { + switch_mutex_lock(conference->canvas_mutex); + init_canvas(conference, svlayout, &canvas); + set_canvas_bgcolor(canvas, conference->video_super_canvas_bgcolor); + attach_canvas(conference, canvas, 1); + launch_conference_video_muxing_thread(conference, canvas, 1); + switch_mutex_unlock(conference->canvas_mutex); + } + } + } } end: @@ -13417,7 +14846,7 @@ static uint32_t kickall_matching_var(conference_obj_t *conference, const char *v for (member = conference->members; member; member = member->next) { switch_channel_t *channel = NULL; - if (switch_test_flag(member, MFLAG_NOCHANNEL)) { + if (member_test_flag(member, MFLAG_NOCHANNEL)) { continue; } @@ -13425,8 +14854,8 @@ static uint32_t kickall_matching_var(conference_obj_t *conference, const char *v vval = switch_channel_get_variable(channel, var); if (vval && !strcmp(vval, val)) { - switch_set_flag_locked(member, MFLAG_KICKED); - switch_clear_flag_locked(member, MFLAG_RUNNING); + member_set_flag_locked(member, MFLAG_KICKED); + member_clear_flag_locked(member, MFLAG_RUNNING); switch_core_session_kill_channel(member->session, SWITCH_SIG_BREAK); r++; } @@ -13460,7 +14889,7 @@ static void call_setup_event_handler(switch_event_t *event) switch_event_t *var_event; switch_event_header_t *hp; - if (switch_test_flag(conference, CFLAG_RFC4579)) { + if (conference_test_flag(conference, CFLAG_RFC4579)) { char *key = switch_mprintf("conf_%s_%s_%s_%s", conference->name, conference->domain, ext, ext_domain); char *expanded = NULL, *ostr = dial_str;; @@ -13550,7 +14979,7 @@ static void conf_data_event_handler(switch_event_t *event) char *body = NULL; if (!zstr(name) && (conference = conference_find(name, domain))) { - if (switch_test_flag(conference, CFLAG_RFC4579)) { + if (conference_test_flag(conference, CFLAG_RFC4579)) { switch_event_dup(&revent, event); revent->event_id = SWITCH_EVENT_CONFERENCE_DATA; revent->flags |= EF_UNIQ_HEADERS; @@ -13703,7 +15132,7 @@ static switch_status_t dmachine_dispatcher(switch_ivr_dmachine_match_t *match) binding->action.expanded_data = NULL; } - switch_set_flag_locked(binding->member, MFLAG_FLUSH_BUFFER); + member_set_flag_locked(binding->member, MFLAG_FLUSH_BUFFER); return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/applications/mod_dptools/mod_dptools.c b/src/mod/applications/mod_dptools/mod_dptools.c index 0f6c8f606d..1aad6e73cd 100644 --- a/src/mod/applications/mod_dptools/mod_dptools.c +++ b/src/mod/applications/mod_dptools/mod_dptools.c @@ -1450,6 +1450,18 @@ SWITCH_STANDARD_APP(sched_cancel_function) static void base_set (switch_core_session_t *session, const char *data, switch_stack_t stack) { char *var, *val = NULL; + const char *what = "SET"; + + switch (stack) { + case SWITCH_STACK_PUSH: + what = "PUSH"; + break; + case SWITCH_STACK_UNSHIFT: + what = "UNSHIFT"; + break; + default: + break; + } if (zstr(data)) { switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "No variable name specified.\n"); @@ -1474,8 +1486,9 @@ static void base_set (switch_core_session_t *session, const char *data, switch_s expanded = switch_channel_expand_variables(channel, val); } - switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s SET [%s]=[%s]\n", switch_channel_get_name(channel), var, - expanded ? expanded : "UNDEF"); + switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_DEBUG, "%s %s [%s]=[%s]\n", + what, switch_channel_get_name(channel), var, expanded ? expanded : "UNDEF"); + switch_channel_add_variable_var_check(channel, var, expanded, SWITCH_FALSE, stack); if (expanded && expanded != val) { diff --git a/src/mod/endpoints/mod_verto/mod_verto.c b/src/mod/endpoints/mod_verto/mod_verto.c index 075b9e26d2..15d6bd473a 100644 --- a/src/mod/endpoints/mod_verto/mod_verto.c +++ b/src/mod/endpoints/mod_verto/mod_verto.c @@ -3259,7 +3259,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; + cJSON *obj = cJSON_CreateObject(), *screenShare = NULL, *dedEnc = NULL, *mirrorInput, *json_ptr = NULL; switch_core_session_t *session = NULL; switch_channel_t *channel; switch_event_t *var_event; @@ -3351,6 +3351,22 @@ static switch_bool_t verto__invite_func(const char *method, cJSON *params, jsock } } + if ((json_ptr = cJSON_GetObjectItem(dialog, "userVariables"))) { + cJSON * i; + + for(i = json_ptr->child; i; i = i->next) { + char *varname = switch_core_session_sprintf(session, "verto_dvar_%s", i->string); + + if (i->type == cJSON_True) { + switch_channel_set_variable(channel, varname, "true"); + } else if (i->type == cJSON_False) { + switch_channel_set_variable(channel, varname, "false"); + } else if (!zstr(i->string) && !zstr(i->valuestring)) { + switch_channel_set_variable(channel, varname, i->valuestring); + } + } + } + switch_snprintf(name, sizeof(name), "verto.rtc/%s", destination_number); switch_channel_set_name(channel, name); switch_channel_set_variable(channel, "jsock_uuid_str", jsock->uuid_str); diff --git a/src/switch_core_media.c b/src/switch_core_media.c index d9e6865b71..f015575533 100644 --- a/src/switch_core_media.c +++ b/src/switch_core_media.c @@ -4907,7 +4907,6 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi switch_core_session_request_video_refresh(session); while (switch_channel_up_nosig(channel)) { - int do_sleep = 0; int send_blank = 0; if (!switch_channel_test_flag(channel, CF_VIDEO)) { @@ -4916,15 +4915,11 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi continue; } - if (!smh->video_write_fh && !smh->video_read_fh && switch_core_session_media_flow(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY) { - do_sleep = 1; - } - if (!switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ) && (++xloops > 20 || switch_channel_test_flag(channel, CF_VIDEO_PASSIVE))) { switch_channel_set_flag(channel, CF_VIDEO_READY); } - if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE) || do_sleep) { + if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s Video thread paused. Echo is %s\n", switch_channel_get_name(session->channel), switch_channel_test_flag(channel, CF_VIDEO_ECHO) ? "on" : "off"); switch_thread_cond_wait(mh->cond, mh->cond_mutex); @@ -4933,7 +4928,7 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi switch_core_session_request_video_refresh(session); } - if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE) || do_sleep) { + if (switch_channel_test_flag(channel, CF_VIDEO_PASSIVE)) { continue; } @@ -4964,27 +4959,25 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) { switch_channel_set_flag(channel, CF_VIDEO_READY); - } else { - - //if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) { - status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); - - if (!SWITCH_READ_ACCEPTABLE(status)) { - switch_cond_next(); - continue; - } - - //if (switch_test_flag(read_frame, SFF_CNG)) { - // continue; - //} - //} - - //if (vloops < 300 && (vloops % 100) == 0) { - // switch_core_media_gen_key_frame(session); - //switch_core_session_request_video_refresh(session); - //} - } + + //if (!smh->video_write_fh || !switch_channel_test_flag(channel, CF_VIDEO_READY)) { + status = switch_core_session_read_video_frame(session, &read_frame, SWITCH_IO_FLAG_NONE, 0); + + if (!SWITCH_READ_ACCEPTABLE(status)) { + switch_cond_next(); + continue; + } + + //if (switch_test_flag(read_frame, SFF_CNG)) { + // continue; + //} + //} + + //if (vloops < 300 && (vloops % 100) == 0) { + // switch_core_media_gen_key_frame(session); + //switch_core_session_request_video_refresh(session); + //} vloops++; @@ -4998,6 +4991,10 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi switch_core_media_gen_key_frame(session); } + if (v_engine->smode == SWITCH_MEDIA_FLOW_SENDONLY) { + send_blank = 1; + } + if (switch_channel_test_flag(channel, CF_VIDEO_READY)) { switch_mutex_lock(mh->file_mutex); if (smh->video_write_fh && switch_channel_ready(session->channel) && switch_test_flag(smh->video_write_fh, SWITCH_FILE_OPEN)) { @@ -5008,8 +5005,10 @@ static void *SWITCH_THREAD_FUNC video_helper_thread(switch_thread_t *thread, voi } else if (wstatus != SWITCH_STATUS_BREAK && wstatus != SWITCH_STATUS_IGNORE) { smh->video_write_fh = NULL; } + send_blank = 0; } else if (smh->video_read_fh && switch_test_flag(smh->video_read_fh, SWITCH_FILE_OPEN) && read_frame->img) { switch_core_file_write_video(smh->video_read_fh, read_frame); + send_blank = 0; } switch_mutex_unlock(mh->file_mutex); } else if (switch_channel_test_flag(channel, CF_VIDEO_DECODED_READ)) {