]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-11206: [mod_conference] add conference hold feature
authorMike Jerris <mike@jerris.com>
Thu, 21 Jun 2018 09:32:22 +0000 (05:32 -0400)
committerMuteesa Fred <muteesafred@hotmail.com>
Tue, 24 Jul 2018 07:21:56 +0000 (07:21 +0000)
src/mod/applications/mod_conference/conference_al.c
src/mod/applications/mod_conference/conference_api.c
src/mod/applications/mod_conference/conference_loop.c
src/mod/applications/mod_conference/conference_member.c
src/mod/applications/mod_conference/conference_utils.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

index 41eeb8cda1be097383b73902a56f66b4ceea1f56..2d4f0ad7a9c943da121017f33f95224bd0741d14 100644 (file)
@@ -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;
                }
 
index d4c427d8db7881e79ee8679abcc6383c7ac35e2f..96c2bc8bc41734aad92ffcd8b8fb2a6feec9852a 100644 (file)
@@ -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> [<quiet>]"},
        {"tmute", (void_fn_t) & conference_api_sub_tmute, CONF_API_SUB_MEMBER_TARGET, "tmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
        {"unmute", (void_fn_t) & conference_api_sub_unmute, CONF_API_SUB_MEMBER_TARGET, "unmute", "<[member_id|all]|last|non_moderator> [<quiet>]"},
@@ -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")) {
index 60e5056435c78ce9909758d41888d171e0af66df..49377312c647b409d3464d6e0ee11bad90291815 100644 (file)
@@ -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;
index b530a6e3fff246cac505153686f6d8443428763a..d72fcf5153f38c804e6d0ffc22ff8464c4cb31e5 100644 (file)
@@ -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");
index 5940c06358d962d6c71bbbc8f10ffd6cce91adaf..c1932ead7477a73bd78699c6f205d23cc62703e2 100644 (file)
@@ -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")) {
index 44ad6d3d54045835ea57f4a74fb6a60365877add..859b135515e3a37957c7a046f05942d95cd84b61 100644 (file)
@@ -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) {
 
index 7b9c8207c826f65197ef8c6c90517e8ce9bb44c5..6efb7c72dff0ff96fb5f924978cd42452bda2454 100644 (file)
@@ -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));
index c4f7b14fba77f6d7f6912a63f7653fa4a018c3f7..60920410a2ca13b8b037089501bfd4ea8b482617 100644 (file)
@@ -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);