From a62f26803ea7fd9c7c3de62dc7f56035c85992c1 Mon Sep 17 00:00:00 2001 From: Anthony Minessale Date: Thu, 9 Mar 2017 14:18:16 -0600 Subject: [PATCH] FS-10121: [mod_conference] Add role-id and layout transitions to conference #resolve --- .../mod_conference/conference_api.c | 54 ++++++++++++++++ .../mod_conference/conference_member.c | 7 ++ .../mod_conference/conference_video.c | 64 +++++++++++++++++-- .../mod_conference/mod_conference.h | 5 ++ 4 files changed, 124 insertions(+), 6 deletions(-) diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index 46176a03ac..ec129e5bb9 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -103,6 +103,7 @@ api_command_t conference_api_sub_commands[] = { {"vid-mute-img", (void_fn_t) & conference_api_sub_vid_mute_img, CONF_API_SUB_MEMBER_TARGET, "vid-mute-img", " [|clear]"}, {"vid-logo-img", (void_fn_t) & conference_api_sub_vid_logo_img, CONF_API_SUB_MEMBER_TARGET, "vid-logo-img", " [|clear]"}, {"vid-res-id", (void_fn_t) & conference_api_sub_vid_res_id, CONF_API_SUB_MEMBER_TARGET, "vid-res-id", " |clear"}, + {"vid-role-id", (void_fn_t) & conference_api_sub_vid_role_id, CONF_API_SUB_MEMBER_TARGET, "vid-role-id", " |clear"}, {"get-uuid", (void_fn_t) & conference_api_sub_get_uuid, CONF_API_SUB_MEMBER_TARGET, "get-uuid", ""}, {"clear-vid-floor", (void_fn_t) & conference_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""}, {"vid-layout", (void_fn_t) & conference_api_sub_vid_layout, CONF_API_SUB_ARGS_SPLIT, "vid-layout", "|group []"}, @@ -1875,6 +1876,24 @@ static void clear_res_id(conference_obj_t *conference, conference_member_t *memb switch_mutex_unlock(conference->member_mutex); } +static void clear_role_id(conference_obj_t *conference, conference_member_t *member, const char *id) +{ + conference_member_t *imember; + + switch_mutex_lock(conference->member_mutex); + for (imember = conference->members; imember; imember = imember->next) { + if (imember == member) { + continue; + } + + if (imember->video_role_id && !strcasecmp(imember->video_role_id, id)) { + imember->video_role_id = NULL; + conference_video_detach_video_layer(imember); + } + } + switch_mutex_unlock(conference->member_mutex); +} + switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switch_stream_handle_t *stream, void *data) { char *text = (char *) data; @@ -1907,6 +1926,41 @@ switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switc + return SWITCH_STATUS_SUCCESS; + +} + + +switch_status_t conference_api_sub_vid_role_id(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + char *text = (char *) data; + + if (member == NULL) + return SWITCH_STATUS_GENERR; + + if (!switch_channel_test_flag(member->channel, CF_VIDEO)) { + return SWITCH_STATUS_FALSE; + } + + if (!member->conference->canvases[0]) { + stream->write_function(stream, "-ERR conference is not in mixing mode\n"); + return SWITCH_STATUS_SUCCESS; + } + + if (zstr(text) || !strcasecmp(text, "clear") || (member->video_role_id && !strcasecmp(text, member->video_role_id))) { + member->video_role_id = NULL; + stream->write_function(stream, "+OK role_id cleared\n"); + } else { + clear_role_id(member->conference, member, text); + if (!member->video_role_id || strcmp(member->video_role_id, text)) { + member->video_role_id = switch_core_strdup(member->pool, text); + } + stream->write_function(stream, "+OK role_id %s\n", text); + conference_video_find_floor(member, SWITCH_FALSE); + } + + + return SWITCH_STATUS_SUCCESS; } diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index 55958661b3..62fa008277 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -197,6 +197,9 @@ void conference_member_update_status_field(conference_member_t *member) cJSON_AddItemToObject(video, "reservationID", member->video_reservation_id ? cJSON_CreateString(member->video_reservation_id) : cJSON_CreateNull()); + cJSON_AddItemToObject(video, "roleID", member->video_role_id ? + cJSON_CreateString(member->video_role_id) : cJSON_CreateNull()); + cJSON_AddItemToObject(video, "videoLayerID", cJSON_CreateNumber(member->video_layer_id)); cJSON_AddItemToObject(json, "video", video); @@ -759,6 +762,10 @@ switch_status_t conference_member_add(conference_obj_t *conference, conference_m member->video_reservation_id = switch_core_strdup(member->pool, var); } + if ((var = switch_channel_get_variable_dup(member->channel, "video_role_id", SWITCH_FALSE, -1))) { + member->video_role_id = switch_core_strdup(member->pool, var); + } + if ((var = switch_channel_get_variable(channel, "video_use_dedicated_encoder")) && switch_true(var)) { conference_utils_member_set_flag_locked(member, MFLAG_NO_MINIMIZE_ENCODING); } diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index 6c8e744f22..a449cea499 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -110,7 +110,7 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int 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) { video_layout_t *vlayout; - const char *val = NULL, *name = NULL, *bgimg = NULL, *fgimg = NULL; + const char *val = NULL, *name = NULL, *bgimg = NULL, *fgimg = NULL, *transition_in = NULL, *transition_out = NULL; switch_bool_t auto_3d = SWITCH_FALSE; int border = 0; @@ -128,6 +128,9 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int bgimg = switch_xml_attr(x_layout, "bgimg"); fgimg = switch_xml_attr(x_layout, "fgimg"); + transition_in = switch_xml_attr(x_layout, "transition-in"); + transition_out = switch_xml_attr(x_layout, "transition-out"); + if ((val = switch_xml_attr(x_layout, "border"))) { border = atoi(val); if (border < 0) border = 0; @@ -145,8 +148,16 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int vlayout->fgimg = switch_core_strdup(conference->pool, fgimg); } + if (transition_in) { + vlayout->transition_in = switch_core_sprintf(conference->pool, "{full-screen=true}%s", transition_in); + } + + if (transition_out) { + vlayout->transition_out = switch_core_sprintf(conference->pool, "{full-screen=true}%s", transition_out); + } + for (x_image = switch_xml_child(x_layout, "image"); x_image; x_image = x_image->next) { - const char *res_id = NULL, *audio_position = NULL; + const char *res_id = NULL, *audio_position = NULL, *role_id = NULL; int x = -1, y = -1, scale = -1, hscale = -1, floor = 0, flooronly = 0, fileonly = 0, overlap = 0, zoom = 0; if ((val = switch_xml_attr(x_image, "x"))) { @@ -189,6 +200,14 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int res_id = val; } + if ((val = switch_xml_attr(x_image, "reservation-id"))) { + res_id = val; + } + + if ((val = switch_xml_attr(x_image, "role-id"))) { + role_id = val; + } + if ((val = switch_xml_attr(x_image, "audio-position"))) { audio_position = val; } @@ -231,6 +250,10 @@ void conference_video_parse_layouts(conference_obj_t *conference, int WIDTH, int vlayout->images[vlayout->layers].res_id = switch_core_strdup(conference->pool, res_id); } + if (role_id) { + vlayout->images[vlayout->layers].role_id = switch_core_strdup(conference->pool, role_id); + } + if (auto_3d || audio_position) { if (auto_3d || !strcasecmp(audio_position, "auto")) { int x_pos = (int)(WIDTH * x / VIDEO_LAYOUT_SCALE); @@ -1368,6 +1391,11 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva switch_mutex_lock(canvas->mutex); canvas->layout_floor_id = -1; + if (canvas->vlayout && canvas->vlayout->transition_out) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play transition out [%s]\n", canvas->vlayout->transition_out); + conference_file_play(conference, canvas->vlayout->transition_out, 0, NULL, 0); + } + if (!vlayout) { vlayout = canvas->new_vlayout; canvas->new_vlayout = NULL; @@ -1417,10 +1445,11 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva if (layer->geometry.floor) { canvas->layout_floor_id = i; } - + /* if we ever decided to reload layers config on demand the pointer assignment below will lead to segs but we only load them once forever per conference so these pointers are valid for the life of the conference */ layer->geometry.res_id = vlayout->images[i].res_id; + layer->geometry.role_id = vlayout->images[i].role_id; layer->geometry.audio_position = vlayout->images[i].audio_position; } @@ -1469,6 +1498,10 @@ void conference_video_init_canvas_layers(conference_obj_t *conference, mcu_canva switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Canvas position %d applied layout %s\n", canvas->canvas_id + 1, vlayout->name); + if (vlayout->transition_in) { + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Play transition in [%s]\n", vlayout->transition_in); + conference_file_play(conference, vlayout->transition_in, 0, NULL, 0); + } } switch_status_t conference_video_set_canvas_bgimg(mcu_canvas_t *canvas, const char *img_path) @@ -3014,7 +3047,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr layer = NULL; switch_mutex_lock(canvas->mutex); - + if (canvas->layout_floor_id > -1 && imember->id == conference->video_floor_holder && imember->video_layer_id != canvas->layout_floor_id) { conference_video_attach_video_layer(imember, canvas, canvas->layout_floor_id); @@ -3023,8 +3056,27 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr //printf("MEMBER %d layer_id %d canvas: %d/%d\n", imember->id, imember->video_layer_id, // canvas->layers_used, canvas->total_layers); - if (imember->video_layer_id > -1) { + if (imember->video_role_id) { + if (imember->video_layer_id > -1) { + layer = &canvas->layers[imember->video_layer_id]; + } + + if (!layer || (!layer->geometry.role_id || strcmp(layer->geometry.role_id, imember->video_role_id))) { + for (i = 0; i < canvas->total_layers; i++) { + mcu_layer_t *xlayer = &canvas->layers[i]; + + if (imember->video_role_id && xlayer->geometry.role_id && !strcmp(xlayer->geometry.role_id, imember->video_role_id)) { + conference_video_attach_video_layer(imember, canvas, i); + layer = xlayer; + } + } + } + } + + + if (!layer && imember->video_layer_id > -1) { layer = &canvas->layers[imember->video_layer_id]; + if (layer->member_id != (int)imember->id) { imember->video_layer_id = -1; layer = NULL; @@ -3530,7 +3582,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr canvas->send_keyframe = 1; canvas->play_file = 0; } - + switch_img_free(&file_img); file_img = write_img = write_frame.img; diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index ebb70f0978..556380fa85 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -422,6 +422,7 @@ typedef struct mcu_layer_geometry_s { int zoom; int border; char *res_id; + char *role_id; char *audio_position; } mcu_layer_geometry_t; @@ -500,6 +501,8 @@ typedef struct video_layout_s { char *audio_position; char *bgimg; char *fgimg; + char *transition_in; + char *transition_out; mcu_layer_geometry_t images[MCU_MAX_LAYERS]; int layers; } video_layout_t; @@ -834,6 +837,7 @@ struct conference_member { switch_img_fit_t logo_fit; char *video_mute_png; char *video_reservation_id; + char *video_role_id; switch_vid_params_t vid_params; uint32_t auto_kps_debounce_ticks; uint32_t layer_loops; @@ -1181,6 +1185,7 @@ switch_status_t conference_api_sub_vid_banner(conference_member_t *member, switc switch_status_t conference_api_sub_enter_sound(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_set(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_vid_res_id(conference_member_t *member, switch_stream_handle_t *stream, void *data); +switch_status_t conference_api_sub_vid_role_id(conference_member_t *member, switch_stream_handle_t *stream, void *data); switch_status_t conference_api_sub_get_uuid(conference_member_t *member, switch_stream_handle_t *stream, void *data); switch_status_t conference_api_sub_get(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv); switch_status_t conference_api_sub_vid_mute_img(conference_member_t *member, switch_stream_handle_t *stream, void *data);