diff --git a/bigbluebutton-client/resources/config.xml.template b/bigbluebutton-client/resources/config.xml.template
old mode 100644
new mode 100755
index 763979403d6a8f57b44e4ab52eb262355619f6f5..a415ce534d1b9fee99d3be500d232bb45de38e46
--- a/bigbluebutton-client/resources/config.xml.template
+++ b/bigbluebutton-client/resources/config.xml.template
@@ -11,7 +11,7 @@
     		  localesConfig="http://HOST/client/conf/locales.xml"
     		  localesDirectory="http://HOST/client/locale/"/>
     <skinning url="http://HOST/client/branding/css/V2Theme.css.swf?v=VERSION" />
-    <branding logo="logos/logo.swf" copyright="&#169; 2018 &lt;u&gt;&lt;a href=&quot;http://HOST/home.html&quot; target=&quot;_blank&quot;&gt;BigBlueButton Inc.&lt;/a&gt;&lt;/u&gt; (build {0})" background="" toolbarColor="" showQuote="true"/>
+    <branding logo="logos/logo.swf" copyright="&#169; 2019 &lt;u&gt;&lt;a href=&quot;http://HOST/home.html&quot; target=&quot;_blank&quot;&gt;BigBlueButton Inc.&lt;/a&gt;&lt;/u&gt; (build {0})" background="" toolbarColor="" showQuote="true"/>
     <shortcutKeys showButton="true" />
     <browserVersions chrome="CHROME_VERSION" firefox="FIREFOX_VERSION" flash="FLASH_VERSION"/>
     <layout showLogButton="false" defaultLayout="bbb.layout.name.defaultlayout"
diff --git a/bigbluebutton-client/resources/prod/lib/kurento-extension.js b/bigbluebutton-client/resources/prod/lib/kurento-extension.js
index dab7affe01d7b4740967cfada438b5d6f716a56d..5eb162c3b09ff3257406014f6e3b895c06f5b774 100755
--- a/bigbluebutton-client/resources/prod/lib/kurento-extension.js
+++ b/bigbluebutton-client/resources/prod/lib/kurento-extension.js
@@ -2,7 +2,8 @@ const isFirefox = typeof window.InstallTrigger !== 'undefined';
 const isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
 const isChrome = !!window.chrome && !isOpera;
 const isSafari = navigator.userAgent.indexOf('Safari') >= 0 && !isChrome;
-const hasDisplayMedia = typeof navigator.getDisplayMedia === 'function';
+const hasDisplayMedia = (typeof navigator.getDisplayMedia === 'function'
+  || typeof navigator.mediaDevices.getDisplayMedia === 'function');
 const kurentoHandler = null;
 const SEND_ROLE = "send";
 const RECV_ROLE = "recv";
