From 3fa8c1c7b68bdbe9291e4ce67e0ed07500ec1934 Mon Sep 17 00:00:00 2001
From: prlanzarin <prlanzarin@inf.ufrgs.br>
Date: Tue, 11 Sep 2018 18:11:52 +0000
Subject: [PATCH] Fix inconsistent screenshare state on presenter switch during
 ongoing negotiation

---
 .../lib/bbb/messages/Constants.js             |  3 +-
 labs/bbb-webrtc-sfu/lib/bbb/pubsub/bbb-gw.js  |  5 +++
 .../WebsocketConnectionManager.js             | 10 ++++-
 .../lib/screenshare/ScreenshareManager.js     | 39 +++++++++++++------
 .../lib/screenshare/screenshare.js            |  5 +++
 5 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/labs/bbb-webrtc-sfu/lib/bbb/messages/Constants.js b/labs/bbb-webrtc-sfu/lib/bbb/messages/Constants.js
index f2d481dcf2..038a0c01dd 100644
--- a/labs/bbb-webrtc-sfu/lib/bbb/messages/Constants.js
+++ b/labs/bbb-webrtc-sfu/lib/bbb/messages/Constants.js
@@ -69,10 +69,9 @@ const config = require('config');
         STOP_TRANSCODER_RESP_2x: "StopTranscoderSysRespMsg",
         GLOBAL_AUDIO_CONNECTED_2x: "UserConnectedToGlobalAudioMsg",
         GLOBAL_AUDIO_DISCONNECTED_2x: "UserDisconnectedFromGlobalAudioMsg",
-        // TODO: Check if this is the correct message in BBB 2.x
         DICONNECT_ALL_USERS_2x: "DisconnectAllClientsSysMsg",
-
         USER_CAM_BROADCAST_STOPPED_2x: "UserBroadcastCamStopMsg",
+        PRESENTER_ASSIGNED_2x: "PresenterAssignedEvtMsg",
 
         STREAM_IS_RECORDED: "StreamIsRecordedMsg",
 
diff --git a/labs/bbb-webrtc-sfu/lib/bbb/pubsub/bbb-gw.js b/labs/bbb-webrtc-sfu/lib/bbb/pubsub/bbb-gw.js
index f55ba1153d..bf6c4d062f 100644
--- a/labs/bbb-webrtc-sfu/lib/bbb/pubsub/bbb-gw.js
+++ b/labs/bbb-webrtc-sfu/lib/bbb/pubsub/bbb-gw.js
@@ -105,6 +105,11 @@ module.exports = class BigBlueButtonGW extends EventEmitter {
           payload[C.MEETING_ID_2x] = header[C.MEETING_ID_2x];
           this.emit(C.DICONNECT_ALL_USERS_2x, payload);
           break;
+        case C.PRESENTER_ASSIGNED_2x:
+          meetingId = header[C.MEETING_ID_2x];
+          payload[C.MEETING_ID_2x] = meetingId;
+          this.emit(C.PRESENTER_ASSIGNED_2x+meetingId, payload);
+          break;
         default:
           this.emit(C.GATEWAY_MESSAGE, msg);
       }
diff --git a/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js b/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js
index dafc004073..b0fbcc3ae7 100644
--- a/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js
+++ b/labs/bbb-webrtc-sfu/lib/connection-manager/WebsocketConnectionManager.js
@@ -29,7 +29,15 @@ module.exports = class WebsocketConnectionManager {
     const connectionId = data? data.connectionId : null;
     const ws = this.webSockets[connectionId];
     if (ws) {
-      this.sendMessage(ws, data);
+      if (data.id === 'close') {
+        try {
+          ws.close();
+        } catch (err) {
+          Logger.warn('[WebsocketConnectionManager] Error on closing WS for', connectionId,  err)
+        }
+      } else {
+        this.sendMessage(ws, data);
+      }
     }
   }
 
