Merge pull request #850 from t3chguy/webrtc_settings
webrtc config electron
This commit is contained in:
commit
ec433907f0
4 changed files with 200 additions and 0 deletions
65
src/CallMediaHandler.js
Normal file
65
src/CallMediaHandler.js
Normal file
|
@ -0,0 +1,65 @@
|
||||||
|
/*
|
||||||
|
Copyright 2017 Michael Telatynski <7t3chguy@gmail.com>
|
||||||
|
|
||||||
|
Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
you may not use this file except in compliance with the License.
|
||||||
|
You may obtain a copy of the License at
|
||||||
|
|
||||||
|
http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
|
||||||
|
Unless required by applicable law or agreed to in writing, software
|
||||||
|
distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
See the License for the specific language governing permissions and
|
||||||
|
limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
import UserSettingsStore from './UserSettingsStore';
|
||||||
|
import * as Matrix from 'matrix-js-sdk';
|
||||||
|
import q from 'q';
|
||||||
|
|
||||||
|
export default {
|
||||||
|
getDevices: function() {
|
||||||
|
// Only needed for Electron atm, though should work in modern browsers
|
||||||
|
// once permission has been granted to the webapp
|
||||||
|
return navigator.mediaDevices.enumerateDevices().then(function(devices) {
|
||||||
|
const audioIn = [];
|
||||||
|
const videoIn = [];
|
||||||
|
|
||||||
|
if (devices.some((device) => !device.label)) return false;
|
||||||
|
|
||||||
|
devices.forEach((device) => {
|
||||||
|
switch (device.kind) {
|
||||||
|
case 'audioinput': audioIn.push(device); break;
|
||||||
|
case 'videoinput': videoIn.push(device); break;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// console.log("Loaded WebRTC Devices", mediaDevices);
|
||||||
|
return {
|
||||||
|
audioinput: audioIn,
|
||||||
|
videoinput: videoIn,
|
||||||
|
};
|
||||||
|
}, (error) => { console.log('Unable to refresh WebRTC Devices: ', error); });
|
||||||
|
},
|
||||||
|
|
||||||
|
loadDevices: function() {
|
||||||
|
// this.getDevices().then((devices) => {
|
||||||
|
const localSettings = UserSettingsStore.getLocalSettings();
|
||||||
|
// // if deviceId is not found, automatic fallback is in spec
|
||||||
|
// // recall previously stored inputs if any
|
||||||
|
Matrix.setMatrixCallAudioInput(localSettings['webrtc_audioinput']);
|
||||||
|
Matrix.setMatrixCallVideoInput(localSettings['webrtc_videoinput']);
|
||||||
|
// });
|
||||||
|
},
|
||||||
|
|
||||||
|
setAudioInput: function(deviceId) {
|
||||||
|
UserSettingsStore.setLocalSetting('webrtc_audioinput', deviceId);
|
||||||
|
Matrix.setMatrixCallAudioInput(deviceId);
|
||||||
|
},
|
||||||
|
|
||||||
|
setVideoInput: function(deviceId) {
|
||||||
|
UserSettingsStore.setLocalSetting('webrtc_videoinput', deviceId);
|
||||||
|
Matrix.setMatrixCallVideoInput(deviceId);
|
||||||
|
},
|
||||||
|
};
|
|
@ -22,6 +22,7 @@ import UserSettingsStore from '../../UserSettingsStore';
|
||||||
import KeyCode from '../../KeyCode';
|
import KeyCode from '../../KeyCode';
|
||||||
import Notifier from '../../Notifier';
|
import Notifier from '../../Notifier';
|
||||||
import PageTypes from '../../PageTypes';
|
import PageTypes from '../../PageTypes';
|
||||||
|
import CallMediaHandler from '../../CallMediaHandler';
|
||||||
import sdk from '../../index';
|
import sdk from '../../index';
|
||||||
import dis from '../../dispatcher';
|
import dis from '../../dispatcher';
|
||||||
|
|
||||||
|
@ -79,6 +80,8 @@ export default React.createClass({
|
||||||
// RoomView.getScrollState()
|
// RoomView.getScrollState()
|
||||||
this._scrollStateMap = {};
|
this._scrollStateMap = {};
|
||||||
|
|
||||||
|
CallMediaHandler.loadDevices();
|
||||||
|
|
||||||
document.addEventListener('keydown', this._onKeyDown);
|
document.addEventListener('keydown', this._onKeyDown);
|
||||||
this._matrixClient.on("accountData", this.onAccountData);
|
this._matrixClient.on("accountData", this.onAccountData);
|
||||||
},
|
},
|
||||||
|
|
|
@ -24,6 +24,7 @@ const dis = require("../../dispatcher");
|
||||||
const q = require('q');
|
const q = require('q');
|
||||||
const packageJson = require('../../../package.json');
|
const packageJson = require('../../../package.json');
|
||||||
const UserSettingsStore = require('../../UserSettingsStore');
|
const UserSettingsStore = require('../../UserSettingsStore');
|
||||||
|
const CallMediaHandler = require('../../CallMediaHandler');
|
||||||
const GeminiScrollbar = require('react-gemini-scrollbar');
|
const GeminiScrollbar = require('react-gemini-scrollbar');
|
||||||
const Email = require('../../email');
|
const Email = require('../../email');
|
||||||
const AddThreepid = require('../../AddThreepid');
|
const AddThreepid = require('../../AddThreepid');
|
||||||
|
@ -176,6 +177,7 @@ module.exports = React.createClass({
|
||||||
email_add_pending: false,
|
email_add_pending: false,
|
||||||
vectorVersion: undefined,
|
vectorVersion: undefined,
|
||||||
rejectingInvites: false,
|
rejectingInvites: false,
|
||||||
|
mediaDevices: null,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -196,6 +198,8 @@ module.exports = React.createClass({
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this._refreshMediaDevices();
|
||||||
|
|
||||||
// Bulk rejecting invites:
|
// Bulk rejecting invites:
|
||||||
// /sync won't have had time to return when UserSettings re-renders from state changes, so getRooms()
|
// /sync won't have had time to return when UserSettings re-renders from state changes, so getRooms()
|
||||||
// will still return rooms with invites. To get around this, add a listener for
|
// will still return rooms with invites. To get around this, add a listener for
|
||||||
|
@ -257,6 +261,20 @@ module.exports = React.createClass({
|
||||||
this.setState({ electron_settings: settings });
|
this.setState({ electron_settings: settings });
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_refreshMediaDevices: function() {
|
||||||
|
q().then(() => {
|
||||||
|
return CallMediaHandler.getDevices();
|
||||||
|
}).then((mediaDevices) => {
|
||||||
|
// console.log("got mediaDevices", mediaDevices, this._unmounted);
|
||||||
|
if (this._unmounted) return;
|
||||||
|
this.setState({
|
||||||
|
mediaDevices,
|
||||||
|
activeAudioInput: this._localSettings['webrtc_audioinput'],
|
||||||
|
activeVideoInput: this._localSettings['webrtc_videoinput'],
|
||||||
|
});
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
_refreshFromServer: function() {
|
_refreshFromServer: function() {
|
||||||
const self = this;
|
const self = this;
|
||||||
q.all([
|
q.all([
|
||||||
|
@ -883,6 +901,110 @@ module.exports = React.createClass({
|
||||||
</div>;
|
</div>;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
_mapWebRtcDevicesToSpans: function(devices) {
|
||||||
|
return devices.map((device) => <span key={device.deviceId}>{device.label}</span>);
|
||||||
|
},
|
||||||
|
|
||||||
|
_setAudioInput: function(deviceId) {
|
||||||
|
this.setState({activeAudioInput: deviceId});
|
||||||
|
CallMediaHandler.setAudioInput(deviceId);
|
||||||
|
},
|
||||||
|
|
||||||
|
_setVideoInput: function(deviceId) {
|
||||||
|
this.setState({activeVideoInput: deviceId});
|
||||||
|
CallMediaHandler.setVideoInput(deviceId);
|
||||||
|
},
|
||||||
|
|
||||||
|
_requestMediaPermissions: function(event) {
|
||||||
|
const getUserMedia = (
|
||||||
|
window.navigator.getUserMedia || window.navigator.webkitGetUserMedia || window.navigator.mozGetUserMedia
|
||||||
|
);
|
||||||
|
if (getUserMedia) {
|
||||||
|
return getUserMedia.apply(window.navigator, [
|
||||||
|
{ video: true, audio: true },
|
||||||
|
this._refreshMediaDevices,
|
||||||
|
function() {
|
||||||
|
const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
|
||||||
|
Modal.createDialog(ErrorDialog, {
|
||||||
|
title: _t('No media permissions'),
|
||||||
|
description: _t('You may need to manually permit Riot to access your microphone/webcam'),
|
||||||
|
});
|
||||||
|
},
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
_renderWebRtcSettings: function() {
|
||||||
|
if (this.state.mediaDevices === false) {
|
||||||
|
return <div>
|
||||||
|
<h3>{_t('VoIP')}</h3>
|
||||||
|
<div className="mx_UserSettings_section">
|
||||||
|
<p className="mx_UserSettings_link" onClick={this._requestMediaPermissions}>
|
||||||
|
{_t('Missing Media Permissions, click here to request.')}
|
||||||
|
</p>
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
} else if (!this.state.mediaDevices) return;
|
||||||
|
|
||||||
|
const Dropdown = sdk.getComponent('elements.Dropdown');
|
||||||
|
|
||||||
|
let microphoneDropdown = <p>{_t('No Microphones detected')}</p>;
|
||||||
|
let webcamDropdown = <p>{_t('No Webcams detected')}</p>;
|
||||||
|
|
||||||
|
const defaultOption = {
|
||||||
|
deviceId: '',
|
||||||
|
label: _t('Default Device'),
|
||||||
|
};
|
||||||
|
|
||||||
|
const audioInputs = this.state.mediaDevices.audioinput.slice(0);
|
||||||
|
if (audioInputs.length > 0) {
|
||||||
|
let defaultInput = '';
|
||||||
|
if (!audioInputs.some((input) => input.deviceId === 'default')) {
|
||||||
|
audioInputs.unshift(defaultOption);
|
||||||
|
} else {
|
||||||
|
defaultInput = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
microphoneDropdown = <div>
|
||||||
|
<h4>{_t('Microphone')}</h4>
|
||||||
|
<Dropdown
|
||||||
|
className="mx_UserSettings_webRtcDevices_dropdown"
|
||||||
|
value={this.state.activeAudioInput || defaultInput}
|
||||||
|
onOptionChange={this._setAudioInput}>
|
||||||
|
{this._mapWebRtcDevicesToSpans(audioInputs)}
|
||||||
|
</Dropdown>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
const videoInputs = this.state.mediaDevices.videoinput.slice(0);
|
||||||
|
if (videoInputs.length > 0) {
|
||||||
|
let defaultInput = '';
|
||||||
|
if (!videoInputs.some((input) => input.deviceId === 'default')) {
|
||||||
|
videoInputs.unshift(defaultOption);
|
||||||
|
} else {
|
||||||
|
defaultInput = 'default';
|
||||||
|
}
|
||||||
|
|
||||||
|
webcamDropdown = <div>
|
||||||
|
<h4>{_t('Camera')}</h4>
|
||||||
|
<Dropdown
|
||||||
|
className="mx_UserSettings_webRtcDevices_dropdown"
|
||||||
|
value={this.state.activeVideoInput || defaultInput}
|
||||||
|
onOptionChange={this._setVideoInput}>
|
||||||
|
{this._mapWebRtcDevicesToSpans(videoInputs)}
|
||||||
|
</Dropdown>
|
||||||
|
</div>;
|
||||||
|
}
|
||||||
|
|
||||||
|
return <div>
|
||||||
|
<h3>{_t('VoIP')}</h3>
|
||||||
|
<div className="mx_UserSettings_section">
|
||||||
|
{microphoneDropdown}
|
||||||
|
{webcamDropdown}
|
||||||
|
</div>
|
||||||
|
</div>;
|
||||||
|
},
|
||||||
|
|
||||||
_showSpoiler: function(event) {
|
_showSpoiler: function(event) {
|
||||||
const target = event.target;
|
const target = event.target;
|
||||||
target.innerHTML = target.getAttribute('data-spoiler');
|
target.innerHTML = target.getAttribute('data-spoiler');
|
||||||
|
@ -1080,6 +1202,7 @@ module.exports = React.createClass({
|
||||||
|
|
||||||
{this._renderUserInterfaceSettings()}
|
{this._renderUserInterfaceSettings()}
|
||||||
{this._renderLabs()}
|
{this._renderLabs()}
|
||||||
|
{this._renderWebRtcSettings()}
|
||||||
{this._renderDevicesPanel()}
|
{this._renderDevicesPanel()}
|
||||||
{this._renderCryptoInfo()}
|
{this._renderCryptoInfo()}
|
||||||
{this._renderBulkOptions()}
|
{this._renderBulkOptions()}
|
||||||
|
|
|
@ -129,6 +129,15 @@
|
||||||
"Add email address": "Add email address",
|
"Add email address": "Add email address",
|
||||||
"Add phone number": "Add phone number",
|
"Add phone number": "Add phone number",
|
||||||
"Admin": "Admin",
|
"Admin": "Admin",
|
||||||
|
"VoIP": "VoIP",
|
||||||
|
"Missing Media Permissions, click here to request.": "Missing Media Permissions, click here to request.",
|
||||||
|
"No Microphones detected": "No Microphones detected",
|
||||||
|
"No Webcams detected": "No Webcams detected",
|
||||||
|
"No media permissions": "No media permissions",
|
||||||
|
"You may need to manually permit Riot to access your microphone/webcam": "You may need to manually permit Riot to access your microphone/webcam",
|
||||||
|
"Default Device": "Default Device",
|
||||||
|
"Microphone": "Microphone",
|
||||||
|
"Camera": "Camera",
|
||||||
"Advanced": "Advanced",
|
"Advanced": "Advanced",
|
||||||
"Algorithm": "Algorithm",
|
"Algorithm": "Algorithm",
|
||||||
"Always show message timestamps": "Always show message timestamps",
|
"Always show message timestamps": "Always show message timestamps",
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue