FS-7513: restore video relationships and refactor conference to use video_read callbacks instead of its own thread and change behavior so video floor holder never sees their own video unless they are the only one with video in the conference

This commit is contained in:
Anthony Minessale 2015-01-16 18:17:50 -06:00 committed by Michael Jerris
parent a69938c3d5
commit d026624631
1 changed files with 203 additions and 211 deletions

View File

@ -198,7 +198,8 @@ typedef enum {
MFLAG_JOIN_ONLY = (1 << 25),
MFLAG_POSITIONAL = (1 << 26),
MFLAG_NO_POSITIONAL = (1 << 27),
MFLAG_JOIN_VID_FLOOR = (1 << 28)
MFLAG_JOIN_VID_FLOOR = (1 << 28),
MFLAG_RECEIVING_VIDEO = (1 << 29)
} member_flag_t;
typedef enum {
@ -231,7 +232,8 @@ typedef enum {
typedef enum {
RFLAG_CAN_SPEAK = (1 << 0),
RFLAG_CAN_HEAR = (1 << 1)
RFLAG_CAN_HEAR = (1 << 1),
RFLAG_CAN_SEND_VIDEO = (1 << 2)
} relation_flag_t;
typedef enum {
@ -397,7 +399,8 @@ typedef struct conference_obj {
switch_mutex_t *mutex;
conference_member_t *members;
conference_member_t *floor_holder;
conference_member_t *video_floor_holder;
uint32_t video_floor_holder;
uint32_t last_video_floor_holder;
switch_mutex_t *member_mutex;
conference_file_node_t *fnode;
conference_file_node_t *async_fnode;
@ -416,7 +419,6 @@ typedef struct conference_obj {
int auto_recording;
int record_count;
uint32_t min_recording_participants;
int video_running;
int ivr_dtmf_timeout;
int ivr_input_timeout;
uint32_t eflags;
@ -555,7 +557,6 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
static switch_status_t conference_add_member(conference_obj_t *conference, conference_member_t *member);
static switch_status_t conference_del_member(conference_obj_t *conference, conference_member_t *member);
static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, void *obj);
static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thread, void *obj);
static void conference_loop_output(conference_member_t *member);
static uint32_t conference_stop_file(conference_obj_t *conference, file_stop_t stop);
static switch_status_t conference_play_file(conference_obj_t *conference, char *file, uint32_t leadin, switch_channel_t *channel, uint8_t async);
@ -585,7 +586,6 @@ static switch_status_t conference_outcall_bg(conference_obj_t *conference,
const char *cid_num, const char *call_uuid, const char *profile, switch_call_cause_t *cancel_cause, switch_event_t **var_event);
SWITCH_STANDARD_APP(conference_function);
static void launch_conference_thread(conference_obj_t *conference);
static void launch_conference_video_thread(conference_obj_t *conference);
static void *SWITCH_THREAD_FUNC conference_loop_input(switch_thread_t *thread, void *obj);
static switch_status_t conference_local_play_file(conference_obj_t *conference, switch_core_session_t *session, char *path, uint32_t leadin, void *buf,
uint32_t buflen);
@ -1920,14 +1920,17 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
switch_status_t status = SWITCH_STATUS_FALSE;
conference_relationship_t *rel, *last = NULL;
if (member == NULL || id == 0)
if (member == NULL)
return status;
lock_member(member);
for (rel = member->relationships; rel; rel = rel->next) {
if (rel->id == id) {
if (id == 0 || rel->id == id) {
/* we just forget about rel here cos it was allocated by the member's pool
it will be freed when the member is */
conference_member_t *omember;
status = SWITCH_STATUS_SUCCESS;
if (last) {
last->next = rel->next;
@ -1935,11 +1938,21 @@ static switch_status_t member_del_relationship(conference_member_t *member, uint
member->relationships = rel->next;
}
if ((rel->flags & RFLAG_CAN_SEND_VIDEO)) {
switch_clear_flag(member, MFLAG_RECEIVING_VIDEO);
if ((omember = conference_member_get(member->conference, rel->id))) {
switch_clear_flag(omember, MFLAG_RECEIVING_VIDEO);
switch_thread_rwlock_unlock(omember->rwlock);
}
}
switch_mutex_lock(member->conference->member_mutex);
member->conference->relationship_total--;
switch_mutex_unlock(member->conference->member_mutex);
continue;
}
last = rel;
}
unlock_member(member);
@ -2093,7 +2106,7 @@ static void member_update_status_field(conference_member_t *member)
if (switch_channel_test_flag(member->channel, CF_VIDEO)) {
vstr = " VIDEO";
if (member == member->conference->video_floor_holder) {
if (member && member->id == member->conference->video_floor_holder) {
vstr = " VIDEO (FLOOR)";
}
}
@ -2261,16 +2274,6 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
}
/* Tell the channel to request a fresh vid frame */
switch_core_session_video_reinit(member->session);
if (conference->video_floor_holder) {
switch_mutex_lock(conference->mutex);
if (conference->video_floor_holder) {
switch_core_session_video_reinit(conference->video_floor_holder->session);
// there's already someone hold the floor, tell the core thread start to read video
switch_channel_clear_flag(member->channel, CF_VIDEO_PASSIVE);
}
switch_mutex_unlock(conference->mutex);
}
}
if (!switch_channel_get_variable(channel, "conference_call_key")) {
@ -2452,8 +2455,9 @@ static switch_status_t conference_add_member(conference_obj_t *conference, confe
static void conference_set_video_floor_holder(conference_obj_t *conference, conference_member_t *member, switch_bool_t force)
{
switch_event_t *event;
conference_member_t *old_member = NULL, *imember = NULL;
conference_member_t *imember = NULL;
int old_id = 0;
uint32_t old_member = 0;
if (!member) {
switch_clear_flag(conference, CFLAG_VID_FLOOR_LOCK);
@ -2464,20 +2468,20 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
}
if (conference->video_floor_holder) {
if (conference->video_floor_holder == member) {
if (member && conference->video_floor_holder == member->id) {
return;
} else {
conference->last_video_floor_holder = conference->video_floor_holder;
old_member = conference->video_floor_holder;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Dropping video floor %s\n",
switch_channel_get_name(old_member->channel));
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Dropping video floor %d\n", old_member);
}
}
switch_mutex_lock(conference->mutex);
if (!member) {
for (imember = conference->members; imember; imember = imember->next) {
if (imember != conference->video_floor_holder && imember->channel && switch_channel_test_flag(imember->channel, CF_VIDEO)) {
if (imember->id != conference->video_floor_holder && imember->channel && switch_channel_test_flag(imember->channel, CF_VIDEO)) {
member = imember;
break;
}
@ -2487,18 +2491,23 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
if (member) {
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG1, "Adding video floor %s\n",
switch_channel_get_name(member->channel));
//switch_channel_set_flag(member->channel, CF_VIDEO_PASSIVE);
switch_core_session_video_reinit(member->session);
conference->video_floor_holder = member;
conference->video_floor_holder = member->id;
member_update_status_field(member);
} else {
conference->video_floor_holder = NULL;
conference->video_floor_holder = 0;
}
if (old_member) {
old_id = old_member->id;
member_update_status_field(old_member);
//switch_channel_clear_flag(old_member->channel, CF_VIDEO_PASSIVE);
conference_member_t *old_member_p = NULL;
old_id = old_member;
if ((old_member_p = conference_member_get(conference, old_id))) {
member_update_status_field(old_member_p);
switch_thread_rwlock_unlock(old_member_p->rwlock);
}
}
for (imember = conference->members; imember; imember = imember->next) {
@ -2506,12 +2515,6 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
continue;
}
if (imember == conference->video_floor_holder) {
switch_channel_set_flag(imember->channel, CF_VIDEO_PASSIVE);
} else {
switch_channel_clear_flag(imember->channel, CF_VIDEO_PASSIVE);
}
switch_channel_set_flag(imember->channel, CF_VIDEO_BREAK);
switch_core_session_kill_channel(imember->session, SWITCH_SIG_BREAK);
switch_core_session_video_reinit(imember->session);
@ -2530,7 +2533,7 @@ static void conference_set_video_floor_holder(conference_obj_t *conference, conf
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);
switch_event_add_header(event, SWITCH_STACK_BOTTOM, "New-ID", "%d", conference->video_floor_holder);
} else {
switch_event_add_header_string(event, SWITCH_STACK_BOTTOM, "New-ID", "none");
}
@ -2705,6 +2708,7 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
lock_member(member);
member_del_relationship(member, 0);
conference_cdr_del(member);
@ -2774,8 +2778,12 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe
}
if (member == member->conference->video_floor_holder) {
conference_set_video_floor_holder(member->conference, NULL, SWITCH_TRUE);
if (member && member->id == member->conference->video_floor_holder) {
if (member->conference->last_video_floor_holder) {
member->conference->video_floor_holder = member->conference->last_video_floor_holder;
} else {
conference_set_video_floor_holder(member->conference, NULL, SWITCH_TRUE);
}
}
member->conference = NULL;
@ -2911,149 +2919,119 @@ static void *SWITCH_THREAD_FUNC conference_video_bridge_thread_run(switch_thread
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)
static void conference_write_video_frame(conference_obj_t *conference, conference_member_t *floor_holder, switch_frame_t *vid_frame)
{
conference_obj_t *conference = (conference_obj_t *) obj;
conference_member_t *imember;
switch_frame_t *vid_frame = NULL;
switch_status_t status;
int want_refresh = 0;
int yield = 0;
switch_core_session_t *session;
//char buf[65536];
conference_member_t *floor_holder = NULL;
int locked = 0;
conference->video_running = 1;
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video thread started for conference %s\n", conference->name);
while (conference->video_running == 1 && globals.running && !switch_test_flag(conference, CFLAG_DESTRUCT)) {
locked = 0;
session = NULL;
if (yield) {
switch_yield(yield);
yield = 0;
}
switch_mutex_lock(conference->mutex);
if (conference->video_floor_holder) {
floor_holder = conference->video_floor_holder;
} else {
floor_holder = NULL;
}
if (!floor_holder) {
yield = 100000;
goto do_continue;
}
if (!floor_holder->session || !floor_holder->channel || !switch_channel_test_flag(floor_holder->channel, CF_VIDEO)) {
yield = 100000;
goto do_continue;
}
session = floor_holder->session;
if ((status = switch_core_session_read_lock(session)) == SWITCH_STATUS_SUCCESS) {
switch_mutex_unlock(conference->mutex);
if ((switch_core_media_read_lock(session, SWITCH_MEDIA_TYPE_VIDEO) == SWITCH_STATUS_SUCCESS)) {
locked = 1;
if (!switch_channel_ready(switch_core_session_get_channel(session))) {
status = SWITCH_STATUS_FALSE;
} else {
status = switch_core_session_read_video_frame(session, &vid_frame, SWITCH_IO_FLAG_NONE, 0);
}
} else {
status = SWITCH_STATUS_FALSE;
}
switch_mutex_lock(conference->mutex);
switch_core_session_rwunlock(session);
}
if (!SWITCH_READ_ACCEPTABLE(status)) {
yield = 100000;
goto do_continue;
}
if (vid_frame && switch_test_flag(vid_frame, SFF_CNG)) {
yield = 10000;
goto do_continue;
}
//memcpy(buf, vid_frame->packet, vid_frame->packelen);
switch_mutex_unlock(conference->mutex);
switch_mutex_lock(conference->mutex);
want_refresh = 0;
if (switch_test_flag(conference, CFLAG_FLOOR_CHANGE)) {
switch_clear_flag(conference, CFLAG_FLOOR_CHANGE);
}
for (imember = conference->members; imember; imember = imember->next) {
switch_core_session_t *isession = imember->session;
switch_channel_t *ichannel;
if (!isession || switch_core_session_read_lock(isession) != SWITCH_STATUS_SUCCESS) {
continue;
}
ichannel = switch_core_session_get_channel(imember->session);
if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) {
want_refresh++;
switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ);
}
if (isession && switch_channel_test_flag(ichannel, CF_VIDEO)) {
//memcpy(vid_frame->packet, buf, vid_frame->packetlen);
switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);
}
switch_core_session_rwunlock(isession);
}
/* seems we are recording a video file */
switch_mutex_lock(conference->mutex);
if (conference->record_fh) {
switch_size_t len = vid_frame->packetlen;
if (!conference->video_recording) {
want_refresh++;
conference->video_recording++;
} else {
if (len > 14) { // 14 = 12(rtp) + 2(cng?)
switch_core_file_write_video(conference->record_fh, vid_frame->packet, &len);
}
}
} else {
conference->video_recording = 0;
}
switch_mutex_unlock(conference->mutex);
if (want_refresh && session) {
switch_core_session_request_video_refresh(session);
want_refresh = 0;
}
do_continue:
if (session && locked) {
switch_core_media_read_unlock(session, SWITCH_MEDIA_TYPE_VIDEO);
locked = 0;
}
switch_mutex_unlock(conference->mutex);
if (switch_test_flag(conference, CFLAG_FLOOR_CHANGE)) {
switch_clear_flag(conference, CFLAG_FLOOR_CHANGE);
}
switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "Video thread ending for conference %s\n", conference->name);
conference->video_running = 0;
switch_mutex_lock(conference->member_mutex);
for (imember = conference->members; imember; imember = imember->next) {
switch_core_session_t *isession = imember->session;
switch_channel_t *ichannel;
if (!isession || switch_core_session_read_lock(isession) != SWITCH_STATUS_SUCCESS) {
continue;
}
ichannel = switch_core_session_get_channel(imember->session);
if (switch_channel_test_flag(ichannel, CF_VIDEO_REFRESH_REQ)) {
want_refresh++;
switch_channel_clear_flag(ichannel, CF_VIDEO_REFRESH_REQ);
}
if (isession && switch_channel_test_flag(ichannel, CF_VIDEO)) {
//switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK) ||
return NULL;
if (!switch_test_flag(imember, MFLAG_RECEIVING_VIDEO) &&
(switch_test_flag(conference, CFLAG_VID_FLOOR_LOCK) ||
!(imember->id == imember->conference->video_floor_holder && imember->conference->last_video_floor_holder))) {
switch_core_session_write_video_frame(imember->session, vid_frame, SWITCH_IO_FLAG_NONE, 0);
}
}
switch_core_session_rwunlock(isession);
}
switch_mutex_unlock(conference->member_mutex);
/* seems we are recording a video file */
switch_mutex_lock(conference->mutex);
if (conference->record_fh) {
switch_size_t len = vid_frame->packetlen;
if (!conference->video_recording) {
want_refresh++;
conference->video_recording++;
} else {
if (len > 14) { // 14 = 12(rtp) + 2(cng?)
switch_core_file_write_video(conference->record_fh, vid_frame->packet, &len);
}
}
} else {
conference->video_recording = 0;
}
switch_mutex_unlock(conference->mutex);
if (want_refresh && floor_holder->session) {
switch_core_session_request_video_refresh(floor_holder->session);
}
}
switch_status_t video_thread_callback(switch_core_session_t *session, switch_frame_t *frame, void *user_data)
{
//switch_channel_t *channel = switch_core_session_get_channel(session);
//char *name = switch_channel_get_name(channel);
conference_member_t *member = (conference_member_t *)user_data;
conference_relationship_t *rel = NULL, *last = NULL;
switch_assert(member);
lock_member(member);
for (rel = member->relationships; rel; rel = rel->next) {
conference_member_t *imember;
if (!(rel->flags & RFLAG_CAN_SEND_VIDEO)) continue;
if ((imember = conference_member_get(member->conference, rel->id)) && switch_test_flag(imember, MFLAG_RECEIVING_VIDEO)) {
//switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_ERROR, "%s %d->%d %d\n", name, member->id, imember->id, frame->datalen);
switch_core_session_write_video_frame(imember->session, frame, SWITCH_IO_FLAG_NONE, 0);
switch_thread_rwlock_unlock(imember->rwlock);
} else { /* Stale .. Remove */
if (last) {
last->next = rel->next;
} else {
member->relationships = rel->next;
}
switch_mutex_lock(member->conference->member_mutex);
member->conference->relationship_total--;
switch_mutex_unlock(member->conference->member_mutex);
continue;
}
last = rel;
}
unlock_member(member);
if (member && !switch_test_flag(member->conference, CFLAG_VIDEO_BRIDGE)) {
if (member->id == member->conference->video_floor_holder) {
conference_write_video_frame(member->conference, member, frame);
} else if (!switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK) && member->id == member->conference->last_video_floor_holder) {
conference_member_t *fmember;
if ((fmember = conference_member_get(member->conference, member->conference->video_floor_holder))) {
switch_core_session_write_video_frame(fmember->session, frame, SWITCH_IO_FLAG_NONE, 0);
switch_thread_rwlock_unlock(fmember->rwlock);
}
}
}
return SWITCH_STATUS_SUCCESS;
}
static void conference_command_handler(switch_live_array_t *la, const char *cmd, const char *sessid, cJSON *jla, void *user_data)
@ -3250,12 +3228,6 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
if (members_with_video) {
if (conference->video_running != 1) {
if (!switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) {
launch_conference_video_thread(conference);
}
}
if (conference->vh[0].up == 0 &&
conference->vh[1].up == 0 &&
video_bridge_members[0] &&
@ -3636,14 +3608,6 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v
switch_cond_next();
}
if (conference->video_running == 1) {
conference->video_running = -1;
while (conference->video_running) {
switch_cond_next();
}
}
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", "conference-destroy");
@ -5218,7 +5182,13 @@ static void *SWITCH_THREAD_FUNC conference_record_thread_run(switch_thread_t *th
switch_mutex_lock(conference->mutex);
if (!conference->record_fh) conference->record_fh = &fh;
if (conference->video_floor_holder) {
switch_core_session_video_reinit(conference->video_floor_holder->session);
conference_member_t *member;
if ((member = conference_member_get(conference, conference->video_floor_holder))) {
if (member->session) {
switch_core_session_video_reinit(member->session);
}
switch_thread_rwlock_unlock(member->rwlock);
}
}
switch_mutex_unlock(conference->mutex);
@ -6180,7 +6150,7 @@ static void conference_list(conference_obj_t *conference, switch_stream_handle_t
count++;
}
if (member == member->conference->video_floor_holder) {
if (member->id == member->conference->video_floor_holder) {
stream->write_function(stream, "%s%s", count ? "|" : "", "vid-floor");
count++;
}
@ -6922,7 +6892,7 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc
force = 1;
}
if (member->conference->video_floor_holder == member && switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) {
if (member->conference->video_floor_holder == member->id && switch_test_flag(member->conference, CFLAG_VID_FLOOR_LOCK)) {
switch_clear_flag(member->conference, CFLAG_VID_FLOOR_LOCK);
conference_set_floor_holder(member->conference, member);
@ -6932,7 +6902,7 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc
stream->write_function(stream, "OK floor none\n");
}
} else if (force || member->conference->video_floor_holder == NULL) {
} else if (force || member->conference->video_floor_holder == 0) {
switch_set_flag(member->conference, CFLAG_VID_FLOOR_LOCK);
conference_set_video_floor_holder(member->conference, member, SWITCH_TRUE);
if (test_eflag(member->conference, EFLAG_FLOOR_CHANGE)) {
@ -6948,7 +6918,7 @@ static switch_status_t conf_api_sub_vid_floor(conference_member_t *member, switc
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);
stream->write_function(stream, "ERR floor is held by %u\n", member->conference->video_floor_holder);
}
}
@ -7542,7 +7512,7 @@ static switch_status_t conf_api_sub_stop(conference_obj_t *conference, switch_st
static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_stream_handle_t *stream, int argc, char **argv)
{
uint8_t nospeak = 0, nohear = 0, clear = 0;
uint8_t nospeak = 0, nohear = 0, sendvideo = 0, clear = 0;
switch_assert(conference != NULL);
switch_assert(stream != NULL);
@ -7563,9 +7533,10 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
if (member_id > 0 && member->id != member_id) continue;
for (rel = member->relationships; rel; rel = rel->next) {
stream->write_function(stream, "%d -> %d %s%s\n", member->id, rel->id,
stream->write_function(stream, "%d -> %d %s%s%s\n", member->id, rel->id,
(rel->flags & RFLAG_CAN_SPEAK) ? "SPEAK " : "NOSPEAK ",
(rel->flags & RFLAG_CAN_HEAR) ? "HEAR" : "NOHEAR");
(rel->flags & RFLAG_CAN_HEAR) ? "HEAR " : "NOHEAR ",
(rel->flags & RFLAG_CAN_SEND_VIDEO) ? "SENDVIDEO " : "NOSENDVIDEO ");
}
}
} else {
@ -7580,22 +7551,35 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
nospeak = strstr(argv[4], "nospeak") ? 1 : 0;
nohear = strstr(argv[4], "nohear") ? 1 : 0;
sendvideo = strstr(argv[4], "sendvideo") ? 1 : 0;
if (!strcasecmp(argv[4], "clear")) {
clear = 1;
}
if (!(clear || nospeak || nohear)) {
if (!(clear || nospeak || nohear || sendvideo)) {
return SWITCH_STATUS_GENERR;
}
if (clear) {
conference_member_t *member = NULL;
conference_member_t *member = NULL, *other_member = NULL;
uint32_t id = atoi(argv[2]);
uint32_t oid = atoi(argv[3]);
if ((member = conference_member_get(conference, id))) {
member_del_relationship(member, oid);
other_member = conference_member_get(conference, oid);
if (other_member) {
if (switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO)) {
switch_clear_flag(other_member, MFLAG_RECEIVING_VIDEO);
if (conference->floor_holder) {
switch_core_session_request_video_refresh(conference->floor_holder->session);
}
}
switch_thread_rwlock_unlock(other_member->rwlock);
}
stream->write_function(stream, "relationship %u->%u cleared.\n", id, oid);
switch_thread_rwlock_unlock(member->rwlock);
} else {
@ -7604,7 +7588,7 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
return SWITCH_STATUS_SUCCESS;
}
if (nospeak || nohear) {
if (nospeak || nohear || sendvideo) {
conference_member_t *member = NULL, *other_member = NULL;
uint32_t id = atoi(argv[2]);
uint32_t oid = atoi(argv[3]);
@ -7616,6 +7600,11 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
if (member && other_member) {
conference_relationship_t *rel = NULL;
if (sendvideo && switch_test_flag(other_member, MFLAG_RECEIVING_VIDEO) && (! (nospeak || nohear))) {
stream->write_function(stream, "member %d already receiving video", oid);
goto skip;
}
if ((rel = member_get_relationship(member, other_member))) {
rel->flags = 0;
} else {
@ -7631,7 +7620,13 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
if (nohear) {
switch_clear_flag(rel, RFLAG_CAN_HEAR);
}
stream->write_function(stream, "ok %u->%u set\n", id, oid);
if (sendvideo) {
switch_set_flag(rel, RFLAG_CAN_SEND_VIDEO);
switch_set_flag(other_member, MFLAG_RECEIVING_VIDEO);
switch_core_session_request_video_refresh(member->session);
}
stream->write_function(stream, "ok %u->%u %s set\n", id, oid, argv[4]);
} else {
stream->write_function(stream, "error!\n");
}
@ -7639,6 +7634,7 @@ static switch_status_t conf_api_sub_relate(conference_obj_t *conference, switch_
stream->write_function(stream, "relationship %u->%u not found.\n", id, oid);
}
skip:
if (member) {
switch_thread_rwlock_unlock(member->rwlock);
}
@ -9221,7 +9217,6 @@ SWITCH_STANDARD_APP(conference_function)
switch_core_session_video_reset(session);
switch_channel_set_flag(channel, CF_CONFERENCE);
switch_channel_set_flag(channel, CF_VIDEO_PASSIVE);
if (switch_channel_answer(channel) != SWITCH_STATUS_SUCCESS) {
switch_log_printf(SWITCH_CHANNEL_SESSION_LOG(session), SWITCH_LOG_ERROR, "Channel answer failed.\n");
@ -9743,11 +9738,16 @@ SWITCH_STANDARD_APP(conference_function)
msg.message_id = SWITCH_MESSAGE_INDICATE_BRIDGE;
switch_core_session_receive_message(session, &msg);
/* Chime in the core video thread */
switch_core_session_set_video_read_callback(session, video_thread_callback, (void *)&member);
/* Run the conference loop */
do {
conference_loop_output(&member);
} while (member.loop_loop);
switch_core_session_set_video_read_callback(session, NULL, NULL);
switch_channel_set_private(channel, "_conference_autocall_list_", NULL);
/* Tell the channel we are no longer going to be in a bridge */
@ -9833,7 +9833,6 @@ SWITCH_STANDARD_APP(conference_function)
end:
switch_channel_clear_flag(channel, CF_CONFERENCE);
switch_channel_clear_flag(channel, CF_VIDEO_PASSIVE);
switch_core_session_video_reset(session);
}
@ -9867,13 +9866,6 @@ static switch_thread_t *launch_thread_detached(switch_thread_start_t func, switc
return thread;
}
/* Create a video thread for the conference and launch it */
static void launch_conference_video_thread(conference_obj_t *conference)
{
launch_thread_detached(conference_video_thread_run, conference->pool, conference);
conference->video_running = 1;
}
/* Create a video thread for the conference and launch it */
static int launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b)
{