diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 6f957143ea..78db1b5c90 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -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) {