diff --git a/labs/bbb-webrtc-sfu/lib/screenshare/ScreenshareManager.js b/labs/bbb-webrtc-sfu/lib/screenshare/ScreenshareManager.js
index f98c989838..2353a1fec8 100644
--- a/labs/bbb-webrtc-sfu/lib/screenshare/ScreenshareManager.js
+++ b/labs/bbb-webrtc-sfu/lib/screenshare/ScreenshareManager.js
@@ -70,6 +70,19 @@ module.exports = class ScreenshareManager extends BaseManager {
             this._stopSession(sessionId);
           });
 
+          // listen for presenter change to avoid inconsistent states on reconnection
+          if (role === C.SEND_ROLE) {
+            this._bbbGW.once(C.PRESENTER_ASSIGNED_2x+message.internalMeetingId, async (payload) => {
+              Logger.info(this._logPrefix, "Presenter changed, forcibly closing screensharing session at", message.internalMeetingId);
+              await this.closeSession(session, connectionId, role, sessionId);
+              this._bbbGW.publish(JSON.stringify({
+                connectionId: connectionId,
+                type: C.SCREENSHARE_APP,
+                id : 'close',
+              }), C.FROM_SCREENSHARE);
+            });
+          }
+
           Logger.info(this._logPrefix, "Sending startResponse to peer", sessionId, "for connection", session._id);
         }
         catch (error) {
@@ -101,17 +114,7 @@ module.exports = class ScreenshareManager extends BaseManager {
 
       case 'close':
         Logger.info(this._logPrefix, 'Connection ' + connectionId + ' closed');
-
-        if (session && session.constructor == Screenshare) {
-          if (role === C.SEND_ROLE && session) {
-            Logger.info(this._logPrefix, "Stopping presenter " + sessionId);
-            this._stopSession(sessionId);
-          }
-          if (role === C.RECV_ROLE && session) {
-            Logger.info(this._logPrefix, "Stopping viewer " + sessionId);
-            session.stopViewer(message.connectionId);
-          }
-        }
+        this.closeSession(session, connectionId, role, sessionId);
         break;
 
       default:
@@ -122,4 +125,18 @@ module.exports = class ScreenshareManager extends BaseManager {
         break;
     }
   }
+
+  async closeSession (session, connectionId, role, sessionId) {
+    if (session && session.constructor == Screenshare) {
+      if (role === C.SEND_ROLE && session) {
+        Logger.info(this._logPrefix, "Stopping presenter " + sessionId);
+        await this._stopSession(sessionId);
+        return;
+      }
+      if (role === C.RECV_ROLE && session) {
+        Logger.info(this._logPrefix, "Stopping viewer " + sessionId);
+        await session.stopViewer(message.connectionId);
+      }
+    }
+  }
 };
diff --git a/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js b/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js
index aeab9fc3af..bfb22a0208 100644
--- a/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js
+++ b/labs/bbb-webrtc-sfu/lib/screenshare/screenshare.js
@@ -227,6 +227,8 @@ module.exports = class Screenshare extends BaseProvider {
 
   start (sessionId, connectionId, sdpOffer, userId, role) {
     return new Promise(async (resolve, reject) => {
+      this._status = C.MEDIA_STARTING;
+
       // Forces H264 with a possible preferred profile
       if (FORCE_H264) {
         sdpOffer = h264_sdp.transform(sdpOffer, PREFERRED_H264_PROFILE);
@@ -347,6 +349,9 @@ module.exports = class Screenshare extends BaseProvider {
   stop () {
     return new Promise(async (resolve, reject) => {
       try {
+        if (this._status === C.MEDIA_STOPPED) {
+          return resolve();
+        }
         Logger.info('[screnshare] Stopping and releasing endpoints for MCS user', this.mcsUserId);
         await this._stopScreensharing();
         this._status = C.MEDIA_STOPPED;
-- 
GitLab