diff --git a/css/style.scss b/css/style.scss
index 57a0447f9a0..aa1bc561e9e 100644
--- a/css/style.scss
+++ b/css/style.scss
@@ -922,9 +922,54 @@ input[type="password"] {
}
}
}
+ .talk-settings-button {
+ position: relative;
+
+ .button {
+ cursor: pointer;
+ width: 50px;
+ height: 50px;
+ display: block;
+ background-color: transparent;
+ border: none;
+ margin: 0;
+ opacity: .7;
+ &:hover,
+ &:focus,
+ &:active {
+ opacity: 1;
+ }
+ }
+ }
}
}
+.icon-speaker {
+ background-image: url('../img/speaker.svg?v=1');
+ background-size: contain;
+}
+
+.settings-option {
+ background-position: left;
+ display: inline-block;
+ position: relative;
+ top: 3px;
+ margin-right: 5px;
+}
+
+.settings-input {
+ width: 90%;
+ margin-bottom: 10px;
+}
+
+.settings-menu {
+ padding: 10px;
+}
+
+.settings-confirm {
+ float: right;
+}
+
/**
* Cascade parent element height to the chat view in the sidebar to limit the
* vertical scroll bar only to the list of messages. Otherwise, the vertical
diff --git a/img/speaker.svg b/img/speaker.svg
new file mode 100644
index 00000000000..277120ed9ec
--- /dev/null
+++ b/img/speaker.svg
@@ -0,0 +1 @@
+
diff --git a/js/app.js b/js/app.js
index 48231662325..8556ff05c09 100644
--- a/js/app.js
+++ b/js/app.js
@@ -218,6 +218,106 @@
}.bind(this));
},
+ onAudioOutputChange: function() {
+ localStorage.setItem('audioOutput', $('#audioOutput').val());
+
+ },
+
+ onAudioSourceChange: function() {
+ localStorage.setItem("audioSource", $('#audioSource').val());
+ OCA.SpreedMe.app.setMediaSource(localStorage.getItem("audioSource"), localStorage.getItem("videoSource"));
+ },
+
+ onVideoSourceChange: function() {
+ localStorage.setItem("videoSource", $('#videoSource').val());
+ OCA.SpreedMe.app.setMediaSource(localStorage.getItem("audioSource"), localStorage.getItem("videoSource"));
+ },
+
+ initMediaSources: function() {
+ OCA.SpreedMe.app.setMediaSource(localStorage.getItem("audioSource"), localStorage.getItem("videoSource"));
+ },
+
+ setMediaSource: function(audioSource, videoSource) {
+
+ if (typeof OCA.SpreedMe.webrtc !== 'undefined') {
+ OCA.SpreedMe.webrtc.config.media = {
+ audio: {
+ optional: [{sourceId: audioSource}]
+ },
+ video: {
+ optional: [{sourceId: videoSource}]
+ }
+ };
+ }
+
+ if (OCA.SpreedMe.app.signaling.currentCallToken !== null) {
+ this.changingMedia = true;
+ OCA.SpreedMe.app.signaling.leaveCurrentCall();
+ OCA.SpreedMe.webrtc.stopLocalVideo();
+
+ OCA.SpreedMe.webrtc.startLocalVideo(OCA.SpreedMe.webrtc.config.media);
+ OCA.SpreedMe.app.connection.joinCall(this.activeRoom.get('token'));
+
+ /*var senders = existingPeer.pc.getLocalStreams();
+ for (var i = 0; i < senders.length; i++) {
+ existingPeer.pc.removeStream(senders[i]);
+ }
+ OCA.SpreedMe.webrtc.on('localStream', function() {
+ senders = this.webrtc.localStreams;
+ var localStreams = existingPeer.pc.getLocalStreams();
+ for (var i = 0; i < senders.length; i++) {
+ if (!localStreams.includes(senders[i])) {
+ existingPeer.pc.addStream(senders[i]);
+ }
+ }
+ });*/
+ }
+ },
+
+ startShareScreen: function(mode) {
+ var webrtc = OCA.SpreedMe.webrtc;
+ var screensharingButton = $('#screensharing-button');
+ screensharingButton.prop('disabled', true);
+ webrtc.shareScreen(mode, function(err) {
+ screensharingButton.prop('disabled', false);
+ if (!err) {
+ $('#screensharing-button').attr('data-original-title', t('spreed', 'Screensharing options'))
+ .removeClass('screensharing-disabled icon-screen-off')
+ .addClass('icon-screen');
+ return;
+ }
+ switch (err.name) {
+ case "HTTPS_REQUIRED":
+ OC.Notification.showTemporary(t('spreed', 'Screensharing requires the page to be loaded through HTTPS.'));
+ break;
+ case "PERMISSION_DENIED":
+ case "NotAllowedError":
+ case "CEF_GETSCREENMEDIA_CANCELED": // Experimental, may go away in the future.
+ break;
+ case "FF52_REQUIRED":
+ OC.Notification.showTemporary(t('spreed', 'Sharing your screen only works with Firefox version 52 or newer.'));
+ break;
+ case "EXTENSION_UNAVAILABLE":
+ var extensionURL = null;
+ if (!!window.chrome && !!window.chrome.webstore) {// Chrome
+ extensionURL = 'https://chrome.google.com/webstore/detail/screensharing-for-nextclo/kepnpjhambipllfmgmbapncekcmabkol';
+ }
+ if (extensionURL) {
+ var text = t('spreed', 'Screensharing extension is required to share your screen.');
+ var element = $('').attr('href', extensionURL).attr('target','_blank').text(text);
+ OC.Notification.showTemporary(element, {isHTML: true});
+ } else {
+ OC.Notification.showTemporary(t('spreed', 'Please use a different browser like Firefox or Chrome to share your screen.'));
+ }
+ break;
+ default:
+ OC.Notification.showTemporary(t('spreed', 'An error occurred while starting screensharing.'));
+ console.log("Could not start screensharing", err);
+ break;
+ }
+ });
+ },
+
_onKeyUp: function(event) {
// Define which objects to check for the event properties.
var key = event.which;
@@ -363,6 +463,11 @@
return;
}
+ if (this.changingMedia) {
+ this.changingMedia = false;
+ return;
+ }
+
var flags = this.activeRoom.get('participantFlags') || 0;
var inCall = flags & OCA.SpreedMe.app.FLAG_IN_CALL !== 0;
if (inCall && this._chatViewInMainView === true) {
diff --git a/js/views/callinfoview.js b/js/views/callinfoview.js
index 10cc8de23f7..9edea4b61b3 100644
--- a/js/views/callinfoview.js
+++ b/js/views/callinfoview.js
@@ -71,8 +71,33 @@
'
' +
' ' +
'{{/if}}' +
+ '' +
+ ' ' +
+ '
' +
+ '' +
+ '';
+
var CallInfoView = Marionette.View.extend({
tagName: 'div',
@@ -91,6 +116,7 @@
canFullModerate: this._canFullModerate(),
isPublic: this.model.get('type') === 3,
showShareLink: !canModerate && this.model.get('type') === 3,
+ canPublish: OCA.SpreedMe.canPublish(),
isDeletable: canModerate && (Object.keys(this.model.get('participants')).length > 2 || this.model.get('numGuests') > 0)
});
},
@@ -112,6 +138,10 @@
'passwordConfirm': '.password-confirm',
'menu': '.password-menu',
+
+ 'settingsButton': '.talk-settings-button',
+ 'settingsMenu': '.settings-menu',
+ 'settingsInput': '.settings-input',
},
regions: {
@@ -126,6 +156,7 @@
'click @ui.passwordButton': 'showPasswordInput',
'click @ui.passwordConfirm': 'confirmPassword',
'submit @ui.passwordForm': 'confirmPassword',
+ 'click @ui.settingsButton': 'settingsButtonClicked',
},
modelEvents: {
@@ -242,6 +273,82 @@
$(self.ui.passwordInput).focus();
});
+ this.initSettings();
+
+ },
+
+ gotSources: function(sourceInfos) {
+ var audioSelect = document.querySelector("select#audioSource");
+ var videoSelect = document.querySelector("select#videoSource");
+ var outputSelect = document.querySelector("select#audioOutput");
+
+ // clear the lists
+ $('#audioOutput').empty();
+ $('#audioSource').empty();
+ $('#videoSource').empty();
+
+ for (var i = 0; i != sourceInfos.length; ++i) {
+ var sourceInfo = sourceInfos[i];
+ var option = document.createElement("option");
+ option.value = sourceInfo.deviceId;
+ if (sourceInfo.kind === 'audioinput' && audioSelect !== null) {
+ option.text = sourceInfo.label || 'microphone ' + (audioSelect.length + 1);
+ audioSelect.appendChild(option);
+ } else if (sourceInfo.kind === 'videoinput' && videoSelect !== null) {
+ option.text = sourceInfo.label || 'camera ' + (videoSelect.length + 1);
+ videoSelect.appendChild(option);
+ } else if (sourceInfo.kind === 'audiooutput') {
+ option.text = sourceInfo.label || 'speaker ' + (outputSelect.length + 1);
+ outputSelect.appendChild(option);
+ }
+ }
+
+ // hide empty options
+ if ($('#audioOutput option').length === 0) {
+ var option = document.createElement("option");
+ option.value = sourceInfo.deviceId;
+ option.text = 'Default';
+ outputSelect.appendChild(option);
+ }
+ else {
+ var val = localStorage.getItem("audioOutput");
+ if (val !== null) {
+ $('#audioOutput').val(val);
+ }
+ outputSelect.onchange = OCA.SpreedMe.app.onAudioOutputChange;
+ }
+
+ if ($('#videoSource option').length === 0) {
+ $('#videoSource').hide();
+ }
+ else {
+ var val = localStorage.getItem("videoSource");
+ if (val !== null) {
+ $('#videoSource').val(val);
+ }
+ videoSelect.onchange = OCA.SpreedMe.app.onVideoSourceChange;
+ }
+
+ if ($('#audioSource option').length === 0) {
+ $('#audioSource').hide();
+ }
+ else {
+ var val = localStorage.getItem("audioSource");
+ if (val !== null) {
+ $('#audioSource').val(val);
+ }
+ audioSelect.onchange = OCA.SpreedMe.app.onAudioSourceChange;
+ }
+
+ },
+
+ initSettings: function() {
+ navigator.mediaDevices.enumerateDevices().then(this.gotSources);
+ },
+
+ settingsButtonClicked: function(e) {
+ e.preventDefault();
+ $('.settings-menu').toggle();
},
_canModerate: function() {
diff --git a/js/webrtc.js b/js/webrtc.js
index 8a8cf16b82a..1bd7b1a8f63 100644
--- a/js/webrtc.js
+++ b/js/webrtc.js
@@ -1072,6 +1072,11 @@ var spreedPeerConnectionTable = [];
return;
}
+ // set the output device
+ if (localStorage.getItem("audioOutput") !== null) {
+ video.setSinkId(localStorage.getItem("audioOutput"));
+ }
+
var videoContainer = $(OCA.SpreedMe.videos.getContainerId(peer.id));
if (videoContainer.length) {
var userId = spreedMappingTable[peer.id];