FS-7513: add auto layout advance based on group

This commit is contained in:
Anthony Minessale 2015-02-05 22:38:07 -06:00 committed by Michael Jerris
parent a56e65bace
commit 3e323e3b09
3 changed files with 174 additions and 73 deletions

View File

@ -178,10 +178,12 @@
<!--<param name="conference-flags" value="video-floor-only|rfc-4579|livearray-sync|auto-3d-position|transcode-video|minimize-video-encoding"/> -->
<!-- <param name="video-layout-name" value="3x3"/> -->
<!-- <param name="video-layout-name" value="group:grid"/> -->
<!-- <param name="video-canvas-size" value="1280x720"/> -->
<!-- <param name="video-canvas-bgcolor" value="#0000FF"/> -->
<!-- <param name="video-codec-bandwidth" value="2mb"/> -->
<!--<param name="tts-engine" value="flite"/>-->
<!--<param name="tts-voice" value="kal16"/>-->
</profile>

View File

@ -105,7 +105,7 @@
<image x="300" y="300" scale="60"/>
</layout>
<layout name="1up_top_left+5">
<image x="0" y="0" scale="240" floor="true"/>
<image x="0" y="0" scale="240" floor="true" reservation_id="primary"/>
<image x="240" y="0" scale="120"/>
<image x="240" y="120" scale="120"/>
<image x="0" y="240" scale="120"/>
@ -113,7 +113,7 @@
<image x="240" y="240" scale="120"/>
</layout>
<layout name="1up_top_left+7">
<image x="0" y="0" scale="270" floor="true"/>
<image x="0" y="0" scale="270" floor="true" reservation_id="primary"/>
<image x="270" y="0" scale="90"/>
<image x="270" y="90" scale="90"/>
<image x="270" y="180" scale="90"/>
@ -123,7 +123,7 @@
<image x="270" y="270" scale="90"/>
</layout>
<layout name="1up_top_left+9">
<image x="0" y="0" scale="288" floor="true"/>
<image x="0" y="0" scale="288" floor="true" reservation_id="primary"/>
<image x="288" y="0" scale="72"/>
<image x="288" y="72" scale="72"/>
<image x="288" y="144" scale="72"/>
@ -135,7 +135,7 @@
<image x="288" y="288" scale="72"/>
</layout>
<layout name="2up_top+8">
<image x="0" y="0" scale="180" floor="true"/>
<image x="0" y="0" scale="180" floor="true" reservation_id="primary"/>
<image x="180" y="0" scale="180" reservation_id="secondary"/>
<image x="0" y="180" scale="90"/>
<image x="90" y="180" scale="90"/>
@ -147,7 +147,7 @@
<image x="270" y="270" scale="90"/>
</layout>
<layout name="2up_middle+8">
<image x="0" y="90" scale="180" floor="true"/>
<image x="0" y="90" scale="180" floor="true" reservation_id="primary"/>
<image x="180" y="90" scale="180" reservation_id="secondary"/>
<image x="0" y="0" scale="90"/>
<image x="90" y="0" scale="90"/>
@ -159,7 +159,7 @@
<image x="270" y="270" scale="90"/>
</layout>
<layout name="2up_bottom+8">
<image x="0" y="180" scale="180" floor="true"/>
<image x="0" y="180" scale="180" floor="true" reservation_id="primary"/>
<image x="180" y="180" scale="180" reservation_id="secondary"/>
<image x="0" y="0" scale="90"/>
<image x="90" y="0" scale="90"/>
@ -171,7 +171,7 @@
<image x="270" y="90" scale="90"/>
</layout>
<layout name="3up+4">
<image x="0" y="0" scale="180" floor="true"/>
<image x="0" y="0" scale="180" floor="true" reservation_id="primary"/>
<image x="180" y="0" scale="180" reservation_id="secondary"/>
<image x="0" y="180" scale="180" reservation_id="third"/>
<image x="180" y="180" scale="90"/>
@ -180,7 +180,7 @@
<image x="270" y="270" scale="90"/>
</layout>
<layout name="3up+9">
<image x="0" y="0" scale="180" floor="true"/>
<image x="0" y="0" scale="180" floor="true" reservation_id="primary"/>
<image x="180" y="0" scale="180" reservation_id="secondary"/>
<image x="0" y="180" scale="180" reservation_id="third"/>
<image x="180" y="180" scale="60"/>

