]> git.ipfire.org Git - thirdparty/freeswitch.git/commitdiff
FS-7513: Example code to use the core video thread with a custom callback
authorSeven Du <dujinfang@gmail.com>
Sat, 23 Aug 2014 08:59:52 +0000 (16:59 +0800)
committerMichael Jerris <mike@jerris.com>
Thu, 28 May 2015 17:46:43 +0000 (12:46 -0500)
It by default remains the default behaviour

However, you can setup a relationship between members to let the
member choose to see anyone else but the floor, e.g.:

  conference 3000 relate 1 2 sendvideo

In the above command member 2 will see member 1's video regardless
member 1 has video floor or not

src/mod/applications/mod_conference/mod_conference.c

index 3787f107ecea4bacb0be753a18bad4eb188a9756..53a240a1b4e78c404346ae2a73f6af3c5e11924a 100644 (file)
@@ -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 {
@@ -230,7 +231,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 {
@@ -2910,6 +2912,29 @@ static void *SWITCH_THREAD_FUNC conference_video_bridge_thread_run(switch_thread
        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)
@@ -3001,8 +3026,10 @@ static void *SWITCH_THREAD_FUNC conference_video_thread_run(switch_thread_t *thr
                        }
 
                        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);
@@ -7527,7 +7554,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);
@@ -7548,9 +7575,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 {
@@ -7565,22 +7593,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_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 {
@@ -7589,7 +7630,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]);
@@ -7601,6 +7642,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 {
@@ -7616,7 +7662,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_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");
                        }
@@ -7624,6 +7676,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);
                }
@@ -9727,11 +9780,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_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 */