From 1dbd4c77876b0ed6719d67ba644f47d5bca7bff4 Mon Sep 17 00:00:00 2001 From: Mathieu Rene Date: Thu, 23 Jun 2011 12:18:01 -0400 Subject: [PATCH] Add video-bridge flags to have multiple audio participants to a single video call --- .../mod_conference/mod_conference.c | 110 ++++++++++++++++-- 1 file changed, 102 insertions(+), 8 deletions(-) diff --git a/src/mod/applications/mod_conference/mod_conference.c b/src/mod/applications/mod_conference/mod_conference.c index 66c7a69cae..8217130ed6 100644 --- a/src/mod/applications/mod_conference/mod_conference.c +++ b/src/mod/applications/mod_conference/mod_conference.c @@ -144,7 +144,8 @@ typedef enum { MFLAG_MOD = (1 << 16), MFLAG_INDICATE_MUTE = (1 << 17), MFLAG_INDICATE_UNMUTE = (1 << 18), - MFLAG_NOMOH = (1 << 19) + MFLAG_NOMOH = (1 << 19), + MFLAG_VIDEO_BRIDGE = (1 << 20) } member_flag_t; typedef enum { @@ -161,7 +162,8 @@ typedef enum { CFLAG_OUTCALL = (1 << 10), CFLAG_INHASH = (1 << 11), CFLAG_EXIT_SOUND = (1 << 12), - CFLAG_ENTER_SOUND = (1 << 13) + CFLAG_ENTER_SOUND = (1 << 13), + CFLAG_VIDEO_BRIDGE = (1 << 14) } conf_flag_t; typedef enum { @@ -437,6 +439,7 @@ static switch_status_t chat_send(const char *proto, const char *from, const char const char *body, const char *type, const char *hint); static void launch_conference_record_thread(conference_obj_t *conference, char *path); +static void launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b); 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 *); @@ -951,6 +954,56 @@ static switch_status_t conference_del_member(conference_obj_t *conference, confe return status; } +struct vid_helper { + conference_member_t *member_a; + conference_member_t *member_b; + int up; +}; + +/* Thread bridging video between two members, there will be two threads if video briding is used */ +static void *SWITCH_THREAD_FUNC conference_video_bridge_thread_run(switch_thread_t *thread, void *obj) +{ + struct vid_helper *vh = obj; + switch_channel_t *channel_a = switch_core_session_get_channel(vh->member_a->session); + switch_channel_t *channel_b = switch_core_session_get_channel(vh->member_b->session); + switch_status_t status; + switch_frame_t *read_frame; + + /* Acquire locks for both sessions so the helper object and member structures don't get destroyed before we exit */ + if (switch_core_session_read_lock(vh->member_a->session) != SWITCH_STATUS_SUCCESS) { + return NULL; + } + + if (switch_core_session_read_lock(vh->member_b->session) != SWITCH_STATUS_SUCCESS) { + switch_core_session_rwunlock(vh->member_a->session); + return NULL; + } + + vh->up = 1; + while (switch_test_flag(vh->member_a, MFLAG_RUNNING) && switch_test_flag(vh->member_b, MFLAG_RUNNING) && + switch_channel_ready(channel_a) && switch_channel_ready(channel_b)) { + status = switch_core_session_read_video_frame(vh->member_a->session, &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(vh->member_b->session, read_frame, SWITCH_IO_FLAG_NONE, 0) != SWITCH_STATUS_SUCCESS) { + break; + } + } + } + + switch_core_session_rwunlock(vh->member_a->session); + switch_core_session_rwunlock(vh->member_b->session); + + switch_log_printf(SWITCH_CHANNEL_LOG, SWITCH_LOG_DEBUG, "%s video thread ended.\n", switch_channel_get_name(channel_a)); + + 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) { @@ -1103,6 +1156,7 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v int has_file_data = 0, members_with_video = 0; uint32_t conf_energy = 0; int nomoh = 0; + conference_member_t *video_bridge_members[2] = { 0 }; /* Sync the conference to a single timing source */ if (switch_core_timer_next(&timer) != SWITCH_STATUS_SUCCESS) { @@ -1128,6 +1182,14 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v if (switch_test_flag(imember, MFLAG_NOMOH)) { nomoh++; } + + if (switch_test_flag(imember, MFLAG_VIDEO_BRIDGE)) { + if (!video_bridge_members[0]) { + video_bridge_members[0] = imember; + } else { + video_bridge_members[1] = imember; + } + } } switch_clear_flag_locked(imember, MFLAG_HAS_AUDIO); @@ -1187,7 +1249,11 @@ static void *SWITCH_THREAD_FUNC conference_thread_run(switch_thread_t *thread, v if (members_with_video && conference->video_running != 1) { - launch_conference_video_thread(conference); + if (!switch_test_flag(conference, CFLAG_VIDEO_BRIDGE)) { + launch_conference_video_thread(conference); + } else if (video_bridge_members[0] && video_bridge_members[1]){ + launch_conference_video_bridge_thread(video_bridge_members[0], video_bridge_members[1]); + } } /* If a file or speech event is being played */ @@ -5450,6 +5516,8 @@ static void set_mflags(const char *flags, member_flag_t *f) *f |= MFLAG_ENDCONF; } else if (!strcasecmp(argv[i], "mintwo")) { *f |= MFLAG_MINTWO; + } else if (!strcasecmp(argv[i], "video-bridge")) { + *f |= MFLAG_VIDEO_BRIDGE; } } @@ -5482,6 +5550,8 @@ static void set_cflags(const char *flags, uint32_t *f) *f |= CFLAG_VID_FLOOR; } else if (!strcasecmp(argv[i], "waste-bandwidth")) { *f |= CFLAG_WASTE_BANDWIDTH; + } else if (!strcasecmp(argv[i], "video-bridge")) { + *f |= CFLAG_VIDEO_BRIDGE; } } @@ -6229,20 +6299,44 @@ static void launch_conference_thread(conference_obj_t *conference) switch_thread_create(&thread, thd_attr, conference_thread_run, conference, conference->pool); } - -/* Create a video thread for the conference and launch it */ -static void launch_conference_video_thread(conference_obj_t *conference) +static switch_thread_t *launch_thread_detached(switch_thread_start_t func, switch_memory_pool_t *pool, void *data) { switch_thread_t *thread; switch_threadattr_t *thd_attr = NULL; - switch_threadattr_create(&thd_attr, conference->pool); + switch_threadattr_create(&thd_attr, pool); switch_threadattr_detach_set(thd_attr, 1); switch_threadattr_stacksize_set(thd_attr, SWITCH_THREAD_STACKSIZE); - switch_thread_create(&thread, thd_attr, conference_video_thread_run, conference, conference->pool); + switch_thread_create(&thread, thd_attr, func, data, pool); + + 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 void launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b) +{ + switch_memory_pool_t *pool = member_a->conference->pool; + struct vid_helper *vh = switch_core_alloc(pool, 2 * sizeof *vh); + + vh[0].member_a = member_a; + vh[0].member_b = member_b; + + vh[1].member_a = member_b; + vh[1].member_b = member_a; + + launch_thread_detached(conference_video_bridge_thread_run, pool, &vh[0]); + launch_thread_detached(conference_video_bridge_thread_run, pool, &vh[1]); + + member_a->conference->video_running = 1; +} + static void launch_conference_record_thread(conference_obj_t *conference, char *path) { switch_thread_t *thread;