diff --git a/bigbluebutton-client/resources/prod/lib/kurento-utils.js b/bigbluebutton-client/resources/prod/lib/kurento-utils.js
index 78ea0604b77245cc5ddb842d1162b3bb8cf263b4..2a8bfab960387681317951b9428c19110d407a8a 100644
--- a/bigbluebutton-client/resources/prod/lib/kurento-utils.js
+++ b/bigbluebutton-client/resources/prod/lib/kurento-utils.js
@@ -410,16 +410,24 @@ function WebRtcPeer(mode, options, callback) {
                     return callback(error);
                 constraints = [mediaConstraints];
                 constraints.unshift(constraints_);
-                if (typeof navigator.getDisplayMedia === 'function') {
-                    navigator.getDisplayMedia(recursive.apply(undefined, constraints)).then(stream => {
-                        stream.getTracks()[0].applyConstraints(constraints[0].optional).then(() => {
+                let gDMCallback = function(stream) {
+                    stream.getTracks()[0].applyConstraints(constraints[0].optional)
+                        .then(() => {
                             videoStream = stream;
                             start();
                         }).catch(() => {
-                          videoStream = stream;
-                          start();
+                            videoStream = stream;
+                            start();
                         });
-                    }).catch(callback);
+                }
+                if (typeof navigator.getDisplayMedia === 'function') {
+                    navigator.getDisplayMedia(recursive.apply(undefined, constraints))
+                        .then(gDMCallback)
+                        .catch(callback);
+                } else if (typeof navigator.mediaDevices.getDisplayMedia === 'function') {
+                    navigator.mediaDevices.getDisplayMedia(recursive.apply(undefined, constraints))
+                        .then(gDMCallback)
+                        .catch(callback);
                 } else {
                     getMedia(recursive.apply(undefined, constraints));
                 }
diff --git a/bigbluebutton-config/web/index.html b/bigbluebutton-config/web/index.html
index 00a14c63d7d4b8c3a03458fbafee6c5f2908b1c3..e4fffe534f971c31f81c761e5e8eefd01332255e 100644
--- a/bigbluebutton-config/web/index.html
+++ b/bigbluebutton-config/web/index.html
@@ -56,6 +56,7 @@
             <form name="form1" method="GET" onsubmit="return checkform(this);" action="/demo/demoHTML5.jsp">
               <input type="text" id="username" required="" name="username" placeholder="Enter Your Name" size="29" class="field input-default" autofocus>
               <input type="submit" value="Join" class="submit_btn button success large"><br>
+              <input type="hidden" name="isModerator" value="true">
               <input type="hidden" name="action" value="create">
             </form>
 
diff --git a/bigbluebutton-html5/client/compatibility/kurento-extension.js b/bigbluebutton-html5/client/compatibility/kurento-extension.js
index 229771c9f841bc057d832e6fdba1705ec9c070f4..66e34642ad5ef6a6fe5b0d8b12ba2217b679f37d 100644
--- a/bigbluebutton-html5/client/compatibility/kurento-extension.js
+++ b/bigbluebutton-html5/client/compatibility/kurento-extension.js
@@ -3,7 +3,8 @@ const isOpera = !!window.opera || navigator.userAgent.indexOf(' OPR/') >= 0;
 const isChrome = !!window.chrome && !isOpera;
 const isSafari = navigator.userAgent.indexOf('Safari') >= 0 && !isChrome;
 const isElectron = navigator.userAgent.toLowerCase().indexOf(' electron/') > -1;
-const hasDisplayMedia = typeof navigator.getDisplayMedia === 'function';
+const hasDisplayMedia = (typeof navigator.getDisplayMedia === 'function'
+  || typeof navigator.mediaDevices.getDisplayMedia === 'function');
 const kurentoHandler = null;
 
 Kurento = function (
diff --git a/bigbluebutton-html5/client/compatibility/kurento-utils.js b/bigbluebutton-html5/client/compatibility/kurento-utils.js
index d15bf65cd8aec11d6766e24916d6be69e4e0aca4..7e118d2d9d17b6a9a30dedc7a6251e75c0f3c40d 100644
--- a/bigbluebutton-html5/client/compatibility/kurento-utils.js
+++ b/bigbluebutton-html5/client/compatibility/kurento-utils.js
@@ -201,7 +201,7 @@ function WebRtcPeer(mode, options, callback) {
                 pc.addTransceiver('video');
             } catch(e) {}
         }
-        
+
         if (useDataChannels && !dataChannel) {
             var dcId = 'WebRtcPeer-' + self.id;
             var dcOptions = undefined;
@@ -267,16 +267,25 @@ function WebRtcPeer(mode, options, callback) {
     };
     this.generateOffer = function (callback) {
         callback = callback.bind(this);
+        const descriptionCallback = () => {
+            var localDescription = pc.localDescription;
+            // logger.debug('Local description set', localDescription.sdp);
+            if (multistream && usePlanB) {
+              localDescription = interop.toUnifiedPlan(localDescription);
+              logger.debug('offer::origPlanB->UnifiedPlan', dumpSDP(localDescription));
+            }
+            callback(null, localDescription.sdp, self.processAnswer.bind(self));
+        }
 
-        pc.onicegatheringstatechange = function (event) {
-            if(event.target.iceGatheringState == "complete") {
-                var localDescription = pc.localDescription;
-                // logger.debug('Local description set', localDescription.sdp);
-                if (multistream && usePlanB) {
-                    localDescription = interop.toUnifiedPlan(localDescription);
-                    logger.debug('offer::origPlanB->UnifiedPlan', dumpSDP(localDescription));
+        const userAgent = window.navigator.userAgent.toLocaleLowerCase();
+        const isSafari = ((userAgent.indexOf('iphone') > -1 || userAgent.indexOf('ipad') > -1) || browser.name.toLowerCase() == 'safari');
+
+        // Bind the SDP release to the gathering state on Safari-based envs
+        if (isSafari) {
+            pc.onicegatheringstatechange = function (event) {
+                if(event.target.iceGatheringState == "complete") {
+                  descriptionCallback();
                 }
-                callback(null, localDescription.sdp, self.processAnswer.bind(self));
             }
         }
 
@@ -296,7 +305,13 @@ function WebRtcPeer(mode, options, callback) {
             // logger.debug('Created SDP offer');
             offer = mangleSdpToAddSimulcast(offer);
             return pc.setLocalDescription(offer);
-        });
+        }).then(() => {
+            // The Safari offer release was already binded to the gathering state
+            if (isSafari) {
+                return;
+            }
+            descriptionCallback();
+        }).catch(callback);
     };
     this.getLocalSessionDescriptor = function () {
         return pc.localDescription;
@@ -446,16 +461,24 @@ function WebRtcPeer(mode, options, callback) {
                     return callback(error);
                 constraints = [mediaConstraints];
                 constraints.unshift(constraints_);
-                if (typeof navigator.getDisplayMedia === 'function') {
-                    navigator.getDisplayMedia(recursive.apply(undefined, constraints)).then(stream => {
-                        stream.getTracks()[0].applyConstraints(constraints[0].optional).then(() => {
+                let gDMCallback = function(stream) {
+                    stream.getTracks()[0].applyConstraints(constraints[0].optional)
+                        .then(() => {
                             videoStream = stream;
                             start();
                         }).catch(() => {
-                          videoStream = stream;
-                          start();
+                            videoStream = stream;
+                            start();
                         });
-                    }).catch(callback);
+                }
+                if (typeof navigator.getDisplayMedia === 'function') {
+                    navigator.getDisplayMedia(recursive.apply(undefined, constraints))
+                        .then(gDMCallback)
+                        .catch(callback);
+                } else if (typeof navigator.mediaDevices.getDisplayMedia === 'function') {
+                    navigator.mediaDevices.getDisplayMedia(recursive.apply(undefined, constraints))
+                        .then(gDMCallback)
+                        .catch(callback);
                 } else {
                     getMedia(recursive.apply(undefined, constraints));
                 }
@@ -1232,7 +1255,7 @@ if (typeof Object.create === 'function') {
 ;(function(isNode) {
 
 	/**
-	 * Merge one or more objects 
+	 * Merge one or more objects
 	 * @param bool? clone
 	 * @param mixed,... arguments
 	 * @return object
@@ -1245,7 +1268,7 @@ if (typeof Object.create === 'function') {
 	}, publicName = 'merge';
 
 	/**
-	 * Merge two or more objects recursively 
+	 * Merge two or more objects recursively
 	 * @param bool? clone
 	 * @param mixed,... arguments
 	 * @return object
diff --git a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx
index d05c8e86fdddf0f7e236ac6cc6258f9ec5a97916..33f66e942e24fc84e9c2021b14f665edad0fe68e 100644
--- a/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx
+++ b/bigbluebutton-html5/imports/ui/components/video-preview/component.jsx
@@ -146,7 +146,6 @@ class VideoPreview extends Component {
 
   componentDidMount() {
     const { webcamDeviceId, changeWebcam } = this.props;
-    const { webcamDeviceId: savedWebcamDeviceId } = this.state;
     const constraints = {
       video: VIDEO_CONSTRAINTS,
     };
@@ -174,7 +173,7 @@ class VideoPreview extends Component {
         this.setState({ availableWebcams: webcams });
       }
 
-      constraints.video.deviceId = { exact: savedWebcamDeviceId };
+      constraints.video.deviceId = { exact: this.state.webcamDeviceId };
       navigator.mediaDevices.getUserMedia(constraints).then((stream) => {
         // display the preview
         this.video.srcObject = stream;
diff --git a/bigbluebutton-html5/private/config/settings.yml b/bigbluebutton-html5/private/config/settings.yml
index 6ecfaea42c178a3fc752ebfa5a80d7da12136332..f312128c5dcc5d6730b78563af00b77b0c020e5b 100755
--- a/bigbluebutton-html5/private/config/settings.yml
+++ b/bigbluebutton-html5/private/config/settings.yml
@@ -95,7 +95,7 @@ public:
       height:
         max: 480
     enableScreensharing: false
-    enableVideo: false
+    enableVideo: true
     enableVideoStats: false
     enableListenOnly: false
     autoShareWebcam: false