switch_time_t end_time;
char *log_dir;
struct vid_helper vh[2];
+ struct vid_helper mh;
} conference_obj_t;
/* Relationship with another member */
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);
+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 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_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);
+
+ 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)
{
switch_channel_ready(switch_core_session_get_channel(video_bridge_members[0]->session)) &&
switch_channel_ready(switch_core_session_get_channel(video_bridge_members[1]->session))
) {
+ conference->mh.up = 2;
+ if (launch_conference_video_bridge_thread(video_bridge_members[0], video_bridge_members[1])) {
+ conference->mh.up = 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_bridge_thread(video_bridge_members[0], video_bridge_members[1]);
+ launch_conference_video_mirror_thread(video_bridge_members[0]);
}
}
}
/* 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)
+static int launch_conference_video_bridge_thread(conference_member_t *member_a, conference_member_t *member_b)
{
conference_obj_t *conference = member_a->conference;
switch_memory_pool_t *pool = conference->pool;
- int sanity = 10000;
+ int sanity = 10000, r = 0;
memset(conference->vh, 0, sizeof(conference->vh));
if (conference->vh[0].up == 1 && conference->vh[1].up != 1) {
conference->vh[0].up = -1;
+ r = -1;
}
if (conference->vh[1].up == 1 && conference->vh[0].up != 1) {
conference->vh[1].up = -1;
+ r = -1;
}
+
+ return r;
+
+}
+
+
+
+/* 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)