View File

@ -426,6 +426,7 @@ typedef struct conference_obj {
char *record_filename;
char *outcall_templ;
char *video_layout_name;
char *video_layout_group;
char *video_canvas_bgcolor;
uint32_t video_codec_bandwidth;
uint32_t canvas_width;
@ -687,16 +688,20 @@ static switch_status_t conf_api_sub_position(conference_member_t *member, switch
//#define lock_member(_member) switch_mutex_lock(_member->write_mutex)
//#define unlock_member(_member) switch_mutex_unlock(_member->write_mutex)
typedef struct layout_node_s {
typedef struct video_layout_s {
char *name;
char *audio_position;
mcu_layer_geometry_t images[MCU_MAX_LAYERS];
struct layout_node_s *next;
int layers;
} layout_node_t;
} video_layout_t;
typedef struct video_layout_node_s {
video_layout_t *vlayout;
struct video_layout_node_s *next;
} video_layout_node_t;
typedef struct layout_group_s {
layout_node_t *layouts;
video_layout_node_t *layouts;
} layout_group_t;
static void conference_parse_layouts(conference_obj_t *conference)
@ -724,7 +729,7 @@ static void conference_parse_layouts(conference_obj_t *conference)
if ((x_layout_settings = switch_xml_child(cfg, "layout-settings"))) {
if ((x_layouts = switch_xml_child(x_layout_settings, "layouts"))) {
for (x_layout = switch_xml_child(x_layouts, "layout"); x_layout; x_layout = x_layout->next) {
layout_node_t *lnode;
video_layout_t *vlayout;
const char *val = NULL, *name = NULL;
if ((val = switch_xml_attr(x_layout, "name"))) {
@ -736,8 +741,8 @@ static void conference_parse_layouts(conference_obj_t *conference)
continue;
}
lnode = switch_core_alloc(conference->pool, sizeof(*lnode));
lnode->name = switch_core_strdup(conference->pool, name);
vlayout = switch_core_alloc(conference->pool, sizeof(*vlayout));
vlayout->name = switch_core_strdup(conference->pool, name);
for (x_image = switch_xml_child(x_layout, "image"); x_image; x_image = x_image->next) {
const char *res_id = NULL, *audio_position = NULL;
@ -775,33 +780,34 @@ static void conference_parse_layouts(conference_obj_t *conference)
}
lnode->images[lnode->layers].x = x;
lnode->images[lnode->layers].y = y;
lnode->images[lnode->layers].scale = scale;
lnode->images[lnode->layers].floor = floor;
vlayout->images[vlayout->layers].x = x;
vlayout->images[vlayout->layers].y = y;
vlayout->images[vlayout->layers].scale = scale;
vlayout->images[vlayout->layers].floor = floor;
if (res_id) {
lnode->images[lnode->layers].res_id = switch_core_strdup(conference->pool, res_id);
vlayout->images[vlayout->layers].res_id = switch_core_strdup(conference->pool, res_id);
}
if (audio_position) {
lnode->images[lnode->layers].audio_position = switch_core_strdup(conference->pool, audio_position);
vlayout->images[vlayout->layers].audio_position = switch_core_strdup(conference->pool, audio_position);
}
lnode->layers++;
vlayout->layers++;
}
switch_core_hash_insert(conference->layout_hash, name, lnode);
switch_core_hash_insert(conference->layout_hash, name, vlayout);
}
}
if ((x_groups = switch_xml_child(cfg, "groups"))) {
if ((x_groups = switch_xml_child(x_layout_settings, "groups"))) {
for (x_group = switch_xml_child(x_groups, "group"); x_group; x_group = x_group->next) {
const char *name = switch_xml_attr(x_group, "name");
layout_group_t *lg;
x_layout = switch_xml_child(cfg, "layout");
video_layout_node_t *last_vlnode = NULL;
x_layout = switch_xml_child(x_group, "layout");
if (!name || !x_group || !x_layout) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid group\n");
@ -809,22 +815,30 @@ static void conference_parse_layouts(conference_obj_t *conference)
}
lg = switch_core_alloc(conference->pool, sizeof(*lg));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding layout group %s\n", name);
switch_core_hash_insert(conference->layout_group_hash, name, lg);
while(x_layout) {
const char *name = x_layout->txt;
layout_node_t *lnode, *last_lnode = NULL;
const char *nname = x_layout->txt;
video_layout_t *vlayout;
video_layout_node_t *vlnode;
if ((lnode = switch_core_hash_find(conference->layout_hash, name))) {
if (!lg->layouts) {
lnode = lg->layouts;
if ((vlayout = switch_core_hash_find(conference->layout_hash, nname))) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Adding node %s to layout group %s\n", nname, name);
vlnode = switch_core_alloc(conference->pool, sizeof(*vlnode));
vlnode->vlayout = vlayout;
if (last_vlnode) {
last_vlnode->next = vlnode;
last_vlnode = last_vlnode->next;
} else {
lnode = last_lnode->next;
lg->layouts = last_vlnode = vlnode;
}
last_lnode = lnode;
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid group member\n");
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid group member %s\n", nname);
}
x_layout = x_layout->next;
@ -1050,7 +1064,10 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
conference_member_t *imember = NULL;
switch_channel_t *channel = NULL;
const char *res_id = NULL;
if (!member->session) abort();
switch_mutex_lock(member->conference->canvas->mutex);
channel = switch_core_session_get_channel(member->session);
res_id = switch_channel_get_variable(channel, "video_reservation_id");
@ -1062,11 +1079,10 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
if (layer->geometry.res_id || res_id) {
if (!layer->geometry.res_id || !res_id || strcmp(layer->geometry.res_id, res_id)) {
switch_mutex_unlock(member->conference->canvas->mutex);
return SWITCH_STATUS_FALSE;
}
}
switch_mutex_lock(member->conference->canvas->mutex);
if (layer->member_id && (imember = conference_member_get(member->conference, layer->member_id))) {
detach_video_layer(imember);
@ -1085,20 +1101,22 @@ static switch_status_t attach_video_layer(conference_member_t *member, int idx)
return SWITCH_STATUS_SUCCESS;
}
static void init_canvas_layers(conference_obj_t *conference, layout_node_t *lnode)
static void init_canvas_layers(conference_obj_t *conference, video_layout_t *vlayout)
{
int i = 0;
conference_member_t *member = NULL;
if (!conference->canvas) return;
conference->canvas->layout_floor_id = -1;
for (i = 0; i < lnode->layers; i++) {
for (i = 0; i < vlayout->layers; i++) {
mcu_layer_t *layer = &conference->canvas->layers[i];
layer->geometry.x = lnode->images[i].x;
layer->geometry.y = lnode->images[i].y;
layer->geometry.scale = lnode->images[i].scale;
layer->geometry.floor = lnode->images[i].floor;
layer->geometry.x = vlayout->images[i].x;
layer->geometry.y = vlayout->images[i].y;
layer->geometry.scale = vlayout->images[i].scale;
layer->geometry.floor = vlayout->images[i].floor;
layer->idx = i;
if (layer->geometry.floor) {
@ -1107,8 +1125,8 @@ static void init_canvas_layers(conference_obj_t *conference, layout_node_t *lnod
/* if we ever decided to reload layers config on demand the pointer assignment below will lead to segs but we
only load them once forever per conference so these pointers are valid for the life of the conference */
layer->geometry.res_id = lnode->images[i].res_id;
layer->geometry.audio_position = lnode->images[i].audio_position;
layer->geometry.res_id = vlayout->images[i].res_id;
layer->geometry.audio_position = vlayout->images[i].audio_position;
}
if (conference->canvas->layout_floor_id > -1 &&
@ -1117,10 +1135,10 @@ static void init_canvas_layers(conference_obj_t *conference, layout_node_t *lnod
switch_thread_rwlock_unlock(member->rwlock);
}
conference->canvas->total_layers = lnode->layers;
conference->canvas->total_layers = vlayout->layers;
}
static void init_canvas(conference_obj_t *conference, layout_node_t *lnode)
static void init_canvas(conference_obj_t *conference, video_layout_t *vlayout)
{
if (!conference->canvas) {
conference->canvas = switch_core_alloc(conference->pool, sizeof(*conference->canvas));
@ -1140,7 +1158,7 @@ static void init_canvas(conference_obj_t *conference, layout_node_t *lnode)
switch_mutex_lock(conference->canvas->mutex);
set_canvas_bgcolor(conference->canvas, conference->video_canvas_bgcolor);
init_canvas_layers(conference, lnode);
init_canvas_layers(conference, vlayout);
switch_mutex_unlock(conference->canvas->mutex);
}
@ -1228,11 +1246,26 @@ static void write_canvas_image_to_codec_group(conference_obj_t *conference, code
#define MAX_MUX_CODECS 10
//#define TRACK_FPS
static video_layout_t *find_best_layout(conference_obj_t *conference, layout_group_t *lg)
{
video_layout_node_t *vlnode = NULL, *last = NULL;
for (vlnode = lg->layouts; vlnode; vlnode = vlnode->next) {
if (vlnode->vlayout->layers >= conference->count) {
break;
}
last = vlnode;
}
return vlnode? vlnode->vlayout : last ? last->vlayout : NULL;
}
static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thread, void *obj)
{
conference_obj_t *conference = (conference_obj_t *) obj;
conference_member_t *imember;
layout_node_t *lnode = switch_core_hash_find(conference->layout_hash, conference->video_layout_name);
video_layout_t *vlayout = NULL;
switch_codec_t *check_codec = NULL;
codec_set_t *write_codecs[MAX_MUX_CODECS] = { 0 };
int buflen = SWITCH_RECOMMENDED_BUFFER_SIZE * 2;
@ -1243,15 +1276,29 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
switch_time_t last_key_time = 0;
mcu_layer_t *layer = NULL;
switch_frame_t write_frame = { 0 };
uint8_t *packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
uint8_t *packet = NULL;
layout_group_t *lg = NULL;
#ifdef TRACK_FPS
uint64_t frames = 0;
switch_time_t started = switch_micro_time_now();
#endif
switch_assert(lnode);
if (conference->video_layout_group) {
lg = switch_core_hash_find(conference->layout_group_hash, conference->video_layout_group);
vlayout = find_best_layout(conference, lg);
} else {
vlayout = switch_core_hash_find(conference->layout_hash, conference->video_layout_name);
}
init_canvas(conference, lnode);
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);
switch_core_timer_init(&timer, "soft", 1, 90, conference->pool);
@ -1277,8 +1324,9 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
continue;
}
if (switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
if (!switch_test_flag(conference, CFLAG_MINIMIZE_VIDEO_ENCODING)) {
packet = switch_core_alloc(conference->pool, SWITCH_RECOMMENDED_BUFFER_SIZE);
} else {
if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) {
switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ);
need_refresh = SWITCH_TRUE;
@ -1292,7 +1340,7 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
break;
}
}
if (imember->video_codec_index < 0) {
write_codecs[i] = switch_core_alloc(conference->pool, sizeof(codec_set_t));
@ -1341,6 +1389,9 @@ static void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread
used++;
switch_mutex_lock(conference->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);
if (imember->video_layer_id > -1) {
if (imember->video_layer_id >= conference->canvas->total_layers) {
detach_video_layer(imember);
@ -3043,7 +3094,8 @@ 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) {
@ -3088,6 +3140,19 @@ 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);
init_canvas_layers(conference, vlayout);
reset_image(conference->canvas->img, &conference->canvas->bgcolor);
switch_mutex_unlock(conference->member_mutex);
}
if (conference->canvas->layout_floor_id > -1) {
attach_video_layer(member, conference->canvas->layout_floor_id);
}
}
}
@ -3371,9 +3436,9 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
if (member->conference->canvas) {
switch_mutex_lock(member->conference->canvas->mutex);
detach_video_layer(member);
detach_video_layer(imember);
attach_video_layer(member, conference->canvas->layout_floor_id);
if (conference->canvas->layout_floor_id > -1) {
attach_video_layer(member, conference->canvas->layout_floor_id);
}
switch_mutex_unlock(member->conference->canvas->mutex);
}
@ -3626,8 +3691,6 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
lock_member(member);
detach_video_layer(member);
member_del_relationship(member, 0);
conference_cdr_del(member);
@ -3705,10 +3768,6 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
member->conference->video_floor_holder = 0;
}
find_video_floor(member, SWITCH_FALSE);
member->conference = NULL;
if (!switch_test_flag(member, MFLAG_NOCHANNEL)) {
switch_channel_t *channel = switch_core_session_get_channel(member->session);
if (switch_test_flag(member, MFLAG_GHOST)) {
@ -3752,6 +3811,12 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
switch_event_fire(&event);
}
}
find_video_floor(member, SWITCH_FALSE);
detach_video_layer(member);
member->conference = NULL;
switch_mutex_unlock(conference->member_mutex);
unlock_member(member);
switch_mutex_unlock(member->audio_out_mutex);
@ -7541,20 +7606,40 @@ static switch_status_t conf_api_sub_volume_out(conference_member_t *member, swit
static switch_status_t conf_api_sub_vid_layout(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
layout_node_t *lnode;
video_layout_t *vlayout = NULL;
if (!argv[2]) {
stream->write_function(stream, "Invalid input\n");
return SWITCH_STATUS_SUCCESS;
}
if (!(lnode = switch_core_hash_find(conference->layout_hash, argv[2]))) {
if (!strcasecmp(argv[2], "group")) {
layout_group_t *lg = NULL;
if (!argv[3]) {
stream->write_function(stream, "Group name not specified.\n");
return SWITCH_STATUS_SUCCESS;
} else {
if (((lg = switch_core_hash_find(conference->layout_group_hash, argv[3])))) {
vlayout = find_best_layout(conference, lg);
}
if (!vlayout) {
stream->write_function(stream, "Invalid group layout [%s]\n", argv[3]);
return SWITCH_STATUS_SUCCESS;
}
}
}
if (!vlayout && !(vlayout = switch_core_hash_find(conference->layout_hash, argv[2]))) {
stream->write_function(stream, "Invalid layout [%s]\n", argv[2]);
return SWITCH_STATUS_SUCCESS;
}
stream->write_function(stream, "Change to layout [%s]\n", vlayout->name);
switch_mutex_lock(conference->member_mutex);
init_canvas_layers(conference, lnode);
init_canvas_layers(conference, vlayout);
reset_image(conference->canvas->img, &conference->canvas->bgcolor);
switch_mutex_unlock(conference->member_mutex);
@ -10917,6 +11002,7 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
char *moh_sound = NULL;
char *outcall_templ = NULL;
char *video_layout_name = NULL;
char *video_layout_group = NULL;
char *video_canvas_size = NULL;
char *video_canvas_bgcolor = NULL;
char *video_codec_bandwidth = NULL;
@ -11262,9 +11348,19 @@ static conference_obj_t *conference_new(char *name, conf_xml_cfg_t cfg, switch_c
conference->video_codec_bandwidth = switch_parse_bandwidth_string(video_codec_bandwidth);
}
if (video_layout_name && !switch_core_hash_find(conference->layout_hash, video_layout_name)) {
video_layout_name = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid conference layout settings\n");
if (video_layout_name) {
if (!strncasecmp(video_layout_name, "group:", 6)) {
if (!switch_core_hash_find(conference->layout_group_hash, video_layout_name + 6)) {
video_layout_name = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid conference layout group settings\n");
} else {
video_layout_group = video_layout_name + 6;
}
} else if (!switch_core_hash_find(conference->layout_hash, video_layout_name)) {
video_layout_name = NULL;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid conference layout settings\n");
}
}
if (!video_canvas_bgcolor) {
@ -11292,11 +11388,14 @@ 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);
}
} else {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid conference dimensions\n");
}
} else if (video_canvas_size || video_layout_name) {
} else if (video_canvas_size || video_layout_name || video_layout_group) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING, "invalid conference layout settings\n");
}