From 7f3878dfcb363bb7b895acf437a5faec58a9007f Mon Sep 17 00:00:00 2001 From: Mike Jerris Date: Thu, 21 Jun 2018 05:32:22 -0400 Subject: [PATCH] FS-11206: [mod_conference] add conference hold feature --- .../mod_conference/conference_al.c | 8 +- .../mod_conference/conference_api.c | 163 ++++++++++++++++++ .../mod_conference/conference_loop.c | 20 ++- .../mod_conference/conference_member.c | 5 +- .../mod_conference/conference_utils.c | 6 +- .../mod_conference/conference_video.c | 29 +++- .../mod_conference/mod_conference.c | 36 ++-- .../mod_conference/mod_conference.h | 5 +- 8 files changed, 242 insertions(+), 30 deletions(-) diff --git a/src/mod/applications/mod_conference/conference_al.c b/src/mod/applications/mod_conference/conference_al.c index 41eeb8cda1..2d4f0ad7a9 100644 --- a/src/mod/applications/mod_conference/conference_al.c +++ b/src/mod/applications/mod_conference/conference_al.c @@ -78,7 +78,9 @@ void conference_al_gen_arc(conference_obj_t *conference, switch_stream_handle_t switch_mutex_lock(conference->member_mutex); for (member = conference->members; member; member = member->next) { - if (member->channel && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_NO_POSITIONAL)) { + if (member->channel && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && + !conference_utils_member_test_flag(member, MFLAG_HOLD) && + !conference_utils_member_test_flag(member, MFLAG_NO_POSITIONAL)) { count++; } } @@ -112,7 +114,9 @@ void conference_al_gen_arc(conference_obj_t *conference, switch_stream_handle_t for (member = conference->members; member; member = member->next) { - if (!member->channel || conference_utils_member_test_flag(member, MFLAG_NO_POSITIONAL) || !conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!member->channel || conference_utils_member_test_flag(member, MFLAG_NO_POSITIONAL) || + conference_utils_member_test_flag(member, MFLAG_HOLD) || + !conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { continue; } diff --git a/src/mod/applications/mod_conference/conference_api.c b/src/mod/applications/mod_conference/conference_api.c index d4c427d8db..96c2bc8bc4 100644 --- a/src/mod/applications/mod_conference/conference_api.c +++ b/src/mod/applications/mod_conference/conference_api.c @@ -72,6 +72,8 @@ api_command_t conference_api_sub_commands[] = { {"vid-flip", (void_fn_t) & conference_api_sub_vid_flip, CONF_API_SUB_MEMBER_TARGET, "vid-flip", "<[member_id|all|last|non_moderator]>"}, {"vid-border", (void_fn_t) & conference_api_sub_vid_border, CONF_API_SUB_MEMBER_TARGET, "vid-border", "<[member_id|all|last|non_moderator]>"}, {"hup", (void_fn_t) & conference_api_sub_hup, CONF_API_SUB_MEMBER_TARGET, "hup", "<[member_id|all|last|non_moderator]>"}, + {"hold", (void_fn_t) & conference_api_sub_hold, CONF_API_SUB_MEMBER_TARGET, "hold", "<[member_id|all]|last|non_moderator> [file]"}, + {"unhold", (void_fn_t) & conference_api_sub_unhold, CONF_API_SUB_MEMBER_TARGET, "unhold", "<[member_id|all]|last|non_moderator>"}, {"mute", (void_fn_t) & conference_api_sub_mute, CONF_API_SUB_MEMBER_TARGET, "mute", "<[member_id|all]|last|non_moderator> []"}, {"tmute", (void_fn_t) & conference_api_sub_tmute, CONF_API_SUB_MEMBER_TARGET, "tmute", "<[member_id|all]|last|non_moderator> []"}, {"unmute", (void_fn_t) & conference_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "unmute", "<[member_id|all]|last|non_moderator> []"}, @@ -313,6 +315,11 @@ switch_status_t conference_api_sub_mute(conference_member_t *member, switch_stre if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR mute %u\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_clear_flag_locked(member, MFLAG_CAN_SPEAK); conference_utils_member_clear_flag_locked(member, MFLAG_TALKING); @@ -345,6 +352,107 @@ switch_status_t conference_api_sub_mute(conference_member_t *member, switch_stre return SWITCH_STATUS_SUCCESS; } +switch_status_t conference_api_sub_unhold(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + mcu_layer_t *layer = NULL; + switch_event_t *event; + + if (member == NULL) + return SWITCH_STATUS_GENERR; + + conference_utils_member_clear_flag_locked(member, MFLAG_HOLD); + + if (member->session && !conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT)) { + switch_core_media_hard_mute(member->session, SWITCH_FALSE); + } + + conference_member_stop_file(member, FILE_STOP_ALL); + + if (switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY) { + if ((layer = conference_video_get_layer_locked(member))) { + layer->clear = 1; + conference_video_release_layer(&layer); + } + + conference_video_reset_video_bitrate_counters(member); + + if (member->channel) { + switch_channel_clear_flag(member->channel, CF_VIDEO_PAUSE_READ); + switch_channel_video_sync(member->channel); + } + } + + if (stream != NULL) { + stream->write_function(stream, "+OK unhold %u\n", member->id); + } + + if (test_eflag(member->conference, EFLAG_HOLD_MEMBER) && + switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { + conference_member_add_event_data(member, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "unhold-member"); + switch_event_fire(&event); + } + + if (conference_utils_test_flag(member->conference, CFLAG_POSITIONAL)) { + conference_al_gen_arc(member->conference, NULL); + } + + conference_member_update_status_field(member); + + return SWITCH_STATUS_SUCCESS; +} + +switch_status_t conference_api_sub_hold(conference_member_t *member, switch_stream_handle_t *stream, void *data) +{ + switch_event_t *event; + + if (member == NULL) + return SWITCH_STATUS_GENERR; + + conference_utils_member_clear_flag_locked(member, MFLAG_TALKING); + + if (switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY) { + conference_video_reset_video_bitrate_counters(member); + + if (member->channel) { + switch_channel_set_flag(member->channel, CF_VIDEO_PAUSE_READ); + switch_core_session_request_video_refresh(member->session); + switch_channel_video_sync(member->channel); + } + } + + if (member->session) { + switch_core_media_hard_mute(member->session, SWITCH_TRUE); + } + + conference_utils_member_set_flag(member, MFLAG_HOLD); + + conference_member_set_score_iir(member, 0); + + if (!zstr(data)) { + conference_member_play_file(member, data, 0, SWITCH_FALSE); + } + + if (stream != NULL) { + stream->write_function(stream, "+OK hold %u\n", member->id); + } + + if (test_eflag(member->conference, EFLAG_HOLD_MEMBER) && + switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { + conference_member_add_event_data(member, event); + switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "hold-member"); + switch_event_fire(&event); + } + + if (conference_utils_test_flag(member->conference, CFLAG_POSITIONAL)) { + conference_al_gen_arc(member->conference, NULL); + } + + conference_member_update_status_field(member); + + return SWITCH_STATUS_SUCCESS; +} + switch_status_t conference_api_sub_tmute(conference_member_t *member, switch_stream_handle_t *stream, void *data) { @@ -352,6 +460,11 @@ switch_status_t conference_api_sub_tmute(conference_member_t *member, switch_str if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR mute %u\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { return conference_api_sub_mute(member, stream, data); } @@ -367,6 +480,11 @@ switch_status_t conference_api_sub_unmute(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR unmute %u\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_set_flag_locked(member, MFLAG_CAN_SPEAK); if (member->session && !conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT)) { @@ -413,6 +531,11 @@ switch_status_t conference_api_sub_conference_video_vmute_snap(conference_member return SWITCH_STATUS_SUCCESS; } + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + if (stream != NULL) { stream->write_function(stream, "+OK vmute image snapped %u\n", member->id); } @@ -437,6 +560,11 @@ switch_status_t conference_api_sub_vmute(conference_member_t *member, switch_str return SWITCH_STATUS_SUCCESS; } + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_clear_flag_locked(member, MFLAG_CAN_BE_SEEN); conference_video_reset_video_bitrate_counters(member); @@ -473,6 +601,11 @@ switch_status_t conference_api_sub_tvmute(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) { return conference_api_sub_vmute(member, stream, data); } @@ -493,6 +626,11 @@ switch_status_t conference_api_sub_unvmute(conference_member_t *member, switch_s return SWITCH_STATUS_SUCCESS; } + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + if ((layer = conference_video_get_layer_locked(member))) { layer->clear = 1; conference_video_release_layer(&layer); @@ -534,6 +672,11 @@ switch_status_t conference_api_sub_vblind(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + switch_core_session_write_blank_video(member->session, 50); conference_utils_member_clear_flag_locked(member, MFLAG_CAN_SEE); conference_video_reset_video_bitrate_counters(member); @@ -565,6 +708,11 @@ switch_status_t conference_api_sub_tvblind(conference_member_t *member, switch_s if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + if (conference_utils_member_test_flag(member, MFLAG_CAN_SEE)) { return conference_api_sub_vblind(member, stream, data); } @@ -580,6 +728,11 @@ switch_status_t conference_api_sub_unvblind(conference_member_t *member, switch_ if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_set_flag_locked(member, MFLAG_CAN_SEE); conference_video_reset_video_bitrate_counters(member); @@ -613,6 +766,11 @@ switch_status_t conference_api_sub_deaf(conference_member_t *member, switch_stre if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_clear_flag_locked(member, MFLAG_CAN_HEAR); if (!(data) || !strstr((char *) data, "quiet")) { @@ -655,6 +813,11 @@ switch_status_t conference_api_sub_undeaf(conference_member_t *member, switch_st if (member == NULL) return SWITCH_STATUS_GENERR; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + if (stream) stream->write_function(stream, "-ERR member %u is on hold\n", member->id); + return SWITCH_STATUS_SUCCESS; + } + conference_utils_member_set_flag_locked(member, MFLAG_CAN_HEAR); if (!(data) || !strstr((char *) data, "quiet")) { diff --git a/src/mod/applications/mod_conference/conference_loop.c b/src/mod/applications/mod_conference/conference_loop.c index 60e5056435..49377312c6 100644 --- a/src/mod/applications/mod_conference/conference_loop.c +++ b/src/mod/applications/mod_conference/conference_loop.c @@ -132,6 +132,8 @@ void conference_loop_mute_toggle(conference_member_t *member, caller_control_act if (member == NULL) return; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return; + if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { conference_api_sub_mute(member, NULL, NULL); } else { @@ -144,6 +146,8 @@ void conference_loop_mute_toggle(conference_member_t *member, caller_control_act void conference_loop_mute_on(conference_member_t *member, caller_control_action_t *action) { + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return; + if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { conference_api_sub_mute(member, NULL, NULL); } @@ -151,6 +155,8 @@ void conference_loop_mute_on(conference_member_t *member, caller_control_action_ void conference_loop_mute_off(conference_member_t *member, caller_control_action_t *action) { + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return; + if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { conference_api_sub_unmute(member, NULL, NULL); if (!conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) { @@ -280,6 +286,8 @@ void conference_loop_deafmute_toggle(conference_member_t *member, caller_control if (member == NULL) return; + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) return; + if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { conference_api_sub_mute(member, NULL, NULL); if (conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) { @@ -933,7 +941,8 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob /* if the member can speak, compute the audio energy level and */ /* generate events when the level crosses the threshold */ - if ((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) || conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) { + if (((conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) || + conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT))) { uint32_t energy = 0, i = 0, samples = 0, j = 0; int16_t *data; int gate_check = 0; @@ -990,7 +999,7 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob gate_check = conference_member_noise_gate_check(member); - if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { + if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) { if (member->max_energy_level) { if (member->score > member->max_energy_level && ++member->max_energy_hits > member->max_energy_hit_trigger) { member->mute_counter = member->burst_mute_count; @@ -1131,6 +1140,7 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob member->talking_count = 0; if (test_eflag(member->conference, EFLAG_START_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && + !conference_utils_member_test_flag(member, MFLAG_HOLD) && switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT) == SWITCH_STATUS_SUCCESS) { conference_member_add_event_data(member, event); switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "start-talking"); @@ -1157,7 +1167,8 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob hangunder_hits--; } - if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { + if (conference_utils_member_test_flag(member, MFLAG_TALKING) && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && + !conference_utils_member_test_flag(member, MFLAG_HOLD)) { if (++hangover_hits >= hangover) { hangover_hits = hangunder_hits = 0; @@ -1188,7 +1199,8 @@ void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *ob /* skip frames that are not actual media or when we are muted or silent */ if ((conference_utils_member_test_flag(member, MFLAG_TALKING) || member->energy_level == 0 || conference_utils_test_flag(member->conference, CFLAG_AUDIO_ALWAYS)) - && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD) + && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) && !conference_utils_test_flag(member->conference, CFLAG_WAIT_MOD) + && !conference_utils_member_test_flag(member, MFLAG_HOLD) && (member->conference->count > 1 || (member->conference->record_count && member->conference->count >= member->conference->min_recording_participants))) { switch_audio_resampler_t *read_resampler = member->read_resampler; void *data; diff --git a/src/mod/applications/mod_conference/conference_member.c b/src/mod/applications/mod_conference/conference_member.c index b530a6e3ff..d72fcf5153 100644 --- a/src/mod/applications/mod_conference/conference_member.c +++ b/src/mod/applications/mod_conference/conference_member.c @@ -133,7 +133,9 @@ void conference_member_update_status_field(conference_member_t *member) switch_live_array_lock(member->conference->la); - if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + str = "HOLD"; + } else if (!conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { str = "MUTE"; } else if (switch_channel_test_flag(member->channel, CF_HOLD)) { str = "HOLD"; @@ -258,6 +260,7 @@ switch_status_t conference_member_add_event_data(conference_member_t *member, sw switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Speak", "%s", conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false" ); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Talking", "%s", conference_utils_member_test_flag(member, MFLAG_TALKING) ? "true" : "false" ); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Mute-Detect", "%s", conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false" ); + switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Hold", "%s", conference_utils_member_test_flag(member, MFLAG_HOLD) ? "true" : "false" ); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-ID", "%u", member->id); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Type", "%s", conference_utils_member_test_flag(member, MFLAG_MOD) ? "moderator" : "member"); switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Member-Ghost", "%s", conference_utils_member_test_flag(member, MFLAG_GHOST) ? "true" : "false"); diff --git a/src/mod/applications/mod_conference/conference_utils.c b/src/mod/applications/mod_conference/conference_utils.c index 5940c06358..c1932ead74 100644 --- a/src/mod/applications/mod_conference/conference_utils.c +++ b/src/mod/applications/mod_conference/conference_utils.c @@ -237,9 +237,7 @@ void conference_utils_clear_eflags(char *events, uint32_t *f) *next++ = '\0'; } - if (!strcmp(event, "add-member")) { - *f &= ~EFLAG_ADD_MEMBER; - } else if (!strcmp(event, "del-member")) { + if (!strcmp(event, "del-member")) { *f &= ~EFLAG_DEL_MEMBER; } else if (!strcmp(event, "energy-level")) { *f &= ~EFLAG_ENERGY_LEVEL; @@ -257,6 +255,8 @@ void conference_utils_clear_eflags(char *events, uint32_t *f) *f &= ~EFLAG_MUTE_DETECT; } else if (!strcmp(event, "mute-member")) { *f &= ~EFLAG_MUTE_MEMBER; + } else if (!strcmp(event, "hold-member")) { + *f &= ~EFLAG_HOLD_MEMBER; } else if (!strcmp(event, "kick-member")) { *f &= ~EFLAG_KICK_MEMBER; } else if (!strcmp(event, "dtmf-member")) { diff --git a/src/mod/applications/mod_conference/conference_video.c b/src/mod/applications/mod_conference/conference_video.c index 44ad6d3d54..859b135515 100644 --- a/src/mod/applications/mod_conference/conference_video.c +++ b/src/mod/applications/mod_conference/conference_video.c @@ -1414,6 +1414,10 @@ switch_status_t conference_video_attach_video_layer(conference_member_t *member, return SWITCH_STATUS_FALSE; } + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + conference_utils_member_clear_flag(member, MFLAG_DED_VID_LAYER); + return SWITCH_STATUS_FALSE; + } if (!switch_channel_test_flag(channel, CF_VIDEO_READY) && !member->avatar_png_img) { conference_utils_member_clear_flag(member, MFLAG_DED_VID_LAYER); @@ -1425,6 +1429,8 @@ switch_status_t conference_video_attach_video_layer(conference_member_t *member, return SWITCH_STATUS_FALSE; } + + switch_mutex_lock(canvas->mutex); layer = &canvas->layers[idx]; @@ -2606,6 +2612,10 @@ switch_status_t conference_video_find_layer(conference_obj_t *conference, mcu_ca return SWITCH_STATUS_FALSE; } + if (conference_utils_member_test_flag(member, MFLAG_HOLD)) { + return SWITCH_STATUS_FALSE; + } + switch_mutex_lock(canvas->mutex); for (i = 0; i < canvas->total_layers; i++) { @@ -2730,7 +2740,7 @@ void conference_video_pop_next_image(conference_member_t *member, switch_image_t size = switch_queue_size(member->video_queue); } while(size > 1); - if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) && + if (conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) && !conference_utils_member_test_flag(member, MFLAG_HOLD) && member->video_layer_id > -1 && switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY && switch_core_session_media_flow(member->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_INACTIVE @@ -2961,7 +2971,7 @@ void conference_video_check_auto_bitrate(conference_member_t *member, mcu_layer_ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s setting bitrate to %dkps because it was forced.\n", switch_channel_get_name(member->channel), kps); } else { - if (layer && conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN)) { + if (layer && conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) && !conference_utils_member_test_flag(member, MFLAG_HOLD)) { if (layer->screen_w != screen_w) { switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "%s auto-setting bitrate to %dkps (max res %dx%d) to accommodate %dx%d resolution\n", switch_channel_get_name(member->channel), kps, screen_w, screen_h, layer->screen_w, layer->screen_h); @@ -3177,6 +3187,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr int no_muted = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS); int no_av = conference_utils_test_flag(imember->conference, CFLAG_VIDEO_REQUIRED_FOR_CANVAS); int seen = conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN); + int hold = conference_utils_member_test_flag(imember, MFLAG_HOLD); if (imember->channel && switch_channel_ready(imember->channel) && switch_channel_test_flag(imember->channel, CF_VIDEO_READY) && imember->watching_canvas_id == canvas->canvas_id) { @@ -3184,7 +3195,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr } if (imember->channel && switch_channel_ready(imember->channel) && switch_channel_test_flag(imember->channel, CF_VIDEO_READY) && - !conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) && + !conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) && !hold && conference_utils_member_test_flag(imember, MFLAG_RUNNING) && (!no_muted || seen) && (!no_av || (no_av && !imember->avatar_png_img)) && imember->canvas_id == canvas->canvas_id && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY && imember->video_media_flow != SWITCH_MEDIA_FLOW_INACTIVE) { video_count++; @@ -3403,8 +3414,9 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr continue; } - if (conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) && - !conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN) && imember->video_layer_id > -1) { + if ((conference_utils_member_test_flag(imember, MFLAG_HOLD) || + (conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) && + !conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN))) && imember->video_layer_id > -1) { conference_video_detach_video_layer(imember); switch_img_free(&imember->video_mute_img); @@ -3518,7 +3530,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr // switch_img_free(&layer->cur_img); //} - if (conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN) || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE || conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS)) { + if ((conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN) && !conference_utils_member_test_flag(imember, MFLAG_HOLD)) || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_SENDONLY || switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_MEDIA_FLOW_INACTIVE || conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS)) { layer->mute_patched = 0; } else { @@ -3637,7 +3649,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr if (total > 0 && (!conference_utils_test_flag(imember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) || - conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN)) && + (conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN) && !conference_utils_member_test_flag(imember, MFLAG_HOLD))) && imember->session && switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_SENDONLY && imember->session && switch_core_session_media_flow(imember->session, SWITCH_MEDIA_TYPE_VIDEO) != SWITCH_MEDIA_FLOW_INACTIVE) { @@ -3804,7 +3816,7 @@ void *SWITCH_THREAD_FUNC conference_video_muxing_thread_run(switch_thread_t *thr } if (layer) { - if (conference_utils_member_test_flag(omember, MFLAG_CAN_BE_SEEN)) { + if (conference_utils_member_test_flag(omember, MFLAG_CAN_BE_SEEN) && !conference_utils_member_test_flag(imember, MFLAG_HOLD)) { layer->mute_patched = 0; } else if (!conference_utils_test_flag(omember->conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS)) { if (!layer->mute_patched) { @@ -4954,6 +4966,7 @@ switch_status_t conference_video_thread_callback(switch_core_session_t *session, if (frame->img && (((member->video_layer_id > -1) && canvas_id > -1) || member->canvas) && conference_utils_member_test_flag(member, MFLAG_CAN_BE_SEEN) && + !conference_utils_member_test_flag(member, MFLAG_HOLD) && switch_queue_size(member->video_queue) < member->conference->video_fps.fps && !member->conference->canvases[canvas_id]->playing_video_file) { diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 7b9c8207c8..6efb7c72df 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -84,6 +84,7 @@ void conference_list(conference_obj_t *conference, switch_stream_handle_t *strea char *uuid; char *name; uint32_t count = 0; + switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD); if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) { continue; @@ -97,21 +98,26 @@ void conference_list(conference_obj_t *conference, switch_stream_handle_t *strea stream->write_function(stream, "%u%s%s%s%s%s%s%s%s%s", member->id, delim, name, delim, uuid, delim, profile->caller_id_name, delim, profile->caller_id_number, delim); - if (conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) { + if (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) { stream->write_function(stream, "hear"); count++; } - if (conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { + if (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) { stream->write_function(stream, "%s%s", count ? "|" : "", "speak"); count++; } - if (conference_utils_member_test_flag(member, MFLAG_TALKING)) { + if (!hold && conference_utils_member_test_flag(member, MFLAG_TALKING)) { stream->write_function(stream, "%s%s", count ? "|" : "", "talking"); count++; } + if (hold) { + stream->write_function(stream, "%s%s", count ? "|" : "", "hold"); + count++; + } + if (switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO)) { stream->write_function(stream, "%s%s", count ? "|" : "", "video"); count++; @@ -331,6 +337,7 @@ void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *ob switch_channel_test_flag(channel, CF_VIDEO_READY) && imember->video_media_flow != SWITCH_MEDIA_FLOW_SENDONLY && !conference_utils_member_test_flag(imember, MFLAG_SECOND_SCREEN) && + !conference_utils_member_test_flag(imember, MFLAG_HOLD) && (!conference_utils_test_flag(conference, CFLAG_VIDEO_MUTE_EXIT_CANVAS) || conference_utils_member_test_flag(imember, MFLAG_CAN_BE_SEEN))) { members_with_video++; @@ -1225,7 +1232,8 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i switch_xml_t x_tag; int toff = 0; char tmp[50] = ""; - + switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD); + if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) { if (member->rec_path) { x_member = switch_xml_add_child_d(x_members, "member", moff++); @@ -1286,19 +1294,22 @@ void conference_xlist(conference_obj_t *conference, switch_xml_t x_conference, i switch_assert(x_flags); x_tag = switch_xml_add_child_d(x_flags, "can_hear", count++); - switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_CAN_HEAR) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "can_see", count++); - switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_CAN_SEE) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SEE)) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "can_speak", count++); - switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "mute_detect", count++); switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT) ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "talking", count++); - switch_xml_set_txt_d(x_tag, conference_utils_member_test_flag(member, MFLAG_TALKING) ? "true" : "false"); + switch_xml_set_txt_d(x_tag, (!hold && conference_utils_member_test_flag(member, MFLAG_TALKING)) ? "true" : "false"); + + x_tag = switch_xml_add_child_d(x_flags, "hold", count++); + switch_xml_set_txt_d(x_tag, hold ? "true" : "false"); x_tag = switch_xml_add_child_d(x_flags, "has_video", count++); switch_xml_set_txt_d(x_tag, switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO) ? "true" : "false"); @@ -1374,6 +1385,8 @@ void conference_jlist(conference_obj_t *conference, cJSON *json_conferences) switch_channel_t *channel; switch_caller_profile_t *profile; char *uuid; + switch_bool_t hold = conference_utils_member_test_flag(member, MFLAG_HOLD); + cJSON_AddItemToObject(json_conference_members, "member", json_conference_member = cJSON_CreateObject()); if (conference_utils_member_test_flag(member, MFLAG_NOCHANNEL)) { @@ -1405,9 +1418,10 @@ void conference_jlist(conference_obj_t *conference, cJSON *json_conferences) cJSON_AddNumberToObject(json_conference_member, "volume_out", member->volume_out_level); cJSON_AddNumberToObject(json_conference_member, "output-volume", member->volume_out_level); cJSON_AddNumberToObject(json_conference_member, "input-volume", member->volume_in_level); - ADDBOOL(json_conference_member_flags, "can_hear", conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)); - ADDBOOL(json_conference_member_flags, "can_see", conference_utils_member_test_flag(member, MFLAG_CAN_SEE)); - ADDBOOL(json_conference_member_flags, "can_speak", conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)); + ADDBOOL(json_conference_member_flags, "can_hear", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_HEAR)); + ADDBOOL(json_conference_member_flags, "can_see", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_SEE)); + ADDBOOL(json_conference_member_flags, "can_speak", !hold && conference_utils_member_test_flag(member, MFLAG_CAN_SPEAK)); + ADDBOOL(json_conference_member_flags, "hold", hold); ADDBOOL(json_conference_member_flags, "mute_detect", conference_utils_member_test_flag(member, MFLAG_MUTE_DETECT)); ADDBOOL(json_conference_member_flags, "talking", conference_utils_member_test_flag(member, MFLAG_TALKING)); ADDBOOL(json_conference_member_flags, "has_video", switch_channel_test_flag(switch_core_session_get_channel(member->session), CF_VIDEO)); diff --git a/src/mod/applications/mod_conference/mod_conference.h b/src/mod/applications/mod_conference/mod_conference.h index c4f7b14fba..60920410a2 100644 --- a/src/mod/applications/mod_conference/mod_conference.h +++ b/src/mod/applications/mod_conference/mod_conference.h @@ -220,6 +220,7 @@ typedef enum { MFLAG_NO_VIDEO_BLANKS, MFLAG_VIDEO_JOIN, MFLAG_DED_VID_LAYER, + MFLAG_HOLD, /////////////////////////// MFLAG_MAX } member_flag_t; @@ -322,7 +323,7 @@ typedef enum { } node_flag_t; typedef enum { - EFLAG_ADD_MEMBER = (1 << 0), + EFLAG_HOLD_MEMBER = (1 << 0), EFLAG_DEL_MEMBER = (1 << 1), EFLAG_ENERGY_LEVEL = (1 << 2), EFLAG_VOLUME_LEVEL = (1 << 3), @@ -1210,6 +1211,8 @@ switch_status_t conference_api_sub_file_seek(conference_obj_t *conference, switc 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_hold(conference_member_t *member, switch_stream_handle_t *stream, void *data); +switch_status_t conference_api_sub_unhold(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); switch_status_t conference_api_sub_volume_out(conference_member_t *member, switch_stream_handle_t *stream, void *data); switch_status_t conference_api_sub_lock(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv);