]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
Add video-bridge flags to have multiple audio participants to a single video call
authorMathieu Rene <mrene@avgs.ca>
Thu, 23 Jun 2011 16:18:01 +0000 (12:18 -0400)
committerMathieu Rene <mrene@avgs.ca>
Tue, 23 Aug 2011 15:28:32 +0000 (17:28 +0200)
src/mod/applications/mod_conference/mod_conference.c

index 66c7a69caeb753f0e21d0421b8a1dec025817c11..8217130ed653b17eea25f8e40734f0e574bc1201 100644 (file)
@@ -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;