Allow selecting audio output for WebRTC Audio/Video calls

Signed-off-by: Michael Telatynski <7t3chguy@gmail.com>
This commit is contained in:
Michael Telatynski 2018-05-26 17:22:23 +01:00
parent bbdc27019a
commit 6636fa32f6
No known key found for this signature in database
GPG key ID: 3F879DA5AD802A5E
3 changed files with 50 additions and 8 deletions

View file

@ -22,34 +22,44 @@ export default {
// Only needed for Electron atm, though should work in modern browsers // Only needed for Electron atm, though should work in modern browsers
// once permission has been granted to the webapp // once permission has been granted to the webapp
return navigator.mediaDevices.enumerateDevices().then(function(devices) { return navigator.mediaDevices.enumerateDevices().then(function(devices) {
const audioIn = []; const audiooutput = [];
const videoIn = []; const audioinput = [];
const videoinput = [];
if (devices.some((device) => !device.label)) return false; if (devices.some((device) => !device.label)) return false;
devices.forEach((device) => { devices.forEach((device) => {
switch (device.kind) { switch (device.kind) {
case 'audioinput': audioIn.push(device); break; case 'audiooutput': audiooutput.push(device); break;
case 'videoinput': videoIn.push(device); break; case 'audioinput': audioinput.push(device); break;
case 'videoinput': videoinput.push(device); break;
} }
}); });
// console.log("Loaded WebRTC Devices", mediaDevices); // console.log("Loaded WebRTC Devices", mediaDevices);
return { return {
audioinput: audioIn, audiooutput,
videoinput: videoIn, audioinput,
videoinput,
}; };
}, (error) => { console.log('Unable to refresh WebRTC Devices: ', error); }); }, (error) => { console.log('Unable to refresh WebRTC Devices: ', error); });
}, },
loadDevices: function() { loadDevices: function() {
const audioOutDeviceId = SettingsStore.getValue("webrtc_audiooutput");
const audioDeviceId = SettingsStore.getValue("webrtc_audioinput"); const audioDeviceId = SettingsStore.getValue("webrtc_audioinput");
const videoDeviceId = SettingsStore.getValue("webrtc_videoinput"); const videoDeviceId = SettingsStore.getValue("webrtc_videoinput");
Matrix.setMatrixCallAudioOutput(audioOutDeviceId);
Matrix.setMatrixCallAudioInput(audioDeviceId); Matrix.setMatrixCallAudioInput(audioDeviceId);
Matrix.setMatrixCallVideoInput(videoDeviceId); Matrix.setMatrixCallVideoInput(videoDeviceId);
}, },
setAudioOutput: function(deviceId) {
SettingsStore.setValue("webrtc_audiooutput", null, SettingLevel.DEVICE, deviceId);
Matrix.setMatrixCallAudioOutput(deviceId);
},
setAudioInput: function(deviceId) { setAudioInput: function(deviceId) {
SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId); SettingsStore.setValue("webrtc_audioinput", null, SettingLevel.DEVICE, deviceId);
Matrix.setMatrixCallAudioInput(deviceId); Matrix.setMatrixCallAudioInput(deviceId);

View file

@ -292,6 +292,7 @@ module.exports = React.createClass({
if (this._unmounted) return; if (this._unmounted) return;
this.setState({ this.setState({
mediaDevices, mediaDevices,
activeAudioOutput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_audiooutput'),
activeAudioInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_audioinput'), activeAudioInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_audioinput'),
activeVideoInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_videoinput'), activeVideoInput: SettingsStore.getValueAt(SettingLevel.DEVICE, 'webrtc_videoinput'),
}); });
@ -970,6 +971,11 @@ module.exports = React.createClass({
return devices.map((device) => <span key={device.deviceId}>{ device.label }</span>); return devices.map((device) => <span key={device.deviceId}>{ device.label }</span>);
}, },
_setAudioOutput: function(deviceId) {
this.setState({activeAudioOutput: deviceId});
CallMediaHandler.setAudioOutput(deviceId);
},
_setAudioInput: function(deviceId) { _setAudioInput: function(deviceId) {
this.setState({activeAudioInput: deviceId}); this.setState({activeAudioInput: deviceId});
CallMediaHandler.setAudioInput(deviceId); CallMediaHandler.setAudioInput(deviceId);
@ -1010,6 +1016,7 @@ module.exports = React.createClass({
const Dropdown = sdk.getComponent('elements.Dropdown'); const Dropdown = sdk.getComponent('elements.Dropdown');
let speakerDropdown = <p>{ _t('No Audio Outputs detected') }</p>;
let microphoneDropdown = <p>{ _t('No Microphones detected') }</p>; let microphoneDropdown = <p>{ _t('No Microphones detected') }</p>;
let webcamDropdown = <p>{ _t('No Webcams detected') }</p>; let webcamDropdown = <p>{ _t('No Webcams detected') }</p>;
@ -1018,6 +1025,26 @@ module.exports = React.createClass({
label: _t('Default Device'), label: _t('Default Device'),
}; };
const audioOutputs = this.state.mediaDevices.audiooutput.slice(0);
if (audioOutputs.length > 0) {
let defaultOutput = '';
if (!audioOutputs.some((input) => input.deviceId === 'default')) {
audioOutputs.unshift(defaultOption);
} else {
defaultOutput = 'default';
}
speakerDropdown = <div>
<h4>{ _t('Audio Output') }</h4>
<Dropdown
className="mx_UserSettings_webRtcDevices_dropdown"
value={this.state.activeAudioOutput || defaultOutput}
onOptionChange={this._setAudioOutput}>
{ this._mapWebRtcDevicesToSpans(audioOutputs) }
</Dropdown>
</div>;
}
const audioInputs = this.state.mediaDevices.audioinput.slice(0); const audioInputs = this.state.mediaDevices.audioinput.slice(0);
if (audioInputs.length > 0) { if (audioInputs.length > 0) {
let defaultInput = ''; let defaultInput = '';
@ -1059,6 +1086,7 @@ module.exports = React.createClass({
} }
return <div> return <div>
{ speakerDropdown }
{ microphoneDropdown } { microphoneDropdown }
{ webcamDropdown } { webcamDropdown }
</div>; </div>;

View file

@ -201,6 +201,10 @@ export const SETTINGS = {
displayName: _td('Disable Peer-to-Peer for 1:1 calls'), displayName: _td('Disable Peer-to-Peer for 1:1 calls'),
default: false, default: false,
}, },
"webrtc_audiooutput": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: null,
},
"webrtc_audioinput": { "webrtc_audioinput": {
supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS,
default: null, default: null,