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 {
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 {
return NULL;
}
+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;
+
+ if (!member || member->relationships == NULL) return SWITCH_STATUS_SUCCESS;
+
+ lock_member(member);
+
+ for (rel = member->relationships; rel; rel = rel->next) {
+ conference_member_t *imember = conference_member_get(member->conference, rel->id);
+ if (imember && 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);
+ }
+ }
+
+ unlock_member(member);
+ return SWITCH_STATUS_SUCCESS;
+}
/* Main video monitor thread (1 per distinct conference room) */
static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thread, void *obj)
}
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);
+ if (!switch_test_flag(imember, MFLAG_RECEIVING_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);
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);
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 {
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_refresh_video(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 {
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]);
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 {
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_refresh_video(member->session);
+ }
+
+ stream->write_function(stream, "ok %u->%u %s set\n", id, oid, argv[4]);
} else {
stream->write_function(stream, "error!\n");
}
stream->write_function(stream, "relationship %u->%u not found.\n", id, oid);
}
+skip:
if (member) {
switch_thread_rwlock_unlock(member->rwlock);
}
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_thread_callback(session, (void *)video_thread_callback, (void *)&member);
+
/* Run the conference loop */
do {
conference_loop_output(&member);
} while (member.loop_loop);
+ switch_core_session_set_video_thread_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 */