diff --git a/src/CallMediaHandler.js b/src/CallMediaHandler.js
index 55b8764a9e..a0364f798a 100644
--- a/src/CallMediaHandler.js
+++ b/src/CallMediaHandler.js
@@ -18,6 +18,11 @@ import * as Matrix from 'matrix-js-sdk';
import SettingsStore, {SettingLevel} from "./settings/SettingsStore";
export default {
+ hasAnyLabeledDevices: async function() {
+ const devices = await navigator.mediaDevices.enumerateDevices();
+ return devices.some(d => !!d.label);
+ },
+
getDevices: function() {
// Only needed for Electron atm, though should work in modern browsers
// once permission has been granted to the webapp
diff --git a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
index 31a11b13ea..eb85fe4e44 100644
--- a/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
+++ b/src/components/views/settings/tabs/user/VoiceUserSettingsTab.js
@@ -29,48 +29,64 @@ export default class VoiceUserSettingsTab extends React.Component {
super();
this.state = {
- mediaDevices: null,
+ mediaDevices: false,
activeAudioOutput: null,
activeAudioInput: null,
activeVideoInput: null,
};
}
- componentWillMount(): void {
- this._refreshMediaDevices();
+ async componentDidMount() {
+ const canSeeDeviceLabels = await CallMediaHandler.hasAnyLabeledDevices();
+ if (canSeeDeviceLabels) {
+ this._refreshMediaDevices();
+ }
}
_refreshMediaDevices = async (stream) => {
- if (stream) {
- // kill stream so that we don't leave it lingering around with webcam enabled etc
- // as here we called gUM to ask user for permission to their device names only
- stream.getTracks().forEach((track) => track.stop());
- }
-
this.setState({
mediaDevices: await CallMediaHandler.getDevices(),
activeAudioOutput: CallMediaHandler.getAudioOutput(),
activeAudioInput: CallMediaHandler.getAudioInput(),
activeVideoInput: CallMediaHandler.getVideoInput(),
});
+ if (stream) {
+ // kill stream (after we've enumerated the devices, otherwise we'd get empty labels again)
+ // so that we don't leave it lingering around with webcam enabled etc
+ // as here we called gUM to ask user for permission to their device names only
+ stream.getTracks().forEach((track) => track.stop());
+ }
};
- _requestMediaPermissions = () => {
- 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.createTrackedDialog('No media permissions', '', ErrorDialog, {
- title: _t('No media permissions'),
- description: _t('You may need to manually permit Riot to access your microphone/webcam'),
- });
- },
- ]);
+ _requestMediaPermissions = async () => {
+ let constraints;
+ let stream;
+ let error;
+ try {
+ constraints = {video: true, audio: true};
+ stream = await navigator.mediaDevices.getUserMedia(constraints);
+ } catch (err) {
+ // user likely doesn't have a webcam,
+ // we should still allow to select a microphone
+ if (err.name === "NotFoundError") {
+ constraints = { audio: true };
+ try {
+ stream = await navigator.mediaDevices.getUserMedia(constraints);
+ } catch (err) {
+ error = err;
+ }
+ } else {
+ error = err;
+ }
+ }
+ if (error) {
+ const ErrorDialog = sdk.getComponent('dialogs.ErrorDialog');
+ Modal.createTrackedDialog('No media permissions', '', ErrorDialog, {
+ title: _t('No media permissions'),
+ description: _t('You may need to manually permit Riot to access your microphone/webcam'),
+ });
+ } else {
+ this._refreshMediaDevices(stream);
}
};
@@ -101,15 +117,7 @@ export default class VoiceUserSettingsTab extends React.Component {
_renderDeviceOptions(devices, category) {
return devices.map((d) => {
- let label = d.label;
- if (!label) {
- switch (d.kind) {
- case "audioinput": label = _t("Unnamed microphone"); break;
- case "audiooutput": label = _t("Unnamed audio output"); break;
- case "videoinput": label = _t("Unnamed camera"); break;
- }
- }
- return ();
+ return ();
});
}
diff --git a/src/i18n/strings/en_EN.json b/src/i18n/strings/en_EN.json
index de6a06e9e4..78c5baed34 100644
--- a/src/i18n/strings/en_EN.json
+++ b/src/i18n/strings/en_EN.json
@@ -615,9 +615,6 @@
"Learn more about how we use analytics.": "Learn more about how we use analytics.",
"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",
- "Unnamed microphone": "Unnamed microphone",
- "Unnamed audio output": "Unnamed audio output",
- "Unnamed camera": "Unnamed camera",
"Missing media permissions, click the button below to request.": "Missing media permissions, click the button below to request.",
"Request media permissions": "Request media permissions",
"No Audio Outputs detected": "No Audio Outputs detected",