]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-9742: [mod_conference,mod_cv] Refactor canvas zoom code #resolve
authorAnthony Minessale <anthm@freeswitch.org>
Thu, 1 Dec 2016 00:17:47 +0000 (18:17 -0600)
committerAnthony Minessale <anthm@freeswitch.org>
Thu, 9 Mar 2017 17:54:13 +0000 (11:54 -0600)
html5/verto/js/Makefile
html5/verto/js/src/jquery.verto.js
html5/verto/video_demo/js/verto-min.js
src/include/switch_frame.h
src/mod/applications/mod_conference/conference_api.c
src/mod/applications/mod_conference/conference_event.c
src/mod/applications/mod_conference/conference_video.c
src/mod/applications/mod_conference/mod_conference.c
src/mod/applications/mod_conference/mod_conference.h
src/mod/applications/mod_cv/mod_cv.cpp
src/mod/endpoints/mod_verto/mod_verto.c

index 05aa6617b010678503934684aceb3eaf6c34b635..ac2fcc9cd45089cabb02c13cde296f5b1bf9bc71 100644 (file)
@@ -22,6 +22,8 @@ install-maxdemo: all verto-max.js
 
 install-video_demo: all
        cp verto-min.js ../video_demo/js
+       cp verto-min.js ../video_demo-live_canvas/js
 
 install-video_maxdemo: all verto-max.js
        cp verto-max.js ../video_demo/js/verto-min.js
+       cp verto-max.js ../video_demo-live_canvas/js/verto-min.js
index 1c33b1392f522f34a2107b7de708d60f67128db7..cff5bf1b4178ccbb7bc436dc37e1d262e4580307 100644 (file)
             }
         });
 
