switch_mutex_t *mutex;
conference_member_t *members;
conference_member_t *floor_holder;
+ conference_member_t *video_floor_holder;
switch_mutex_t *member_mutex;
conference_file_node_t *fnode;
conference_file_node_t *async_fnode;
static void launch_conference_record_thread(conference_obj_t *conference, char *path);
static int launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b);
-static void launch_conference_video_mirror_thread(conference_member_t *member_a);
typedef switch_status_t (*conf_api_args_cmd_t) (conference_obj_t *, switch_stream_handle_t *, int, char **);
typedef switch_status_t (*conf_api_member_cmd_t) (conference_member_t *, switch_stream_handle_t *, void *);
static switch_status_t conference_add_event_data(conference_obj_t *conference, switch_event_t *event);
static switch_status_t conference_add_event_member_data(conference_member_t *member, switch_event_t *event);
static switch_status_t conf_api_sub_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data);
+static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data);
+static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference, switch_stream_handle_t *stream, void *data);
static switch_status_t conf_api_sub_enforce_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data);
if (switch_channel_test_flag(channel, CF_VIDEO)) {
- switch_channel_clear_flag(channel, CF_VIDEO_ECHO);
+ if (!switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
+ switch_channel_clear_flag(channel, CF_VIDEO_ECHO);
+ }
/* Tell the channel to request a fresh vid frame */
switch_core_session_refresh_video(member->session);
}
return status;
}
+static void conference_set_video_floor_holder(conference_obj_t *conference, conference_member_t *member)
+{
+ switch_event_t *event;
+ int old_id = 0;
+
+ if (switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
+ return;
+ }
+
+ if (conference->video_floor_holder) {
+ if (conference->video_floor_holder == member) {
+ return;
+ } else {
+ old_id = conference->video_floor_holder->id;
+ switch_channel_clear_flag(conference->video_floor_holder->channel, CF_VIDEO_PASSIVE);
+ switch_core_session_refresh_video(conference->video_floor_holder->session);
+ }
+ }
+
+ if ((conference->video_floor_holder = member)) {
+ switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE);
+ switch_core_session_refresh_video(conference->video_floor_holder->session);
+ switch_set_flag(conference, CFLAG_FLOOR_CHANGE);
+ }
+
+ if (old_id > -1 && test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
+ switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
+ conference_add_event_data(conference, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "video-floor-change");
+ if (old_id) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", old_id);
+ } else {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
+ }
+ if (conference->video_floor_holder) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", conference->video_floor_holder->id);
+ } else {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
+ }
+ switch_event_fire(&event);
+ }
+
+}
+
static void conference_set_floor_holder(conference_obj_t *conference, conference_member_t *member)
{
+ switch_event_t *event;
+ int old_id = 0;
- if (conference->floor_holder && conference->floor_holder != member) {
- switch_channel_clear_flag(conference->floor_holder->channel, CF_VIDEO_PASSIVE);
+ if (conference->floor_holder) {
+ if (conference->floor_holder == member) {
+ return;
+ } else {
+ old_id = conference->floor_holder->id;
+ if (!conference->video_floor_holder && !switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
+ switch_channel_clear_flag(conference->floor_holder->channel, CF_VIDEO_PASSIVE);
+ switch_core_session_refresh_video(conference->floor_holder->session);
+ }
+ }
}
if ((conference->floor_holder = member)) {
- switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE);
- switch_core_session_refresh_video(conference->floor_holder->session);
+ if (!conference->video_floor_holder && !switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
+ switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE);
+ switch_core_session_refresh_video(conference->floor_holder->session);
+ }
switch_set_flag(conference, CFLAG_FLOOR_CHANGE);
}
+
+ if (old_id > -1 && test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
+ switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
+ conference_add_event_data(conference, event);
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
+ if (old_id) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", old_id);
+ } else {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
+ }
+
+ if (conference->floor_holder) {
+ switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", conference->floor_holder->id);
+ } else {
+ switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
+ }
+
+ switch_event_fire(&event);
+ }
+
}
/* Gain exclusive access and remove the member from the list */
}
if (member == member->conference->floor_holder) {
- //member->conference->floor_holder = NULL;
conference_set_floor_holder(member->conference, NULL);
+ }
- if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
- switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
- conference_add_event_data(conference, event);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", member->id);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
- switch_event_fire(&event);
- }
+ if (member == member->conference->video_floor_holder) {
+ conference_set_video_floor_holder(member->conference, NULL);
}
member->conference = NULL;
switch_thread_rwlock_rdlock(vh->member_b->rwlock);
+ switch_channel_set_flag(channel_a, CF_VIDEO_PASSIVE);
+
/* Acquire locks for both sessions so the helper object and member structures don't get destroyed before we exit */
switch_core_session_read_lock(session_a);
switch_core_session_read_lock(session_b);
}
}
}
+ switch_channel_clear_flag(channel_a, CF_VIDEO_PASSIVE);
switch_thread_rwlock_unlock(vh->member_b->rwlock);
switch_thread_rwlock_unlock(vh->member_a->rwlock);
}
-
-static void *SWITCH_THREAD_FUNC conference_video_mirror_thread_run(switch_thread_t *thread, void *obj)
-{
- struct vid_helper *vh = obj;
- switch_core_session_t *session_a = vh->member_a->session;
- switch_channel_t *channel_a = switch_core_session_get_channel(session_a);
- switch_status_t status;
- switch_frame_t *read_frame;
- conference_obj_t *conference = vh->member_a->conference;
- switch_core_session_message_t msg = { 0 };
-
- switch_thread_rwlock_rdlock(conference->rwlock);
- switch_thread_rwlock_rdlock(vh->member_a->rwlock);
-
- /* Acquire locks for both sessions so the helper object and member structures don't get destroyed before we exit */
- switch_core_session_read_lock(session_a);
-
- /* Tell the channel to request a fresh vid frame */
- msg.from = __FILE__;
- msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
- switch_core_session_receive_message(session_a, &msg);
-
- vh->up = 1;
- while (vh->up > 0 && switch_test_flag(vh->member_a, MFLAG_RUNNING) &&
- switch_channel_ready(channel_a)) {
-
- if (vh->up == 1) {
- status = switch_core_session_read_video_frame(session_a, &read_frame, SWITCH_IO_FLAG_NONE, 0);
- if (!SWITCH_READ_ACCEPTABLE(status)) {
- break;
- }
-
- if (!switch_test_flag(read_frame, SFF_CNG)) {
- if (switch_core_session_write_video_frame(session_a, read_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) {
- break;
- }
- }
- } else {
- switch_yield(100000);
- }
- }
-
-
- switch_thread_rwlock_unlock(vh->member_a->rwlock);
-
- switch_core_session_rwunlock(session_a);
-
- switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s video mirror thread ended.\n", switch_channel_get_name(channel_a));
-
- switch_thread_rwlock_unlock(conference->rwlock);
-
- vh->up = 0;
- return NULL;
-}
-
-
/* Main video monitor thread (1 per distinct conference room) */
static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thread, void *obj)
{
int yield = 0;
switch_core_session_t *session;
char buf[65536];
+ conference_member_t *floor_holder = NULL;
conference->video_running = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video thread started for conference %s\n", conference->name);
switch_mutex_lock(conference->mutex);
- if (!conference->floor_holder) {
+ if (conference->video_floor_holder) {
+ floor_holder = conference->video_floor_holder;
+ } else {
+ floor_holder = conference->floor_holder;
+ }
+
+
+ if (!floor_holder) {
yield = 100000;
goto do_continue;
}
- if (!switch_channel_test_flag(switch_core_session_get_channel(conference->floor_holder->session), CF_VIDEO)) {
+ if (!switch_channel_test_flag(switch_core_session_get_channel(floor_holder->session), CF_VIDEO)) {
yield = 100000;
goto do_continue;
}
- session = conference->floor_holder->session;
+ session = floor_holder->session;
if ((status = switch_core_session_read_lock(session)) == SWITCH_STATUS_SUCCESS) {
switch_mutex_unlock(conference->mutex);
switch_mutex_unlock(imember->audio_in_mutex);
}
-
-
if (floor_holder != conference->floor_holder) {
- switch_event_t *event = NULL;
-
- if (test_eflag(conference, EFLAG_FLOOR_CHANGE)) {
- switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
-
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
-
- if (floor_holder) {
- conference_add_event_member_data(floor_holder, event);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", floor_holder->id);
- } else {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
- }
-
- if (conference->floor_holder) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", conference->floor_holder->id);
- } else {
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
- }
-
- switch_event_fire(&event);
- }
-
- if (floor_holder) {
- switch_channel_t *floor_channel = switch_core_session_get_channel(floor_holder->session);
- if (switch_channel_test_flag(floor_channel, CF_VIDEO)) {
- switch_core_session_message_t msg = { 0 };
-
- msg.from = __FILE__;
- msg.message_id = SWITCH_MESSAGE_INDICATE_VIDEO_REFRESH_REQ;
-
- switch_core_session_receive_message(floor_holder->session, &msg);
- }
- }
-
- //conference->floor_holder = floor_holder;
conference_set_floor_holder(conference, floor_holder);
}
-
if (conference->perpetual_sound && !conference->async_fnode) {
conference_play_file(conference, conference->perpetual_sound, CONF_DEFAULT_LEADIN, NULL, 1);
} else {
conference->mh.up = -1;
}
- } else if (conference->vh[0].up == 0 &&
- conference->vh[1].up == 0 &&
- conference->mh.up == 0 &&
- video_bridge_members[0] &&
- !video_bridge_members[1] &&
- switch_test_flag(video_bridge_members[0], MFLAG_RUNNING) &&
- switch_channel_ready(switch_core_session_get_channel(video_bridge_members[0]->session))
- ) {
-
- launch_conference_video_mirror_thread(video_bridge_members[0]);
}
}
conf_api_sub_floor(member, NULL, NULL);
}
+static void conference_loop_fn_vid_floor_toggle(conference_member_t *member, caller_control_action_t *action)
+{
+ if (member == NULL) return;
+
+ conf_api_sub_vid_floor(member, NULL, NULL);
+}
+
+static void conference_loop_fn_vid_floor_force(conference_member_t *member, caller_control_action_t *action)
+{
+ if (member == NULL) return;
+
+ conf_api_sub_vid_floor(member, NULL, "force");
+}
+
static void conference_loop_fn_enforce_floor(conference_member_t *member, caller_control_action_t *action)
{
if (member == NULL) return;
static switch_status_t conf_api_sub_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data)
{
- switch_event_t *event;
if (member == NULL)
return SWITCH_STATUS_GENERR;
switch_mutex_lock(member->conference->mutex);
if (member->conference->floor_holder == member) {
- //member->conference->floor_holder = NULL;
conference_set_floor_holder(member->conference, NULL);
- if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE)) {
- switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
- conference_add_event_data(member->conference, event);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", member->id);
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
- switch_event_fire(&event);
- if (stream != NULL) {
- stream->write_function(stream, "OK floor none\n");
- }
+ if (stream != NULL) {
+ stream->write_function(stream, "OK floor none\n");
}
} else if (member->conference->floor_holder == NULL) {
- //member->conference->floor_holder = member;
conference_set_floor_holder(member->conference, member);
- if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE)) {
- switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
- conference_add_event_data(member->conference, event);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", member->id);
- switch_event_fire(&event);
- if (stream != NULL) {
- stream->write_function(stream, "OK floor %u\n", member->id);
- }
-
- if (switch_core_session_read_lock(member->session) == SWITCH_STATUS_SUCCESS) {
- /* Tell the channel to request a fresh vid frame */
- switch_channel_set_flag(switch_core_session_get_channel(member->session), CF_VIDEO_REFRESH_REQ);
- switch_core_session_rwunlock(member->session);
- }
+ if (stream != NULL) {
+ stream->write_function(stream, "OK floor %u\n", member->id);
}
} else {
if (stream != NULL) {
return SWITCH_STATUS_SUCCESS;
}
-static switch_status_t conf_api_sub_enforce_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data)
+static switch_status_t conf_api_sub_clear_vid_floor(conference_obj_t *conference, switch_stream_handle_t *stream, void *data)
{
- switch_event_t *event;
+
+ if (switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "conference %s is in video bridge mode, this functionality is not compatible\n", conference->name);
+ return SWITCH_STATUS_FALSE;
+ }
+
+ switch_mutex_lock(conference->mutex);
+ conference_set_video_floor_holder(conference, NULL);
+ switch_mutex_unlock(conference->mutex);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data)
+{
+ int force = 0;
if (member == NULL)
return SWITCH_STATUS_GENERR;
+ if (switch_test_flag(member->conference, CFLAG_VIDEO_BRIDGE)) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_WARNING,
+ "conference %s is in video bridge mode, this functionality is not compatible\n", member->conference->name);
+ return SWITCH_STATUS_FALSE;
+ }
+
switch_mutex_lock(member->conference->mutex);
- if (member->conference->floor_holder != member) {
- conference_member_t *old_member = member->conference->floor_holder;
- //member->conference->floor_holder = member;
- conference_set_floor_holder(member->conference, member);
+ if (data && switch_stristr("force", (char *) data)) {
+ force = 1;
+ }
+
+ if (!force && member->conference->video_floor_holder == member) {
+ conference_set_video_floor_holder(member->conference, NULL);
+ if (stream == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "conference %s OK floor none\n", member->conference->name);
+ } else {
+ stream->write_function(stream, "OK floor none\n");
+ }
+
+ } else if (force || member->conference->video_floor_holder == NULL) {
+ conference_set_video_floor_holder(member->conference, member);
if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE)) {
- switch_event_create_subclass(&event, SWITCH_EVENT_CUSTOM, CONF_EVENT_MAINT);
- conference_add_event_data(member->conference, event);
- switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "Action", "floor-change");
- if (old_member == NULL) {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "none");
+ if (stream == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "conference %s OK floor %d %s\n",
+ member->conference->name, member->id, switch_channel_get_name(member->channel));
} else {
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "Old-ID", "%d", old_member->id);
- }
- switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", member->id);
- switch_event_fire(&event);
- if (stream != NULL) {
stream->write_function(stream, "OK floor %u\n", member->id);
}
}
+ } else {
+ if (stream == NULL) {
+ switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_INFO, "conference %s floor already held by %d %s\n",
+ member->conference->name, member->id, switch_channel_get_name(member->channel));
+ } else {
+ stream->write_function(stream, "ERR floor is held by %u\n", member->conference->video_floor_holder->id);
+ }
+ }
- if (switch_core_session_read_lock(member->session) == SWITCH_STATUS_SUCCESS) {
- /* Tell the channel to request a fresh vid frame */
- switch_channel_set_flag(switch_core_session_get_channel(member->session), CF_VIDEO_REFRESH_REQ);
- switch_core_session_rwunlock(member->session);
+ switch_mutex_unlock(member->conference->mutex);
+
+ return SWITCH_STATUS_SUCCESS;
+}
+
+static switch_status_t conf_api_sub_enforce_floor(conference_member_t *member, switch_stream_handle_t *stream, void *data)
+{
+ if (member == NULL)
+ return SWITCH_STATUS_GENERR;
+
+ switch_mutex_lock(member->conference->mutex);
+
+ if (member->conference->floor_holder != member) {
+ conference_set_floor_holder(member->conference, member);
+
+ if (stream != NULL) {
+ stream->write_function(stream, "OK floor %u\n", member->id);
}
}
{"get", (void_fn_t) & conf_api_sub_get, CONF_API_SUB_ARGS_SPLIT, "get", "<parameter-name>"},
{"set", (void_fn_t) & conf_api_sub_set, CONF_API_SUB_ARGS_SPLIT, "set", "<max_members|sound_prefix|caller_id_name|caller_id_number|endconf_grace_time> <value>"},
{"floor", (void_fn_t) & conf_api_sub_floor, CONF_API_SUB_MEMBER_TARGET, "floor", "<member_id|last>"},
+ {"vid-floor", (void_fn_t) & conf_api_sub_vid_floor, CONF_API_SUB_MEMBER_TARGET, "vid-floor", "<member_id|last> [force]"},
+ {"clear-vid-floor", (void_fn_t) & conf_api_sub_clear_vid_floor, CONF_API_SUB_ARGS_AS_ONE, "clear-vid-floor", ""},
{"enforce_floor", (void_fn_t) & conf_api_sub_enforce_floor, CONF_API_SUB_MEMBER_TARGET, "enforce_floor", "<member_id|last>"},
};
-/* Create a video thread for the conference and launch it */
-static void launch_conference_video_mirror_thread(conference_member_t *member_a)
-{
- conference_obj_t *conference = member_a->conference;
- switch_memory_pool_t *pool = conference->pool;
-
- memset(&conference->mh, 0, sizeof(conference->mh));
-
- conference->mh.member_a = member_a;
-
- launch_thread_detached(conference_video_mirror_thread_run, pool, &conference->mh);
-}
-
static void launch_conference_record_thread(conference_obj_t *conference, char *path)
{
switch_thread_t *thread;
{"transfer", conference_loop_fn_transfer},
{"execute_application", conference_loop_fn_exec_app},
{"floor", conference_loop_fn_floor_toggle},
+ {"vid-floor", conference_loop_fn_vid_floor_toggle},
+ {"vid-floor-force", conference_loop_fn_vid_floor_force},
{"enforce_floor", conference_loop_fn_enforce_floor},
};
#define MAPPING_LEN (sizeof(control_mappings)/sizeof(control_mappings[0]))