diff --git a/conference.js b/conference.js
index 618b230a2..75333fcc3 100644
--- a/conference.js
+++ b/conference.js
@@ -73,8 +73,11 @@ function getDisplayName (id) {
/**
* Mute or unmute local audio stream if it exists.
* @param {boolean} muted if audio stream should be muted or unmuted.
+ * @param {boolean} indicates if this local audio mute was a result of user
+ * interaction
+ *
*/
-function muteLocalAudio (muted) {
+function muteLocalAudio (muted, userInteraction) {
if (!localAudio) {
return;
}
diff --git a/index.html b/index.html
index 8c201d8e3..f4ac8e737 100644
--- a/index.html
+++ b/index.html
@@ -124,6 +124,9 @@
+
diff --git a/lang/main.json b/lang/main.json
index 963c6e553..f05fe8791 100644
--- a/lang/main.json
+++ b/lang/main.json
@@ -65,7 +65,8 @@
"logout": "Logout",
"dialpad": "Show dialpad",
"sharedVideoMutedPopup": "Your shared video has been muted so
that you can talk to the other participants.",
- "micMutedPopup": "Your microphone has been muted so that you
would fully enjoy your shared video."
+ "micMutedPopup": "Your microphone has been muted so that you
would fully enjoy your shared video.",
+ "unableToUnmutePopup": "You're not able to un-mute while the shared video is on."
},
"bottomtoolbar": {
"chat": "Open / close chat",
diff --git a/modules/UI/UI.js b/modules/UI/UI.js
index 260b003b9..cafe3ef9d 100644
--- a/modules/UI/UI.js
+++ b/modules/UI/UI.js
@@ -331,6 +331,14 @@ function bindEvents() {
$(window).resize(onResize);
}
+/**
+ * Returns the shared document manager object.
+ * @return {EtherpadManager} the shared document manager object
+ */
+UI.getSharedVideoManager = function () {
+ return sharedVideoManager;
+};
+
/**
* Starts the UI module and initializes all related components.
*
diff --git a/modules/UI/shared_video/SharedVideo.js b/modules/UI/shared_video/SharedVideo.js
index ea2ca86e3..aa9af4deb 100644
--- a/modules/UI/shared_video/SharedVideo.js
+++ b/modules/UI/shared_video/SharedVideo.js
@@ -26,6 +26,24 @@ export default class SharedVideoManager {
this.emitter = emitter;
this.isSharedVideoShown = false;
this.isPlayerAPILoaded = false;
+ this.mutedWithUserInteraction = false;
+ }
+
+ /**
+ * Indicates if the player volume is currently on.
+ *
+ * @returns {*|player|boolean}
+ */
+ isSharedVideoVolumeOn() {
+ return (this.player && this.player.getVolume() > 0);
+ }
+
+ /**
+ * Indicates if the local user is the owner of the shared video.
+ * @returns {*|boolean}
+ */
+ isSharedVideoOwner() {
+ return this.from && APP.conference.isLocalId(this.from);
}
/**
@@ -169,10 +187,15 @@ export default class SharedVideoManager {
// let's check, if player is not muted lets mute locally
if(event.data.volume > 0 && !event.data.muted
- && !APP.conference.isLocalAudioMuted()){
- self.emitter.emit(UIEvents.AUDIO_MUTED, true);
+ && !APP.conference.isLocalAudioMuted()) {
+ self.emitter.emit(UIEvents.AUDIO_MUTED, true, false);
self.showMicMutedPopup(true);
}
+ else if (!self.mutedWithUserInteraction
+ && (event.data.volume <=0 || event.data.muted)
+ && APP.conference.isLocalAudioMuted()) {
+ self.emitter.emit(UIEvents.AUDIO_MUTED, false, false);
+ }
};
window.onPlayerReady = function(event) {
@@ -231,9 +254,11 @@ export default class SharedVideoManager {
this.processTime(player, attributes, playerPaused);
// lets check the volume
- if (attributes.volume !== undefined &&
- player.getVolume() != attributes.volume
- && APP.conference.isLocalAudioMuted()) {
+ if (attributes.volume !== undefined
+ && player.getVolume() != attributes.volume
+ && (APP.conference.isLocalAudioMuted()
+ || !this.mutedWithUserInteraction)) {
+
player.setVolume(attributes.volume);
console.info("Player change of volume:" + attributes.volume);
this.showSharedVideoMutedPopup(false);
@@ -393,17 +418,21 @@ export default class SharedVideoManager {
/**
* Receives events for local audio mute/unmute by local user.
* @param muted boolena whether it is muted or not.
+ * @param {boolean} indicates if this mute was a result of user interaction,
+ * i.e. pressing the mute button or it was programatically triggerred
*/
- localAudioMuted (muted) {
+ localAudioMuted (muted, userInteraction) {
if(!this.player)
return;
- if(muted)
+ if (muted) {
+ this.mutedWithUserInteraction = userInteraction;
return;
+ }
// if we are un-muting and player is not muted, lets muted
// to not pollute the conference
- if(this.player.getVolume() > 0 || !this.player.isMuted()){
+ if (this.player.getVolume() > 0 || !this.player.isMuted()) {
this.player.setVolume(0);
this.showSharedVideoMutedPopup(true);
}
@@ -415,30 +444,10 @@ export default class SharedVideoManager {
* @param show boolean, show or hide the notification
*/
showMicMutedPopup (show) {
- var micMutedPopupSelector = $("#micMutedPopup");
- if(show) {
+ if(show)
this.showSharedVideoMutedPopup(false);
- if (!micMutedPopupSelector.is(":visible"))
- micMutedPopupSelector.css("display", "inline-block");
-
- // FIXME: we need an utility method for that.
- micMutedPopupSelector.fadeIn(300,
- () => {micMutedPopupSelector.css({opacity: 1});}
- );
-
- setTimeout(
- function () {
- micMutedPopupSelector.fadeOut(300,
- () => {micMutedPopupSelector.css({opacity: 0});}
- );
- }, 5000);
- }
- else {
- micMutedPopupSelector.fadeOut(300,
- () => {micMutedPopupSelector.css({opacity: 0});}
- );
- }
+ UIUtil.animateShowElement($("#micMutedPopup"), show, 5000);
}
/**
@@ -448,30 +457,10 @@ export default class SharedVideoManager {
* @param show boolean, show or hide the notification
*/
showSharedVideoMutedPopup (show) {
- var sharedVideoMutedPopupSelector = $("#sharedVideoMutedPopup");
- if(show) {
+ if(show)
this.showMicMutedPopup(false);
- if (!sharedVideoMutedPopupSelector.is(":visible"))
- sharedVideoMutedPopupSelector.css("display", "inline-block");
-
- // FIXME: we need an utility method for that.
- sharedVideoMutedPopupSelector.fadeIn(300,
- () => {sharedVideoMutedPopupSelector.css({opacity: 1});}
- );
-
- setTimeout(
- function () {
- sharedVideoMutedPopupSelector.fadeOut(300,
- () => {sharedVideoMutedPopupSelector.css({opacity: 0});}
- );
- }, 5000);
- }
- else {
- sharedVideoMutedPopupSelector.fadeOut(300,
- () => {sharedVideoMutedPopupSelector.css({opacity: 0});}
- );
- }
+ UIUtil.animateShowElement($("#sharedVideoMutedPopup"), show, 5000);
}
}
diff --git a/modules/UI/toolbars/Toolbar.js b/modules/UI/toolbars/Toolbar.js
index 7a95487ee..e98abc9cc 100644
--- a/modules/UI/toolbars/Toolbar.js
+++ b/modules/UI/toolbars/Toolbar.js
@@ -44,12 +44,25 @@ function openLinkDialog () {
const buttonHandlers = {
"toolbar_button_mute": function () {
+ let sharedVideoManager = APP.UI.getSharedVideoManager();
+
if (APP.conference.audioMuted) {
- AnalyticsAdapter.sendEvent('toolbar.audio.unmuted');
- emitter.emit(UIEvents.AUDIO_MUTED, false);
+ // If there's a shared video with the volume "on" and we aren't
+ // the video owner, we warn the user
+ // that currently it's not possible to unmute.
+ if (sharedVideoManager
+ && sharedVideoManager.isSharedVideoVolumeOn()
+ && !sharedVideoManager.isSharedVideoOwner()) {
+ UIUtil.animateShowElement(
+ $("#unableToUnmutePopup"), true, 5000);
+ }
+ else {
+ AnalyticsAdapter.sendEvent('toolbar.audio.unmuted');
+ emitter.emit(UIEvents.AUDIO_MUTED, false, true);
+ }
} else {
AnalyticsAdapter.sendEvent('toolbar.audio.muted');
- emitter.emit(UIEvents.AUDIO_MUTED, true);
+ emitter.emit(UIEvents.AUDIO_MUTED, true, true);
}
},
"toolbar_button_camera": function () {
diff --git a/modules/UI/util/UIUtil.js b/modules/UI/util/UIUtil.js
index 4e3e381e3..0e37b5b11 100644
--- a/modules/UI/util/UIUtil.js
+++ b/modules/UI/util/UIUtil.js
@@ -166,6 +166,39 @@
*/
isVisible(el) {
return (el.offsetParent !== null);
+ },
+
+ /**
+ * Shows / hides the element given by {selector} and sets a timeout if the
+ * {hideDelay} is set to a value > 0.
+ * @param selector the jquery selector of the element to show/hide.
+ * @param show a {boolean} that indicates if the element should be shown or
+ * hidden
+ * @param hideDelay the value in milliseconds to wait before hiding the
+ * element
+ */
+ animateShowElement(selector, show, hideDelay) {
+ if(show) {
+ if (!selector.is(":visible"))
+ selector.css("display", "inline-block");
+
+ selector.fadeIn(300,
+ () => {selector.css({opacity: 1});}
+ );
+
+ if (hideDelay && hideDelay > 0)
+ setTimeout(
+ function () {
+ selector.fadeOut(300,
+ () => {selector.css({opacity: 0});}
+ );
+ }, hideDelay);
+ }
+ else {
+ selector.fadeOut(300,
+ () => {selector.css({opacity: 0});}
+ );
+ }
}
};