+        verto.subscribe(conf.params.laData.infoChannel, {
+            handler: function(v, e) {
+                if (typeof(conf.params.infoCallback) === "function") {
+                    conf.params.infoCallback(v,e);
+                }
+            }
+        });
+
         verto.subscribe(conf.params.laData.chatChannel, {
             handler: function(v, e) {
                 if (typeof(conf.params.chatCallback) === "function") {
         if (conf.params.laData.chatChannel) {
             conf.verto.unsubscribe(conf.params.laData.chatChannel);
         }
+
+        if (conf.params.laData.infoChannel) {
+            conf.verto.unsubscribe(conf.params.laData.infoChannel);
+        }
     };
 
     function createMainModeratorMethods() {
 
         //$(".jsDataTable").width(confMan.params.hasVid ? "900px" : "800px");
 
+        verto.subscribe(confMan.params.laData.infoChannel, {
+            handler: function(v, e) {
+                if (typeof(confMan.params.infoCallback) === "function") {
+                    confMan.params.infoCallback(v,e);
+                }
+            }
+        });
+
        verto.subscribe(confMan.params.laData.chatChannel, {
            handler: function(v, e) {
                if (typeof(confMan.params.chatCallback) === "function") {
index e7e1782a92084e289da1edc57d5f8004aa792eca..ca36b1f4704915c9e3f1f82106c0e712ce5ccd41 100644 (file)
@@ -213,8 +213,9 @@ dt.fnClearTable();dt.fnAddData(genArray(obj));dt.fnAdjustColumnSizing();break;ca
 if(args.redraw>-1){dt.fnClearTable();dt.fnAddData(genArray(obj));}else{dt.fnAddData(genRow(args.data));}
 dt.fnAdjustColumnSizing();break;case"modify":if(!args.data){return;}
 dt.fnUpdate(genRow(args.data),index);dt.fnAdjustColumnSizing();break;case"del":dt.fnDeleteRow(index);dt.fnAdjustColumnSizing();break;case"clear":dt.fnClearTable();break;case"reorder":dt.fnClearTable();dt.fnAddData(genArray(obj));break;case"hide":jq.hide();break;case"show":jq.show();break;}}catch(err){console.error("ERROR: "+err);iserr++;}
-if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);}
-if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';}
+if(iserr){obj.errs++;if(obj.errs<3){obj.bootstrap(obj.user_obj);}}else{obj.errs=0;}};la.onChange(la,{action:"init"});};var CONFMAN_SERNO=1;$.verto.conf=function(verto,params){var conf=this;conf.params=$.extend({dialog:null,hasVid:false,laData:null,onBroadcast:null,onLaChange:null,onLaRow:null},params);conf.verto=verto;conf.serno=CONFMAN_SERNO++;createMainModeratorMethods();verto.subscribe(conf.params.laData.modChannel,{handler:function(v,e){if(conf.params.onBroadcast){conf.params.onBroadcast(verto,conf,e.data);}}});verto.subscribe(conf.params.laData.infoChannel,{handler:function(v,e){if(typeof(conf.params.infoCallback)==="function"){conf.params.infoCallback(v,e);}}});verto.subscribe(conf.params.laData.chatChannel,{handler:function(v,e){if(typeof(conf.params.chatCallback)==="function"){conf.params.chatCallback(v,e);}}});};$.verto.conf.prototype.modCommand=function(cmd,id,value){var conf=this;conf.verto.rpcClient.call("verto.broadcast",{"eventChannel":conf.params.laData.modChannel,"data":{"application":"conf-control","command":cmd,"id":id,"value":value}});};$.verto.conf.prototype.destroy=function(){var conf=this;conf.destroyed=true;conf.params.onBroadcast(conf.verto,conf,'destroy');if(conf.params.laData.modChannel){conf.verto.unsubscribe(conf.params.laData.modChannel);}
+if(conf.params.laData.chatChannel){conf.verto.unsubscribe(conf.params.laData.chatChannel);}
+if(conf.params.laData.infoChannel){conf.verto.unsubscribe(conf.params.laData.infoChannel);}};function createMainModeratorMethods(){$.verto.conf.prototype.listVideoLayouts=function(){this.modCommand("list-videoLayouts",null,null);};$.verto.conf.prototype.play=function(file){this.modCommand("play",null,file);};$.verto.conf.prototype.stop=function(){this.modCommand("stop",null,"all");};$.verto.conf.prototype.deaf=function(memberID){this.modCommand("deaf",parseInt(memberID));};$.verto.conf.prototype.undeaf=function(memberID){this.modCommand("undeaf",parseInt(memberID));};$.verto.conf.prototype.record=function(file){this.modCommand("recording",null,["start",file]);};$.verto.conf.prototype.stopRecord=function(){this.modCommand("recording",null,["stop","all"]);};$.verto.conf.prototype.snapshot=function(file){if(!this.params.hasVid){throw'Conference has no video';}
 this.modCommand("vid-write-png",null,file);};$.verto.conf.prototype.setVideoLayout=function(layout,canvasID){if(!this.params.hasVid){throw'Conference has no video';}
 if(canvasID){this.modCommand("vid-layout",null,[layout,canvasID]);}else{this.modCommand("vid-layout",null,layout);}};$.verto.conf.prototype.kick=function(memberID){this.modCommand("kick",parseInt(memberID));};$.verto.conf.prototype.muteMic=function(memberID){this.modCommand("tmute",parseInt(memberID));};$.verto.conf.prototype.muteVideo=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
 this.modCommand("tvmute",parseInt(memberID));};$.verto.conf.prototype.presenter=function(memberID){if(!this.params.hasVid){throw'Conference has no video';}
@@ -230,7 +231,7 @@ html+="<br>"+"<button class='ctlbtn' id='"+layer_set_id+"'>Set Layer</button>"+"
 jq.html(html);if(!jq.data("mouse")){$("#"+box_id).hide();}
 jq.mouseover(function(e){jq.data({"mouse":true});$("#"+box_id).show();});jq.mouseout(function(e){jq.data({"mouse":false});$("#"+box_id).hide();});$("#"+transfer_id).click(function(){var xten=prompt("Enter Extension");if(xten){confMan.modCommand("transfer",x,xten);}});$("#"+kick_id).click(function(){confMan.modCommand("kick",x);});$("#"+layer_set_id).click(function(){var cid=prompt("Please enter layer ID","");if(cid){confMan.modCommand("vid-layer",x,cid);}});$("#"+layer_next_id).click(function(){confMan.modCommand("vid-layer",x,"next");});$("#"+layer_prev_id).click(function(){confMan.modCommand("vid-layer",x,"prev");});$("#"+canvas_in_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-canvas",x,cid);}});$("#"+canvas_out_set_id).click(function(){var cid=prompt("Please enter canvas ID","");if(cid){confMan.modCommand("vid-watching-canvas",x,cid);}});$("#"+canvas_in_next_id).click(function(){confMan.modCommand("vid-canvas",x,"next");});$("#"+canvas_in_prev_id).click(function(){confMan.modCommand("vid-canvas",x,"prev");});$("#"+canvas_out_next_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"next");});$("#"+canvas_out_prev_id).click(function(){confMan.modCommand("vid-watching-canvas",x,"prev");});$("#"+tmute_id).click(function(){confMan.modCommand("tmute",x);});if(confMan.params.hasVid){$("#"+tvmute_id).click(function(){confMan.modCommand("tvmute",x);});$("#"+tvpresenter_id).click(function(){confMan.modCommand("vid-res-id",x,"presenter");});$("#"+tvfloor_id).click(function(){confMan.modCommand("vid-floor",x,"force");});$("#"+vbanner_id).click(function(){var text=prompt("Please enter text","");if(text){confMan.modCommand("vid-banner",x,escape(text));}});}
 $("#"+gainup_id).click(function(){confMan.modCommand("volume_in",x,"up");});$("#"+gaindn_id).click(function(){confMan.modCommand("volume_in",x,"down");});$("#"+volup_id).click(function(){confMan.modCommand("volume_out",x,"up");});$("#"+voldn_id).click(function(){confMan.modCommand("volume_out",x,"down");});return html;}
-var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready<br><br>");}else{$(confMan.params.mainModID).html("");}
+var atitle="";var awidth=0;verto.subscribe(confMan.params.laData.infoChannel,{handler:function(v,e){if(typeof(confMan.params.infoCallback)==="function"){confMan.params.infoCallback(v,e);}}});verto.subscribe(confMan.params.laData.chatChannel,{handler:function(v,e){if(typeof(confMan.params.chatCallback)==="function"){confMan.params.chatCallback(v,e);}}});if(confMan.params.laData.role==="moderator"){atitle="Action";awidth=600;if(confMan.params.mainModID){genMainMod($(confMan.params.mainModID));$(confMan.params.displayID).html("Moderator Controls Ready<br><br>");}else{$(confMan.params.mainModID).html("");}
 verto.subscribe(confMan.params.laData.modChannel,{handler:function(v,e){if(confMan.params.onBroadcast){confMan.params.onBroadcast(verto,confMan,e.data);}
 if(e.data["conf-command"]==="list-videoLayouts"){for(var j=0;j<confMan.canvasCount;j++){var vlselect_id="#confman_vl_select_"+j+"_"+confMan.serno;var vlayout_id="#confman_vid_layout_"+j+"_"+confMan.serno;var x=0;var options;$(vlselect_id).selectmenu({});$(vlselect_id).selectmenu("enable");$(vlselect_id).empty();$(vlselect_id).append(new Option("Choose a Layout","none"));if(e.data.responseData){var rdata=[];for(var i in e.data.responseData){rdata.push(e.data.responseData[i].name);}
 options=rdata.sort(function(a,b){var ga=a.substring(0,6)=="group:"?true:false;var gb=b.substring(0,6)=="group:"?true:false;if((ga||gb)&&ga!=gb){return ga?-1:1;}
index 54898eff3afff5ee9f47576abb81b5798fc9395a..ad739331c0d0245e87da7e7de2bc1abc498345f3 100644 (file)
 
 SWITCH_BEGIN_EXTERN_C
 
-struct switch_frame_geometry {
+typedef struct switch_frame_geometry {
        uint32_t w;
        uint32_t h;
        uint32_t x;
        uint32_t y;
        uint32_t z;
-       uint32_t m;
-};
+       uint32_t M;
+       uint32_t X;
+} switch_frame_geometry_t;
 
 /*! \brief An abstraction of a data frame */
        struct switch_frame {
index 6f07937145dd36585904b83b208f195d9d82d175..dbf05b21c241de135f0d752b536d6f68e5da64bb 100644 (file)
@@ -60,6 +60,7 @@ api_command_t conference_api_sub_commands[] = {
        {"file_seek", (void_fn_t) & conference_api_sub_file_seek, CONF_API_SUB_ARGS_SPLIT, "file_seek", "[+-]<val> [<member_id>]"},
        {"say", (void_fn_t) & conference_api_sub_say, CONF_API_SUB_ARGS_AS_ONE, "say", "<text>"},
        {"saymember", (void_fn_t) & conference_api_sub_saymember, CONF_API_SUB_ARGS_AS_ONE, "saymember", "<member_id> <text>"},
+       {"cam", (void_fn_t) & conference_api_sub_cam, CONF_API_SUB_ARGS_SPLIT, "cam", ""},
        {"stop", (void_fn_t) & conference_api_sub_stop, CONF_API_SUB_ARGS_SPLIT, "stop", "<[current|all|async|last]> [<member_id>]"},
        {"dtmf", (void_fn_t) & conference_api_sub_dtmf, CONF_API_SUB_MEMBER_TARGET, "dtmf", "<[member_id|all|last|non_moderator]> <digits>"},
        {"kick", (void_fn_t) & conference_api_sub_kick, CONF_API_SUB_MEMBER_TARGET, "kick", "<[member_id|all|last|non_moderator]> [<optional sound file>]"},
@@ -2009,6 +2010,262 @@ switch_status_t conference_api_sub_saymember(conference_obj_t *conference, switc
        return ret_status;
 }
 
+switch_status_t conference_api_sub_cam(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
+{
+       int x;
+       int canvas_id = -1;
+       int layer_id = -1;
+       int ok = 0;
+       mcu_canvas_t *canvas = NULL;
+       mcu_layer_t *layer = NULL;
+
+       if (!conference->canvases[0]) {
+               stream->write_function(stream, "Conference is not in mixing mode\n");
+               return SWITCH_STATUS_SUCCESS;
+       }
+
+       if (argc > 4) {
+               canvas_id = atoi(argv[2]);
+               layer_id = atoi(argv[3]);
+
+               if (canvas_id > -1 && layer_id > -1 && canvas_id < conference->canvas_count) {
+                       switch_mutex_lock(conference->canvas_mutex);
+                       canvas = conference->canvases[canvas_id];
+                       switch_mutex_lock(canvas->mutex);
+                       if (layer_id < canvas->total_layers) {
+                               layer = &canvas->layers[layer_id];
+                               ok = 1;
+                               for (x = 4; x < argc; x++) {
+                                       char *p = strchr(argv[x], '=');
+                                       int val = -1, isfalse = 0;
+                                       char *str_arg = NULL;
+                                       
+                                       if (p) {
+                                               *p++ = '\0';
+                                               if (!p) p = "";
+                                               
+                                               if (!strcasecmp(argv[x], "zoom") || !strcasecmp(argv[x], "pan")) {
+                                                       str_arg = p;
+                                                       if (switch_false(p)) {
+                                                               isfalse = 1;
+                                                       }
+                                               } else {
+                                                       if (switch_is_number(p)) {
+                                                               val = atoi(p);
+                                                       } else if (switch_true(p)) {
+                                                               val = 1;
+                                                       } else {
+                                                               val = 0;
+                                                               isfalse = 1;
+                                                       }
+                                               }
+                                       } else if (!strcasecmp(argv[x], "reset")) {
+                                               str_arg = "true";
+                                       }
+
+                                       if (val < 0 && !str_arg) {
+                                               stream->write_function(stream, "-ERR invalid val for option [%s]\n", argv[x]);
+                                               continue;
+                                       }
+
+                                       if (!strcasecmp(argv[x], "autozoom")) {
+                                               if ((layer->cam_opts.autozoom = val)) {
+                                                       layer->cam_opts.manual_zoom = 0;
+                                               }
+                                               
+                                       } else if (!strcasecmp(argv[x], "autopan")) {
+                                               if ((layer->cam_opts.autopan = val)) {
+                                                       layer->cam_opts.manual_pan = 0;
+                                               }
+                                       } else if (!strcasecmp(argv[x], "zoom_factor")) {
+                                               if (val > 0 && val < 5) {
+                                                       layer->cam_opts.zoom_factor = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-4\n", argv[x]);
+                                               }
+                                       } else if (!strcasecmp(argv[x], "snap_factor")) {
+                                               if (val > 0 && val < layer->screen_w / 2) {
+                                                       layer->cam_opts.snap_factor = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-%d\n", argv[x], layer->screen_w / 2);
+                                               }
+                                       } else if (!strcasecmp(argv[x], "zoom_move_factor")) {
+                                               if (val > 0 && val < layer->screen_w / 2) {
+                                                       layer->cam_opts.zoom_move_factor = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-4\n", argv[x], layer->screen_w / 2);
+                                               }
+                                       } else if (!strcasecmp(argv[x], "pan_speed")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.pan_speed = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "pan_accel_speed")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.pan_accel_speed = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "pan_accel_min")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.pan_accel_min = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "zoom_speed")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.zoom_speed = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "zoom_accel_speed")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.zoom_accel_speed = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "zoom_accel_min")) {
+                                               if (val > 0 && val < 100) {
+                                                       layer->cam_opts.zoom_accel_min = val;
+                                               } else {
+                                                       stream->write_function(stream, "-ERR invalid val for option [%s] must be 1-100\n");
+                                               }
+                                       } else if (!strcasecmp(argv[x], "reset")) {
+                                               conference_video_reset_layer_cam(layer);
+                                       } else if (!strcasecmp(argv[x], "pan")) {
+                                               char *x_val = NULL, *y_val = NULL;
+                                               int x = -1, y = -1;
+                                               int on = 0;
+
+                                               if (isfalse) {
+                                                       layer->pan_geometry.x = 0;
+                                                       layer->pan_geometry.y = 0;
+                                                       layer->cam_opts.manual_pan = 0;
+                                               } else {
+                                                       
+                                                       if (str_arg) {
+                                                               char *p = strchr(str_arg, ':');
+                                                               
+                                                               if (p) {
+                                                                       *p++ = '\0';
+
+                                                                       if (*str_arg == 'x') {
+                                                                               x_val = p;
+                                                                       } else if (*str_arg == 'y') {
+                                                                               y_val = p;
+                                                                       }
+                                                               }
+                                                       }
+
+                                                       if (!x_val && !y_val) {
+                                                               stream->write_function(stream, "-ERR invalid val for pan\n");
+                                                       }
+
+                                                       if (x_val) x = atoi(x_val);
+                                                       if (y_val) y = atoi(y_val);
+                                                       
+                                                       if (x_val && strrchr(x_val, 'i')) {
+                                                               int nx = (int)layer->pan_geometry.x + x;
+
+                                                               if (nx < 0) nx = 0;
+                                                               if (nx + layer->pan_geometry.w > layer->img->d_w) nx = layer->img->d_w - layer->pan_geometry.w;
+                                                               
+                                                               layer->pan_geometry.x = nx;
+                                                               on++;
+                                                       } else if (x > -1) {
+                                                               layer->pan_geometry.x = x;
+                                                               on++;
+                                                       }
+                                                       
+                                                       if (y_val && strrchr(y_val, 'i')) {
+                                                               int ny = (int)layer->pan_geometry.y + y;
+
+                                                               if (ny < 0) ny = 0;
+                                                               if (ny + layer->pan_geometry.h > layer->img->d_h) ny = layer->img->d_h - layer->pan_geometry.h;
+                                                               
+                                                               layer->pan_geometry.y = ny;
+                                                               on++;
+                                                       } else if (y > -1) {
+                                                               layer->pan_geometry.y = y;
+                                                               on++;
+                                                       }       
+                                                       
+
+                                                       if (on) {
+                                                               layer->cam_opts.manual_pan = 1;
+                                                               layer->cam_opts.autopan = 0;
+                                                               stream->write_function(stream, "+OK PAN %d,%d\n", layer->pan_geometry.x, layer->pan_geometry.y);
+                                                       }
+                                               }
+
+                                               
+                                       } else if (!strcasecmp(argv[x], "zoom")) {
+                                               if (str_arg && !isfalse) {
+                                                       char *array[4] = {0};
+                                                       int iray[4] = {0};
+                                                       int ac;
+                                                       
+                                                       if ((ac = switch_split(str_arg, ':', array)) >= 3) {
+                                                               int i;
+
+                                                               for (i = 0; i < ac; i++) {
+                                                                       int tmp = atoi(array[i]);
+
+                                                                       if (tmp < 0) break;
+                                                                       iray[i] = tmp;
+                                                               }
+
+                                                               if (i == ac) {
+                                                                       layer->cam_opts.manual_zoom = 1;
+                                                                       layer->cam_opts.autozoom = 0;
+
+                                                                       layer->zoom_geometry.x = iray[0];
+                                                                       layer->zoom_geometry.y = iray[1];
+                                                                       layer->zoom_geometry.w = iray[2];
+                                                                       if (iray[3]) {
+                                                                               layer->zoom_geometry.h = iray[3];
+                                                                       } else {
+                                                                               layer->zoom_geometry.h = iray[2];
+                                                                       }
+                                                                       
+                                                                       layer->crop_x = iray[0];
+                                                                       layer->crop_y = iray[1];
+                                                                       layer->crop_w = iray[2];
+                                                                       layer->crop_h = iray[2];
+                                                                       layer->pan_geometry = layer->zoom_geometry;
+                                                               } else {
+                                                                       ok = 0;
+                                                               }
+                                                       }
+                                               } else {
+                                                       layer->zoom_geometry.x = 0;
+                                                       layer->zoom_geometry.y = 0;
+                                                       layer->zoom_geometry.w = 0;
+                                                       layer->zoom_geometry.h = 0;
+                                                       layer->cam_opts.manual_zoom = 0;
+                                               }
+                                       } else {
+                                               stream->write_function(stream, "-ERR invalid option [%s]\n", argv[x]);
+                                       }
+                               }
+                       }
+                       switch_mutex_unlock(canvas->mutex);
+                       switch_mutex_unlock(conference->canvas_mutex);
+
+               }
+       }
+
+       if (ok) {
+               stream->write_function(stream, "+OK\n");
+       } else {
+               stream->write_function(stream, "-ERR invalid args\n");
+       }
+
+
+       return SWITCH_STATUS_SUCCESS;
+}
+
 switch_status_t conference_api_sub_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
 {
        uint8_t current = 0, all = 0, async = 0;
index 79f487fae98c03fe398eb6dc3fc55226270b4cf0..6325311c3213991fce6f1ad2e1a2952a75bf981b 100644 (file)
@@ -237,14 +237,22 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json
                const void *vvar;
                cJSON *array = cJSON_CreateArray();
                conference_obj_t *conference = NULL;
+               int i;
+
                if ((conference = conference_find(conference_name, NULL))) {
                        switch_mutex_lock(conference_globals.setup_mutex);
+
+                       for (i = 0; i <= conference->canvas_count; i++) {
+                               if (conference->canvases[i]) {
+                                       conference_event_adv_layout(conference, conference->canvases[i], conference->canvases[i]->vlayout);
+                               }
+                       }
+
                        if (conference->layout_hash) {
                                for (hi = switch_core_hash_first(conference->layout_hash); hi; hi = switch_core_hash_next(&hi)) {
                                        video_layout_t *vlayout;
                                        cJSON *obj = cJSON_CreateObject();
                                        cJSON *resarray = cJSON_CreateArray();
-                                       int i;
 
                                        switch_core_hash_this(hi, &vvar, NULL, &val);
                                        vlayout = (video_layout_t *)val;
@@ -292,6 +300,83 @@ void conference_event_mod_channel_handler(const char *event_channel, cJSON *json
                        switch_thread_rwlock_unlock(conference->rwlock);
                }
                addobj = array;
+       } else if (!strcasecmp(action, "click-layer")) {
+       } else if (!strcasecmp(action, "shift-click-layer")) {
+       } else if (!strcasecmp(action, "reset-layer") || !strcasecmp(action, "layer-pan-x") || !strcasecmp(action, "layer-pan-y")) {
+               cJSON *v;
+               int layer_id = 0, canvas_id = 0, metric = 0, absolute = 0;
+               const char *i = "i", *xy = "";
+
+               if ((v = cJSON_GetObjectItem(data, "layerID"))) {
+                       layer_id = v->valueint;
+               }
+
+               if ((v = cJSON_GetObjectItem(data, "canvasID"))) {
+                       canvas_id = v->valueint;
+               }
+
+               if ((v = cJSON_GetObjectItem(data, "metric"))) {
+                       metric = v->valueint;
+               }
+
+               if ((v = cJSON_GetObjectItem(data, "absolute"))) {
+                       if ((absolute = v->valueint)) {
+                               i = "";
+                       }
+               }
+
+               if (canvas_id > -1 && layer_id > -1) {
+                       if (!strcasecmp(action, "layer-pan-x")) {
+                               xy = "x";
+                       } else if (!strcasecmp(action, "layer-pan-y")) {
+                               xy = "y";
+                       }
+
+                       if (!strcasecmp(action, "reset-layer")) {
+                               exec = switch_mprintf("%s cam %d %d reset", conference_name, canvas_id, layer_id);
+                       } else {
+                               exec = switch_mprintf("%s cam %d %d pan=%s:%d%s", conference_name, canvas_id, layer_id, xy, metric, i);
+                       }
+               }
+               
+
+       } else if (!strcasecmp(action, "zoom-layer")) {
+               cJSON *v;
+               int layer_id = -1, canvas_id = -1, x = -1, y = -1, w = -1, h = -1;
+
+               if ((v = cJSON_GetObjectItem(data, "layerID"))) {
+                       layer_id = v->valueint;
+               }
+
+               if ((v = cJSON_GetObjectItem(data, "canvasID"))) {
+                       canvas_id = v->valueint;
+               }
+               
+               
+               if ((v = cJSON_GetObjectItem(data, "dimensions"))) {
+                       cJSON *d;
+
+                       if ((d = cJSON_GetObjectItem(v, "w"))) {
+                               w = d->valueint;
+                       }
+
+                       if ((d = cJSON_GetObjectItem(v, "h"))) {
+                               h = d->valueint;
+                       }
+
+                       if ((d = cJSON_GetObjectItem(v, "x"))) {
+                               x = d->valueint;
+                       }
+
+                       if ((d = cJSON_GetObjectItem(v, "y"))) {
+                               y = d->valueint;
+                       }
+               }
+
+               if (canvas_id > -1 && layer_id > -1 && x > -1 && y > -1 && w > -1 && h > -1) {
+                       exec = switch_mprintf("%s cam %d %d zoom=%d:%d:%d:%d snap_factor=1 zoom_factor=1", conference_name, canvas_id, layer_id, x, y, w, h);
+               }
+               
        }
 
        if (exec) {
@@ -486,6 +571,59 @@ void conference_event_la_command_handler(switch_live_array_t *la, const char *cm
 {
 }
 
+void conference_event_adv_layout(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout)
+{
+       cJSON *msg, *data, *obj;
+       int i = 0;
+
+       msg = cJSON_CreateObject();
+       data = json_add_child_obj(msg, "eventData", NULL);
+
+       cJSON_AddItemToObject(msg, "eventChannel", cJSON_CreateString(conference->info_event_channel));
+       cJSON_AddItemToObject(data, "contentType", cJSON_CreateString("layout-info"));
+       
+       switch_thread_rwlock_rdlock(canvas->video_rwlock);
+       switch_mutex_lock(canvas->mutex);
+       
+       if ((obj = get_canvas_info(canvas))) {
+               cJSON *array = cJSON_CreateArray();
+
+               for (i = 0; i < vlayout->layers; i++) {
+                       cJSON *layout = cJSON_CreateObject();
+                       int scale = vlayout->images[i].scale;
+                       int hscale = vlayout->images[i].hscale ? vlayout->images[i].hscale : scale;
+                       
+                       cJSON_AddItemToObject(layout, "x", cJSON_CreateNumber(vlayout->images[i].x));
+                       cJSON_AddItemToObject(layout, "y", cJSON_CreateNumber(vlayout->images[i].y));
+                       cJSON_AddItemToObject(layout, "scale", cJSON_CreateNumber(vlayout->images[i].scale));
+                       cJSON_AddItemToObject(layout, "hscale", cJSON_CreateNumber(hscale));
+                       cJSON_AddItemToObject(layout, "scale", cJSON_CreateNumber(scale));
+                       cJSON_AddItemToObject(layout, "zoom", cJSON_CreateNumber(vlayout->images[i].zoom));
+                       cJSON_AddItemToObject(layout, "border", cJSON_CreateNumber(vlayout->images[i].border));
+                       cJSON_AddItemToObject(layout, "floor", cJSON_CreateNumber(vlayout->images[i].floor));
+                       cJSON_AddItemToObject(layout, "overlap", cJSON_CreateNumber(vlayout->images[i].overlap));
+                       cJSON_AddItemToObject(layout, "screenWidth", cJSON_CreateNumber((uint32_t)(canvas->img->d_w * scale / VIDEO_LAYOUT_SCALE)));
+                       cJSON_AddItemToObject(layout, "screenHeight", cJSON_CreateNumber((uint32_t)(canvas->img->d_h * hscale / VIDEO_LAYOUT_SCALE)));
+                       cJSON_AddItemToObject(layout, "xPOS", cJSON_CreateNumber((int)(canvas->img->d_w * vlayout->images[i].x / VIDEO_LAYOUT_SCALE)));
+                       cJSON_AddItemToObject(layout, "yPOS", cJSON_CreateNumber((int)(canvas->img->d_h * vlayout->images[i].y / VIDEO_LAYOUT_SCALE)));
+                       cJSON_AddItemToObject(layout, "resID", cJSON_CreateString(vlayout->images[i].res_id));
+                       cJSON_AddItemToObject(layout, "audioPOS", cJSON_CreateString(vlayout->images[i].audio_position));
+                       cJSON_AddItemToArray(array, layout);
+               }
+               
+
+               cJSON_AddItemToObject(obj, "canvasLayouts", array);
+
+               cJSON_AddItemToObject(obj, "scale", cJSON_CreateNumber(VIDEO_LAYOUT_SCALE));
+               cJSON_AddItemToObject(data, "canvasInfo", obj);
+       }
+       
+       switch_mutex_unlock(canvas->mutex);
+       switch_thread_rwlock_unlock(canvas->video_rwlock);
+
+       switch_event_channel_broadcast(conference->info_event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
+
+}
 
 void conference_event_adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join)
 {
@@ -501,6 +639,7 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
                switch_event_t *variables;
                switch_event_header_t *hp;
                char idstr[128] = "";
+               int i;
 
                snprintf(idstr, sizeof(idstr), "%d", member->id);
                msg = cJSON_CreateObject();
@@ -526,6 +665,7 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
                }
 
                cJSON_AddItemToObject(data, "chatChannel", cJSON_CreateString(conference->chat_event_channel));
+               cJSON_AddItemToObject(data, "infoChannel", cJSON_CreateString(conference->info_event_channel));
 
                switch_core_get_variables(&variables);
                for (hp = variables->headers; hp; hp = hp->next) {
@@ -538,12 +678,19 @@ void conference_event_adv_la(conference_obj_t *conference, conference_member_t *
                }
                switch_event_destroy(&variables);
 
-               switch_event_channel_broadcast(event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
-
                if (cookie) {
                        switch_event_channel_permission_modify(cookie, conference->la_event_channel, join);
                        switch_event_channel_permission_modify(cookie, conference->mod_event_channel, join);
                        switch_event_channel_permission_modify(cookie, conference->chat_event_channel, join);
+                       switch_event_channel_permission_modify(cookie, conference->info_event_channel, join);
+               }
+
+               switch_event_channel_broadcast(event_channel, &msg, "mod_conference", conference_globals.event_channel_id);
+
+               for (i = 0; i <= conference->canvas_count; i++) {
+                       if (conference->canvases[i]) {
+                               conference_event_adv_layout(conference, conference->canvases[i], conference->canvases[i]->vlayout);
+                       }
                }
        }
 }
index 8d0d0e98a0aed963247a656e3901adfc46e5774d..6c8e744f228106ba49f8b880130b797028b1d4ac 100644 (file)
@@ -349,6 +349,45 @@ void conference_video_clear_layer(mcu_layer_t *layer)
 
 }
 
+static void set_default_cam_opts(mcu_layer_t *layer)
+{
+       //layer->cam_opts.autozoom = 1;
+       //layer->cam_opts.autopan = 1;
+       layer->cam_opts.manual_pan = 0;
+       layer->cam_opts.manual_zoom = 0;
+       layer->cam_opts.zoom_factor = 3;
+       layer->cam_opts.snap_factor = 25;
+       layer->cam_opts.zoom_move_factor = 125;
+       layer->cam_opts.pan_speed = 3;
+       layer->cam_opts.pan_accel_speed = 10;
+       layer->cam_opts.pan_accel_min = 50;
+       layer->cam_opts.zoom_speed = 3;
+       layer->cam_opts.zoom_accel_speed = 10;
+       layer->cam_opts.zoom_accel_min = 50;
+}
+
+
+void conference_video_reset_layer_cam(mcu_layer_t *layer)
+{
+       layer->crop_x = 0;
+       layer->crop_y = 0;
+       layer->crop_w = 0;
+       layer->crop_h = 0;
+       layer->last_w = 0;
+       layer->last_h = 0;
+       layer->img_count = 0;
+
+       memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
+       memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
+       memset(&layer->pan_geometry, 0, sizeof(layer->pan_geometry));
+       memset(&layer->zoom_geometry, 0, sizeof(layer->zoom_geometry));
+       memset(&layer->last_geometry, 0, sizeof(layer->last_geometry));
+
+       set_default_cam_opts(layer);
+
+
+}
+
 void conference_video_reset_layer(mcu_layer_t *layer)
 {
        switch_img_free(&layer->banner_img);
@@ -361,7 +400,7 @@ void conference_video_reset_layer(mcu_layer_t *layer)
        layer->is_avatar = 0;
        layer->need_patch = 0;
 
-       memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
+       conference_video_reset_layer_cam(layer);
 
        if (layer->geometry.overlap) {
                layer->canvas->refresh = 1;
@@ -375,36 +414,73 @@ void conference_video_reset_layer(mcu_layer_t *layer)
        switch_img_free(&layer->cur_img);
 }
 
-static void set_pan(mcu_layer_t *layer, int crop_point, int max_width)
+static void set_pan(int crop_point, int *target_point, int accel_speed, int accel_min, int speed)
 {
-       if (layer->crop_point <= 0 || layer->crop_point > max_width) {
-               layer->crop_point = crop_point;
-       } else if (crop_point > layer->crop_point) {
-               if (crop_point - layer->crop_point > 25) {
-                       layer->crop_point += 5;
+
+       if (crop_point > *target_point) {
+               if ((crop_point - *target_point) > accel_min) {
+                       *target_point += accel_speed;
                } else {
-                       layer->crop_point++;
+                       *target_point += speed;
                }
 
-               if (crop_point < layer->crop_point) {
-                       layer->crop_point = crop_point;
+               if (*target_point > crop_point) {
+                       *target_point = crop_point;
                }
-       } else if (crop_point < layer->crop_point) {
-               if (layer->crop_point - crop_point > 25) {
-                       layer->crop_point -= 5;
+       } else if (crop_point < *target_point) {
+
+               if ((*target_point - crop_point) > accel_min) {
+                       *target_point -= accel_speed;
                } else {
-                       layer->crop_point--;
+                       *target_point -= speed;
                }
 
-               if (crop_point > layer->crop_point) {
-                       layer->crop_point = crop_point;
+               if (*target_point < crop_point) {
+                       *target_point = crop_point;
                }
        }
 }
 
+static void set_bounds(int *x, int *y, int img_w, int img_h, int crop_w, int crop_h)
+{
+       int crop_x = *x;
+       int crop_y = *y;
+       
+       if (crop_x < 0) {
+               crop_x = 0;
+       }
+
+       if (crop_y < 0) {
+               crop_y = 0;
+       }
+       
+       if (crop_x + crop_w > img_w) {
+               crop_x = img_w - crop_w;
+       }
+       
+       if (crop_y + crop_h > img_h) {
+               crop_y = img_h - crop_h;
+       }
+
+       if (crop_x < 0) {
+               crop_x = 0;
+       }
+
+       if (crop_y < 0) {
+               crop_y = 0;
+       }
+
+       *x = crop_x;
+       *y = crop_y;
+
+
+}
+
 void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze)
 {
        switch_image_t *IMG, *img;
+       int img_changed = 0;
 
        switch_mutex_lock(layer->canvas->mutex);
 
@@ -417,6 +493,47 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
                switch_mutex_unlock(layer->canvas->mutex);
                return;
        }
+       //printf("RAW %dx%d\n", img->d_w, img->d_h);
+
+       if (layer->img_count++ == 0 || layer->last_w != img->d_w || layer->last_h != img->d_h) {
+               double change_scale;
+
+               if (img->d_w && layer->last_w) {
+                       if (img->d_w < layer->last_w) {
+                               change_scale = layer->last_w / img->d_w;
+                       } else {
+                               change_scale = img->d_w / layer->last_w;
+                       }
+
+                       layer->crop_x = (int)(layer->crop_x * change_scale);
+                       layer->crop_y = (int)(layer->crop_y * change_scale);
+                       layer->crop_w = (int)(layer->crop_w * change_scale);
+                       layer->crop_h = (int)(layer->crop_h * change_scale);
+
+                       layer->zoom_geometry.x = (int)(layer->zoom_geometry.x * change_scale);
+                       layer->zoom_geometry.y = (int)(layer->zoom_geometry.y * change_scale);
+                       layer->zoom_geometry.w = (int)(layer->zoom_geometry.w * change_scale);
+                       layer->zoom_geometry.h = (int)(layer->zoom_geometry.h * change_scale);
+
+
+                       layer->pan_geometry.x = (int)(layer->pan_geometry.x * change_scale);
+                       layer->pan_geometry.y = (int)(layer->pan_geometry.y * change_scale);
+                       layer->pan_geometry.w = (int)(layer->pan_geometry.w * change_scale);
+                       layer->pan_geometry.h = (int)(layer->pan_geometry.h * change_scale);
+
+               }
+
+               memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
+               //memset(&layer->zoom_geometry, 0, sizeof(layer->zoom_geometry));
+               //memset(&layer->pan_geometry, 0, sizeof(layer->pan_geometry));
+               memset(&layer->last_geometry, 0, sizeof(layer->last_geometry));
+
+               img_changed = 1;
+       }
+
+       layer->last_w = img->d_w;
+       layer->last_h = img->d_h;
+
 
        if (layer->bugged) {
                if (layer->member_id > -1 && layer->member && switch_thread_rwlock_tryrdlock(layer->member->rwlock) == SWITCH_STATUS_SUCCESS) {
@@ -427,7 +544,39 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
                        switch_thread_rwlock_unlock(layer->member->rwlock);
                }
 
+               if ((!layer->manual_geometry.w || 
+                        (layer->last_geometry.x && abs(layer->manual_geometry.x - layer->last_geometry.x) > layer->cam_opts.zoom_move_factor) ||
+                        (layer->last_geometry.y && abs(layer->manual_geometry.y - layer->last_geometry.y) > layer->cam_opts.zoom_move_factor) ||
+                        (layer->last_geometry.w && abs(layer->manual_geometry.w - layer->last_geometry.w) > layer->cam_opts.zoom_move_factor / 2))) {
+                       switch_event_t *event;
+
+                       if (switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) {
+                               switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "action", "movement-detection");
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "member_id", "%d", layer->member_id);
+
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_x", "%d", layer->manual_geometry.x);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_y", "%d", layer->manual_geometry.y);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_w", "%d", layer->manual_geometry.w);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "last_h", "%d", layer->manual_geometry.h);
+
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_x", "%d", layer->bug_frame.geometry.x);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_y", "%d", layer->bug_frame.geometry.y);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_w", "%d", layer->bug_frame.geometry.w);
+                               switch_event_add_header(event, SWITCH_STACK_BOTTOM, "new_h", "%d", layer->bug_frame.geometry.h);
+
+                               switch_event_fire(&event);
+                       }
+                       
+                       layer->manual_geometry = layer->bug_frame.geometry;
+               }
+               
                layer->bugged = 0;
+       } else {
+               if (layer->bug_frame.geometry.w) {
+                       memset(&layer->bug_frame, 0, sizeof(layer->bug_frame));
+               }
+               layer->cam_opts.autozoom = 0;
+               layer->cam_opts.autopan = 0;
        }
 
        if (layer->clear) {
@@ -446,7 +595,7 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
                int x_pos = layer->x_pos;
                int y_pos = layer->y_pos;
                switch_size_t img_addr = 0;
-
+               switch_frame_geometry_t *use_geometry = &layer->auto_geometry;
                img_w = layer->screen_w = (uint32_t)(IMG->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE);
                img_h = layer->screen_h = (uint32_t)(IMG->d_h * layer->geometry.hscale / VIDEO_LAYOUT_SCALE);
 
@@ -456,76 +605,184 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
 
                img_addr = (switch_size_t)img;
 
-               if (layer->last_img_addr != img_addr && layer->geometry.zoom) {
-                       uint32_t new_w = 0, new_h = 0;
-                       int crop_point = 0;
+               
+               if (layer->last_img_addr != img_addr && (layer->geometry.zoom || layer->cam_opts.autozoom || 
+                                                                                                layer->cam_opts.autopan || layer->cam_opts.manual_pan || layer->cam_opts.manual_zoom)) {
+
                        double scale = 1;
+                       int crop_x = 0, crop_y = 0, crop_w = 0, crop_h = 0, zoom_w = 0, zoom_h = 0;
+                       int can_pan = 0;
+                       int can_zoom = 0;
+                       int did_zoom = 0;
 
                        if (screen_aspect < img_aspect) {
-
                                if (img->d_h != layer->screen_h) {
                                        scale = (double)layer->screen_h / img->d_h;
                                }
+                       } else if (screen_aspect > img_aspect) {
+                               if (img->d_w != layer->screen_w) {
+                                       scale = (double)layer->screen_w / img->d_w;
+                               }
+                       }
 
-                               new_w = (uint32_t)((double)layer->screen_w / scale);
-                               new_h = (uint32_t)((double)layer->screen_h / scale);
+                       if (scale == 1) {
+                               crop_w = img->d_w;
+                               crop_h = img->d_h;
+                       } else {
+                               crop_w = (uint32_t)((double)layer->screen_w / scale);
+                               crop_h = (uint32_t)((double)layer->screen_h / scale);
+                       }
 
-                               if (layer->bug_frame.geometry.w) {
-                                       //new_w = layer->bug_frame.geometry.w * 2;
-                                       //new_h = new_w / screen_aspect;
-                                       crop_point = switch_round_to_step(layer->bug_frame.geometry.x - (new_w / 2), 25);
-                               } else {
-                                       crop_point = (img->d_w - new_w) / 2;
-                               }
+                       //if (layer->bug_frame.geometry.X > 90) {
+                       //      memset(&layer->auto_geometry, 0, sizeof(layer->auto_geometry));
+                       //}
+                       
+                       if (layer->cam_opts.autopan) {
+                               can_pan = layer->bug_frame.geometry.w && (layer->geometry.zoom || layer->cam_opts.manual_zoom);
+                       } else {
+                               can_pan = layer->cam_opts.manual_pan && (layer->geometry.zoom || layer->cam_opts.manual_zoom);
+                       }
 
-                               if (crop_point < 1) {
-                                       crop_point = 1;
-                               } else if (crop_point > img->d_w - new_w) {
-                                       crop_point = img->d_w - new_w;
-                               }
+                       if (layer->cam_opts.autozoom) {
+                               can_zoom = layer->bug_frame.geometry.w;
+                       } else {
+                               can_zoom = layer->cam_opts.manual_zoom && layer->zoom_geometry.w;
+                       }
 
-                               set_pan(layer, crop_point, img->d_w - new_w);
+                       //printf("CHECK %d %d,%d %d,%d %d/%d\n", layer->auto_geometry.w, 
+                       //         layer->last_geometry.x, layer->last_geometry.y,
+                       //         layer->auto_geometry.x, layer->auto_geometry.y,
+                       //         abs(layer->auto_geometry.x - layer->last_geometry.x), 
+                       //         abs(layer->auto_geometry.y - layer->last_geometry.y));
+
+                       if ((layer->cam_opts.autozoom || layer->cam_opts.autopan) &&
+                               (!layer->auto_geometry.w || 
+                                (layer->last_geometry.x && abs(layer->auto_geometry.x - layer->last_geometry.x) > layer->cam_opts.zoom_move_factor) ||
+                                (layer->last_geometry.y && abs(layer->auto_geometry.y - layer->last_geometry.y) > layer->cam_opts.zoom_move_factor) ||
+                                (layer->last_geometry.w && abs(layer->auto_geometry.w - layer->last_geometry.w) > layer->cam_opts.zoom_move_factor / 2))) {
+                               
+                               layer->auto_geometry = layer->bug_frame.geometry;
+                       }
 
-                               if (layer->crop_point > 0) {
-                                       switch_img_set_rect(img, layer->crop_point, 0, new_w, new_h);
-                                       img_aspect = (double) img->d_w / img->d_h;
+                       if (can_zoom) {
+
+                               if (layer->cam_opts.autozoom) {
+                                       use_geometry = &layer->auto_geometry;
+                               } else {
+                                       use_geometry = &layer->zoom_geometry;
                                }
 
-                       } else if (screen_aspect > img_aspect) {
+                               zoom_w = use_geometry->w * layer->cam_opts.zoom_factor;
+                               zoom_h = zoom_w / screen_aspect; 
+                               
+                               if (zoom_w < crop_w && zoom_h < crop_h) {
+                                       int c_x = use_geometry->x;
+                                       int c_y = use_geometry->y;
+                                       
+                                       crop_w = zoom_w;
+                                       crop_h = zoom_h;
+                                       
+                                       //crop_w = switch_round_to_step(crop_w, layer->cam_opts.snap_factor);
+                                       //crop_h = switch_round_to_step(crop_h, layer->cam_opts.snap_factor);
 
-                               if (img->d_w != layer->screen_w) {
-                                       scale = (double)layer->screen_w / img->d_w;
-                               }
+                                       if (layer->cam_opts.autozoom) {
+                                               did_zoom = 1;
+                                       }
+                                       
+
+                                       if (layer->cam_opts.autozoom) {
+                                               c_x = switch_round_to_step(c_x, layer->cam_opts.snap_factor);
+                                               c_y = switch_round_to_step(c_y, layer->cam_opts.snap_factor);
+                                               
+                                               crop_x = c_x - (crop_w / 2);
+                                               crop_y = c_y - (crop_h / 2);
+                                       } else {
+                                               crop_x = c_x;
+                                               crop_y = c_y;
+                                       }
+                                       
+                                       set_bounds(&crop_x, &crop_y, img->d_w, img->d_h, crop_w, crop_h);
 
+                                       //printf("ZOOM %d,%d %d,%d %dx%d\n", crop_x, crop_y, c_x, c_y, zoom_w, zoom_h);
+                               }
+                       }
+                               
 
-                               new_w = (uint32_t)((double)layer->screen_w / scale);
-                               new_h = (uint32_t)((double)layer->screen_h / scale);
+                       if (!did_zoom) {
 
-                               if (layer->bug_frame.geometry.w) {
-                                       crop_point = layer->bug_frame.geometry.y - (new_h / 2);
+                               if (layer->cam_opts.autopan) {
+                                       use_geometry = &layer->auto_geometry;
                                } else {
-                                       crop_point = (img->d_h - new_h) / 2;
+                                       use_geometry = &layer->pan_geometry;
                                }
 
-                               if (crop_point < 1) {
-                                       crop_point = 1;
-                               } else if (crop_point > img->d_h - new_h) {
-                                       crop_point = img->d_h - new_h;
+                               if (can_pan) {
+                                       if (layer->cam_opts.autopan) {
+                                               crop_x = use_geometry->x - (crop_w / 2);
+                                       } else {
+                                               crop_x = use_geometry->x;
+                                       }
+                               } else if (screen_aspect > img_aspect) {
+                                       crop_x = img->d_w / 4;
                                }
 
-                               set_pan(layer, crop_point, img->d_h - new_h);
-
-                               if (crop_point > 0) {
-                                       switch_img_set_rect(img, 0, crop_point, (unsigned int)(layer->screen_w/scale), (unsigned int)(layer->screen_h/scale));
-                                       img_aspect = (double) img->d_w / img->d_h;
+                               if (can_pan) {
+                                       if (layer->cam_opts.autopan) {
+                                               crop_y = use_geometry->y - (crop_h / 2);
+                                       } else {
+                                               crop_y = use_geometry->y;
+                                       }
+                               } else if (screen_aspect < img_aspect) {
+                                       crop_y = img->d_h / 4;
                                }
+
+                               crop_x = switch_round_to_step(crop_x, layer->cam_opts.snap_factor);
+                               crop_y = switch_round_to_step(crop_y, layer->cam_opts.snap_factor);
+                       }
+
+                       //printf("BOUNDS B4 %d,%d %dx%d %dx%d\n", crop_x, crop_y, img->d_w, img->d_h, crop_w, crop_h);
+                       set_bounds(&crop_x, &crop_y, img->d_w, img->d_h, crop_w, crop_h);
+                       //printf("BOUNDS AF %d,%d %dx%d %dx%d\n", crop_x, crop_y, img->d_w, img->d_h, crop_w, crop_h);
+                               
+                       if (img_changed) {
+                               layer->crop_x = crop_x;
+                               layer->crop_y = crop_y;
+                               layer->crop_w = crop_w;
+                               layer->crop_h = crop_h;
                        }
+
+                       //printf("B4 %d,%d %d,%d\n", crop_x, crop_y, layer->crop_x, layer->crop_y);
+
+
+                       set_pan(crop_x, &layer->crop_x, layer->cam_opts.pan_accel_speed, layer->cam_opts.pan_accel_min, layer->cam_opts.pan_speed);
+                       set_pan(crop_y, &layer->crop_y, layer->cam_opts.pan_accel_speed, layer->cam_opts.pan_accel_min, layer->cam_opts.pan_speed);
+
+                       //printf("AF %d,%d\n", layer->crop_x, layer->crop_y);
+
+
+                       //printf("B4 %dx%d %dx%d\n", crop_w, crop_h, layer->crop_w, layer->crop_h);
+                       set_pan(crop_w, &layer->crop_w, layer->cam_opts.zoom_accel_speed, layer->cam_opts.zoom_accel_min, layer->cam_opts.zoom_speed);
+                       layer->crop_h = layer->crop_w / screen_aspect;
+
+                       set_bounds(&layer->crop_x, &layer->crop_y, img->d_w, img->d_h, layer->crop_w, layer->crop_h);
+
+                       assert(layer->crop_w > 0);
+
+                       //printf("RECT %d,%d %dx%d (%dx%d) [%dx%d] [%dx%d]\n", layer->crop_x, layer->crop_y, layer->crop_w, layer->crop_h, layer->crop_w + layer->crop_x, layer->crop_h + layer->crop_y, img->d_w, img->d_h, layer->screen_w, layer->screen_h);
+                       
+                       switch_img_set_rect(img, layer->crop_x, layer->crop_y, layer->crop_w, layer->crop_h);
+                       switch_assert(img->d_w == layer->crop_w);
+                               
+                       img_aspect = (double) img->d_w / img->d_h;
+
                }
 
+               layer->last_geometry = layer->bug_frame.geometry;
+
                if (freeze) {
                        switch_img_free(&layer->img);
                }
-
+               
                if (screen_aspect > img_aspect) {
                        img_w = (uint32_t)ceil((double)img_aspect * layer->screen_h);
                        x_pos += (layer->screen_w - img_w) / 2;
@@ -565,9 +822,12 @@ void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg,
                img_w -= (layer->geometry.border * 2);
                img_h -= (layer->geometry.border * 2);
 
+               //printf("SCALE %d,%d %dx%d\n", x_pos, y_pos, img_w, img_h);
+
                switch_img_scale(img, &layer->img, img_w, img_h);
 
                if (layer->img) {
+                       //switch_img_copy(img, &layer->img);
                        switch_img_patch(IMG, layer->img, x_pos + layer->geometry.border, y_pos + layer->geometry.border);
                }
 
@@ -734,6 +994,8 @@ void conference_video_detach_video_layer(conference_member_t *member)
                switch_img_txt_handle_destroy(&layer->txthandle);
        }
 
+       member->cam_opts = layer->cam_opts;
+       
        conference_video_reset_layer(layer);
        layer->member_id = 0;
        layer->member = NULL;
@@ -1121,6 +1383,9 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
 
        for (i = 0; i < vlayout->layers; i++) {
                mcu_layer_t *layer = &canvas->layers[i];
+
+               conference_video_reset_layer(layer);
+
                layer->geometry.x = vlayout->images[i].x;
                layer->geometry.y = vlayout->images[i].y;
                layer->geometry.hscale = vlayout->images[i].scale;
@@ -1137,7 +1402,6 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
                layer->idx = i;
                layer->refresh = 1;
 
-
                layer->screen_w = (uint32_t)(canvas->img->d_w * layer->geometry.scale / VIDEO_LAYOUT_SCALE);
                layer->screen_h = (uint32_t)(canvas->img->d_h * layer->geometry.hscale / VIDEO_LAYOUT_SCALE);
 
@@ -1147,6 +1411,8 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
                layer->x_pos = (int)(canvas->img->d_w * layer->geometry.x / VIDEO_LAYOUT_SCALE);
                layer->y_pos = (int)(canvas->img->d_h * layer->geometry.y / VIDEO_LAYOUT_SCALE);
 
+               set_default_cam_opts(layer);
+
 
                if (layer->geometry.floor) {
                        canvas->layout_floor_id = i;
@@ -1199,6 +1465,8 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva
        switch_mutex_unlock(canvas->mutex);
        switch_thread_rwlock_unlock(canvas->video_rwlock);
 
+       conference_event_adv_layout(conference, canvas, vlayout);
+
        switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id + 1, vlayout->name);
 
 }
index ab7bd447544d8966cc7ac29e4e13f0ee62ec114b..37b9ed7f6012f9de820c719149baa336f5fc0def 100644 (file)
@@ -3447,6 +3447,34 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
        conference->super_canvas_label_layers = video_super_canvas_label_layers;
        conference->super_canvas_show_all_layers = video_super_canvas_show_all_layers;
 
+
+       if (conference_utils_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
+               char *p;
+
+               if (strchr(conference->name, '@')) {
+                       conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
+                       conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s", conference->name);
+                       conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s", conference->name);
+                       conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s", conference->name);
+               } else {
+                       conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
+                       conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s@%s", conference->name, conference->domain);
+                       conference->info_event_channel = switch_core_sprintf(conference->pool, "conference-info.%s@%s", conference->name, conference->domain);
+                       conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s@%s", conference->name, conference->domain);
+               }
+
+               conference->la_name = switch_core_strdup(conference->pool, conference->name);
+               if ((p = strchr(conference->la_name, '@'))) {
+                       *p = '\0';
+               }
+
+               switch_live_array_create(conference->la_event_channel, conference->la_name, conference_globals.event_channel_id, &conference->la);
+               switch_live_array_set_user_data(conference->la, conference);
+               switch_live_array_set_command_handler(conference->la, conference_event_la_command_handler);
+       }
+
+
+
        if (video_canvas_count < 1) video_canvas_count = 1;
 
        if (conference_utils_test_flag(conference, CFLAG_PERSONAL_CANVAS) && video_canvas_count > 1) {
@@ -3499,30 +3527,6 @@ conference_obj_t *conference_new(char *name, conference_xml_cfg_t cfg, switch_co
        switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "conference-create");
        switch_event_fire(&event);
 
-       if (conference_utils_test_flag(conference, CFLAG_LIVEARRAY_SYNC)) {
-               char *p;
-
-               if (strchr(conference->name, '@')) {
-                       conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s", conference->name);
-                       conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s", conference->name);
-                       conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s", conference->name);
-               } else {
-                       conference->la_event_channel = switch_core_sprintf(conference->pool, "conference-liveArray.%s@%s", conference->name, conference->domain);
-                       conference->chat_event_channel = switch_core_sprintf(conference->pool, "conference-chat.%s@%s", conference->name, conference->domain);
-                       conference->mod_event_channel = switch_core_sprintf(conference->pool, "conference-mod.%s@%s", conference->name, conference->domain);
-               }
-
-               conference->la_name = switch_core_strdup(conference->pool, conference->name);
-               if ((p = strchr(conference->la_name, '@'))) {
-                       *p = '\0';
-               }
-
-               switch_live_array_create(conference->la_event_channel, conference->la_name, conference_globals.event_channel_id, &conference->la);
-               switch_live_array_set_user_data(conference->la, conference);
-               switch_live_array_set_command_handler(conference->la, conference_event_la_command_handler);
-       }
-
-
  end:
 
        switch_mutex_unlock(conference_globals.hash_mutex);
index 101cbd93bb5168a54532f4a6d8c24c288ed119a3..0a3fb8db103f2660ba64d8dafb66d4a6faf250cd 100644 (file)
@@ -429,6 +429,23 @@ typedef struct mcu_layer_def_s {
        mcu_layer_geometry_t layers[MCU_MAX_LAYERS];
 } mcu_layer_def_t;
 
+
+typedef struct mcu_layer_cam_opts_s {
+       int manual_pan;
+       int manual_zoom;
+       int autozoom;
+       int autopan;
+       int zoom_factor;
+       int snap_factor;
+       int zoom_move_factor;
+       int pan_speed;
+       int pan_accel_speed;
+       int pan_accel_min;
+       int zoom_speed;
+       int zoom_accel_speed;
+       int zoom_accel_min;
+} mcu_layer_cam_opts_t;
+
 struct mcu_canvas_s;
 
 typedef struct mcu_layer_s {
@@ -447,7 +464,13 @@ typedef struct mcu_layer_s {
        int refresh;
        int clear;
        int is_avatar;
-       int crop_point;
+       int crop_x;
+       int crop_y;
+       int crop_w;
+       int crop_h;
+       int last_w;
+       int last_h;
+       uint32_t img_count;
        switch_size_t last_img_addr;
        switch_image_t *img;
        switch_image_t *cur_img;
@@ -463,6 +486,12 @@ typedef struct mcu_layer_s {
        int need_patch;
        conference_member_t *member;
        switch_frame_t bug_frame;
+       switch_frame_geometry_t last_geometry;
+       switch_frame_geometry_t auto_geometry;
+       switch_frame_geometry_t zoom_geometry;
+       switch_frame_geometry_t pan_geometry;
+       switch_frame_geometry_t manual_geometry;
+       mcu_layer_cam_opts_t cam_opts;
 } mcu_layer_t;
 
 typedef struct video_layout_s {
@@ -540,6 +569,7 @@ typedef struct conference_obj {
        char *la_event_channel;
        char *chat_event_channel;
        char *mod_event_channel;
+       char *info_event_channel;
        char *desc;
        char *timer_name;
        char *tts_engine;
@@ -809,6 +839,7 @@ struct conference_member {
        char *text_framedata;
        uint32_t text_framesize;
 
+       mcu_layer_cam_opts_t cam_opts;
 
 };
 
@@ -967,6 +998,7 @@ void conference_event_send_rfc(conference_obj_t *conference);
 void conference_member_update_status_field(conference_member_t *member);
 void conference_event_la_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data);
 void conference_event_adv_la(conference_obj_t *conference, conference_member_t *member, switch_bool_t join);
+void conference_event_adv_layout(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout);
 switch_status_t conference_video_init_canvas(conference_obj_t *conference, video_layout_t *vlayout, mcu_canvas_t **canvasP);
 switch_status_t conference_video_attach_canvas(conference_obj_t *conference, mcu_canvas_t *canvas, int super);
 void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canvas_t *canvas, video_layout_t *vlayout);
@@ -980,6 +1012,7 @@ void conference_video_set_canvas_letterbox_bgcolor(mcu_canvas_t *canvas, char *c
 void conference_video_set_canvas_bgcolor(mcu_canvas_t *canvas, char *color);
 void conference_video_scale_and_patch(mcu_layer_t *layer, switch_image_t *ximg, switch_bool_t freeze);
 void conference_video_reset_layer(mcu_layer_t *layer);
+void conference_video_reset_layer_cam(mcu_layer_t *layer);
 void conference_video_clear_layer(mcu_layer_t *layer);
 void conference_video_reset_image(switch_image_t *img, switch_rgb_color_t *color);
 void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int HEIGHT);
@@ -1111,6 +1144,7 @@ switch_status_t conference_api_sub_check_record(conference_obj_t *conference, sw
 switch_status_t conference_api_sub_check_record(conference_obj_t *conference, switch_stream_handle_t *stream, int arc, char **argv);
 switch_status_t conference_api_sub_volume_in(conference_member_t *member, switch_stream_handle_t *stream, void *data);
 switch_status_t conference_api_sub_file_seek(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
+switch_status_t conference_api_sub_cam(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
 switch_status_t conference_api_sub_stop(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
 switch_status_t conference_api_sub_hup(conference_member_t *member, switch_stream_handle_t *stream, void *data);
 switch_status_t conference_api_sub_pauserec(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);
index c3a0376b3bcd7ba3514f46a5bd68e41ec9d1345b..dfedd930de8eb6a7c2f18b79837b0fcce019e70a 100644 (file)
@@ -134,6 +134,10 @@ typedef struct cv_context_s {
     char *png_prefix;
     int tick_speed;
        int confidence_level;
+       int max_search_w;
+       int max_search_h;
+       int neighbors;
+       double search_scale;
 } cv_context_t;
 
 
@@ -484,6 +488,12 @@ static void init_context(cv_context_t *context)
         context->cascade_path = switch_core_get_variable_pdup("cv_default_cascade", context->pool);
         context->nested_cascade_path = switch_core_get_variable_pdup("cv_default_nested_cascade", context->pool);
                context->confidence_level = 20;
+               context->max_search_w = 20;
+               context->max_search_h = 20;
+               context->neighbors = 2;
+               context->search_scale = 1.1;
+
+
 
         for (int i = 0; i < MAX_OVERLAY; i++) {
             context->overlay[i] = (struct overlay *) switch_core_alloc(context->pool, sizeof(struct overlay));
@@ -588,12 +598,12 @@ void detectAndDraw(cv_context_t *context)
     equalizeHist( smallImg, smallImg );
 
     context->cascade->detectMultiScale( smallImg, detectedObjs,
-                                        1.1, 2, 0
+                                        context->search_scale, context->neighbors, 0
                                         |CV_HAAR_FIND_BIGGEST_OBJECT
                                         |CV_HAAR_DO_ROUGH_SEARCH
                                         |CV_HAAR_SCALE_IMAGE
                                         ,
-                                        Size(20, 20) );
+                                        Size(context->max_search_w, context->max_search_h) );
 
 
     parse_stats(&context->detected, detectedObjs.size(), context->skip);
@@ -616,7 +626,7 @@ void detectAndDraw(cv_context_t *context)
 
         double aspect_ratio = (double)r->width/r->height;
 
-        if (context->shape_idx >= MAX_SHAPES) {
+        if (context->shape_idx >= 1) {//MAX_SHAPES) {
             break;
         }
 
@@ -625,6 +635,7 @@ void detectAndDraw(cv_context_t *context)
             center.x = switch_round_to_step(cvRound((r->x + r->width*0.5)*scale), 20);
             center.y = switch_round_to_step(cvRound((r->y + r->height*0.5)*scale), 20);
             radius = switch_round_to_step(cvRound((r->width + r->height)*0.25*scale), 20);
+                       
 
             if (context->debug) {
                 circle( img, center, radius, color, 3, 8, 0 );
@@ -679,6 +690,7 @@ void detectAndDraw(cv_context_t *context)
 
         // Draw rectangle reflecting confidence
         const int object_neighbors = nestedObjects.size();
+               //printf("WTF %d\n", object_neighbors);
         //cout << "Detected " << object_neighbors << " object neighbors" << endl;
         const int rect_height = cvRound((float)img.rows * object_neighbors / max_neighbors);
         CvScalar col = CV_RGB((float)255 * object_neighbors / max_neighbors, 0, 0);
@@ -861,9 +873,11 @@ static switch_status_t video_thread_callback(switch_core_session_t *session, swi
                frame->geometry.y = context->shape[0].cy;
                frame->geometry.w = context->shape[0].w;
                frame->geometry.h = context->shape[0].h;
-               frame->geometry.m = 1;
+               frame->geometry.M++;
+               frame->geometry.X = 0;
        } else {
-               frame->geometry.m = 0;
+               frame->geometry.M = 0;
+               frame->geometry.X++;
        }
 
     if (context->overlay_count && (abs || (context->detect_event && context->shape[0].cx))) {
@@ -991,7 +1005,7 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
             *val++ = '\0';
         }
 
-        if (name && val) {
+        if (name && !zstr(val)) {
             if (!strcasecmp(name, "xo")) {
                 context->overlay[png_idx]->xo = atof(val);
             } else if (!strcasecmp(name, "nick")) {
@@ -1029,6 +1043,17 @@ static void parse_params(cv_context_t *context, int start, int argc, char **argv
                 context->skip = atoi(val);
             } else if (!strcasecmp(name, "debug")) {
                 context->debug = atoi(val);
+            } else if (!strcasecmp(name, "neighbors")) {
+                               context->neighbors = atoi(val);
+            } else if (!strcasecmp(name, "max_search_w")) {
+                               context->max_search_w = atoi(val);
+            } else if (!strcasecmp(name, "max_search_h")) {
+                               context->max_search_h = atoi(val);
+                       } else if (!strcasecmp(name, "search_scale")) {
+                               double tmp = atof(val);
+                               if (tmp > 1) {
+                                       context->search_scale = tmp;
+                               }
             } else if (!strcasecmp(name, "confidence")) {
                 context->confidence_level = atoi(val);
             } else if (!strcasecmp(name, "cascade")) {
index 0f53f64ed75a5ad0be63eadbf12b99b67ed8a2d1..87ca22501452dfa50a5e187bce9bf4fa8fd73704 100644 (file)
@@ -3898,7 +3898,6 @@ static switch_bool_t verto__unsubscribe_func(const char *method, cJSON *params,
 static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)
 {
        char *json_text = NULL;
-       switch_bool_t r = SWITCH_FALSE;
        const char *event_channel = cJSON_GetObjectCstr(params, "eventChannel");
        cJSON *jevent, *broadcast;
        const char *display = NULL;
@@ -3941,11 +3940,12 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
 
                        if (mcast_socket_send(&jsock->profile->mcast_pub, json_text, strlen(json_text) + 1) <= 0) {
                                switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "multicast socket send error! %s\n", strerror(errno));
-                               r = SWITCH_FALSE;
-                               cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Send failure!"));
+                               //r = SWITCH_FALSE;
+                               //cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Send failure!"));
                        } else {
-                               r = SWITCH_TRUE;
-                               cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent"));
+                               //r = SWITCH_TRUE;
+                               //cJSON_AddItemToObject(*response, "message", cJSON_CreateString("MCAST Data Sent"));
+                               switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "MCAST Data Sent\n");
                        }
                        free(json_text);
                        json_text = NULL;
@@ -3956,7 +3956,7 @@ static switch_bool_t verto__broadcast_func(const char *method, cJSON *params, js
 
  end:
 
-       return r;
+       return SWITCH_TRUE;
 }
 
 static switch_bool_t login_func(const char *method, cJSON *params, jsock_t *jsock, cJSON **response)