diff --git a/src/CallHandler.js b/src/CallHandler.js index 40a8d426f8..f6b3e18538 100644 --- a/src/CallHandler.js +++ b/src/CallHandler.js @@ -1,6 +1,7 @@ /* Copyright 2015, 2016 OpenMarket Ltd Copyright 2017, 2018 New Vector Ltd +Copyright 2019 The Matrix.org Foundation C.I.C. Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. @@ -64,6 +65,7 @@ import { showUnknownDeviceDialogForCalls } from './cryptodevices'; import WidgetUtils from './utils/WidgetUtils'; import WidgetEchoStore from './stores/WidgetEchoStore'; import {IntegrationManagers} from "./integrations/IntegrationManagers"; +import SettingsStore, { SettingLevel } from './settings/SettingsStore'; global.mxCalls = { //room_id: MatrixCall @@ -117,8 +119,7 @@ function _reAttemptCall(call) { function _setCallListeners(call) { call.on("error", function(err) { - console.error("Call error: %s", err); - console.error(err.stack); + console.error("Call error:", err); if (err.code === 'unknown_devices') { const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); @@ -146,8 +147,15 @@ function _setCallListeners(call) { }, }); } else { - const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); + if ( + MatrixClientPeg.get().getTurnServers().length === 0 && + SettingsStore.getValue("fallbackICEServerAllowed") === null + ) { + _showICEFallbackPrompt(); + return; + } + const ErrorDialog = sdk.getComponent("dialogs.ErrorDialog"); Modal.createTrackedDialog('Call Failed', '', ErrorDialog, { title: _t('Call Failed'), description: err.message, @@ -217,6 +225,36 @@ function _setCallState(call, roomId, status) { }); } +function _showICEFallbackPrompt() { + const cli = MatrixClientPeg.get(); + const QuestionDialog = sdk.getComponent("dialogs.QuestionDialog"); + const code = sub => {sub}; + Modal.createTrackedDialog('No TURN servers', '', QuestionDialog, { + title: _t("Call failed due to misconfigured server"), + description:
+

{_t( + "Please ask the administrator of your homeserver " + + "(%(homeserverDomain)s) to configure a TURN server in " + + "order for calls to work reliably.", + { homeserverDomain: cli.getDomain() }, { code }, + )}

+

{_t( + "Alternatively, you can try to use the public server at " + + "turn.matrix.org, but this will not be as reliable, and " + + "it will share your IP address with that server. You can also manage " + + "this in Settings.", + null, { code }, + )}

+
, + button: _t('Try using turn.matrix.org'), + cancelButton: _t('OK'), + onFinished: (allow) => { + SettingsStore.setValue("fallbackICEServerAllowed", null, SettingLevel.DEVICE, allow); + cli.setFallbackICEServerAllowed(allow); + }, + }, null, true); +} + function _onAction(payload) { function placeCall(newCall) { _setCallListeners(newCall); diff --git a/src/MatrixClientPeg.js b/src/MatrixClientPeg.js index d2760bc82c..813f0ed87e 100644 --- a/src/MatrixClientPeg.js +++ b/src/MatrixClientPeg.js @@ -216,6 +216,7 @@ class MatrixClientPeg { deviceId: creds.deviceId, timelineSupport: true, forceTURN: !SettingsStore.getValue('webRtcAllowPeerToPeer', false), + fallbackICEServerAllowed: !!SettingsStore.getValue('fallbackICEServerAllowed'), verificationMethods: [verificationMethods.SAS], unstableClientRelationAggregation: true, }; diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js index eb85fe4e44..18ea5a82be 100644 --- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js +++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js @@ -115,6 +115,10 @@ export default class VoiceUserSettingsTab extends React.Component { MatrixClientPeg.get().setForceTURN(!p2p); }; + _changeFallbackICEServerAllowed = (allow) => { + MatrixClientPeg.get().setFallbackICEServerAllowed(allow); + }; + _renderDeviceOptions(devices, category) { return devices.map((d) => { return (); @@ -201,7 +205,16 @@ export default class VoiceUserSettingsTab extends React.Component { {microphoneDropdown} {webcamDropdown} - + + ); diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json index 0ca1ece48f..ce23180526 100644 --- a/src/i18n/strings/en_EN.json +++ b/src/i18n/strings/en_EN.json @@ -28,6 +28,11 @@ "Answer": "Answer", "Call Timeout": "Call Timeout", "The remote side failed to pick up": "The remote side failed to pick up", + "Call failed due to misconfigured server": "Call failed due to misconfigured server", + "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.": "Please ask the administrator of your homeserver (%(homeserverDomain)s) to configure a TURN server in order for calls to work reliably.", + "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.": "Alternatively, you can try to use the public server at turn.matrix.org, but this will not be as reliable, and it will share your IP address with that server. You can also manage this in Settings.", + "Try using turn.matrix.org": "Try using turn.matrix.org", + "OK": "OK", "Unable to capture screen": "Unable to capture screen", "Existing Call": "Existing Call", "You are already in a call.": "You are already in a call.", @@ -355,6 +360,7 @@ "Show recently visited rooms above the room list": "Show recently visited rooms above the room list", "Show hidden events in timeline": "Show hidden events in timeline", "Low bandwidth mode": "Low bandwidth mode", + "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)": "Allow fallback call assist server turn.matrix.org when your homeserver does not offer one (your IP address would be shared during a call)", "Collecting app version information": "Collecting app version information", "Collecting logs": "Collecting logs", "Uploading report": "Uploading report", @@ -378,7 +384,6 @@ "Decline": "Decline", "Accept": "Accept", "The other party cancelled the verification.": "The other party cancelled the verification.", - "OK": "OK", "Verified!": "Verified!", "You've successfully verified this user.": "You've successfully verified this user.", "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.": "Secure messages with this user are end-to-end encrypted and not able to be read by third parties.", diff --git a/src/settings/Settings.js b/src/settings/Settings.js index 55085963d1..b33ef3f8d7 100644 --- a/src/settings/Settings.js +++ b/src/settings/Settings.js @@ -372,4 +372,13 @@ export const SETTINGS = { default: false, controller: new LowBandwidthController(), }, + "fallbackICEServerAllowed": { + supportedLevels: LEVELS_DEVICE_ONLY_SETTINGS, + displayName: _td( + "Allow fallback call assist server turn.matrix.org when your homeserver " + + "does not offer one (your IP address would be shared during a call)", + ), + // This is a tri-state value, where `null` means "prompt the user". + default: null, + }, };