webrtc config electron

init on LoggedInView mounting
configurable via UserSettings
new class: CallMediaHandler

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2017-04-28 18:21:22 +01:00
parent 0e880f7971
commit c6262d62a6
3 changed files with 145 additions and 1 deletions

63
src/CallMediaHandler.js Normal file
View file

@ -0,0 +1,63 @@
/*
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 = {};
devices.forEach((device) => {
switch (device.kind) {
case 'audioinput': audioIn[device.deviceId] = device.label; break;
case 'videoinput': videoIn[device.deviceId] = device.label; 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);
},
};

View file

@ -21,6 +21,7 @@ import React from 'react';
import KeyCode from '../../KeyCode';
import Notifier from '../../Notifier';
import PageTypes from '../../PageTypes';
import CallMediaHandler from '../../CallMediaHandler';
import sdk from '../../index';
import dis from '../../dispatcher';
@ -71,6 +72,10 @@ export default React.createClass({
// RoomView.getScrollState()
this._scrollStateMap = {};
// Only run these in electron, at least until a better mechanism for perms exists
// https://w3c.github.io/permissions/#dom-permissionname-device-info
if (window && window.process && window.process.type) CallMediaHandler.loadDevices();
document.addEventListener('keydown', this._onKeyDown);
},

View file

@ -24,6 +24,7 @@ var dis = require("../../dispatcher");
var q = require('q');
var package_json = require('../../../package.json');
var UserSettingsStore = require('../../UserSettingsStore');
var CallMediaHandler = require('../../CallMediaHandler');
var GeminiScrollbar = require('react-gemini-scrollbar');
var Email = require('../../email');
var AddThreepid = require('../../AddThreepid');
@ -109,7 +110,6 @@ const THEMES = [
}
];
module.exports = React.createClass({
displayName: 'UserSettings',
@ -147,6 +147,7 @@ module.exports = React.createClass({
email_add_pending: false,
vectorVersion: null,
rejectingInvites: false,
mediaDevices: null,
};
},
@ -167,6 +168,18 @@ module.exports = React.createClass({
});
}
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'] || 'default',
activeVideoInput: this._localSettings['webrtc_videoinput'] || 'default',
});
});
// Bulk rejecting invites:
// /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
@ -187,6 +200,8 @@ module.exports = React.createClass({
this._syncedSettings = syncedSettings;
this._localSettings = UserSettingsStore.getLocalSettings();
this._setAudioInput = this._setAudioInput.bind(this);
this._setVideoInput = this._setVideoInput.bind(this);
},
componentDidMount: function() {
@ -775,6 +790,66 @@ module.exports = React.createClass({
</div>;
},
_mapWebRtcDevicesToSpans: function(devices) {
return Object.keys(devices).map(
(deviceId) => <span key={deviceId}>{devices[deviceId]}</span>
);
},
_setAudioInput: function(deviceId) {
this.setState({activeAudioInput: deviceId});
CallMediaHandler.setAudioInput(deviceId);
},
_setVideoInput: function(deviceId) {
this.setState({activeVideoInput: deviceId});
CallMediaHandler.setVideoInput(deviceId);
},
_renderWebRtcSettings: function() {
if (!(window && window.process && window.process.type)
|| !this.state.mediaDevices) return;
const Dropdown = sdk.getComponent('elements.Dropdown');
let microphoneDropdown = <h5>No Microphones detected</h5>;
let webcamDropdown = <h5>No Webcams detected</h5>;
const audioInputs = this.state.mediaDevices.audioinput;
if ('default' in audioInputs) {
microphoneDropdown = <div>
<h4>Microphone</h4>
<Dropdown
className="mx_UserSettings_webRtcDevices_dropdown"
value={this.state.activeAudioInput}
onOptionChange={this._setAudioInput}>
{this._mapWebRtcDevicesToSpans(audioInputs)}
</Dropdown>
</div>;
}
const videoInputs = this.state.mediaDevices.videoinput;
if ('default' in videoInputs) {
webcamDropdown = <div>
<h4>Cameras</h4>
<Dropdown
className="mx_UserSettings_webRtcDevices_dropdown"
value={this.state.activeVideoInput}
onOptionChange={this._setVideoInput}>
{this._mapWebRtcDevicesToSpans(videoInputs)}
</Dropdown>
</div>;
}
return <div>
<h3>WebRTC</h3>
<div className="mx_UserSettings_section">
{microphoneDropdown}
{webcamDropdown}
</div>
</div>;
},
_showSpoiler: function(event) {
const target = event.target;
const hidden = target.getAttribute('data-spoiler');
@ -973,6 +1048,7 @@ module.exports = React.createClass({
{this._renderUserInterfaceSettings()}
{this._renderLabs()}
{this._renderWebRtcSettings()}
{this._renderDevicesPanel()}
{this._renderCryptoInfo()}
{this._renderBulkOptions()}