Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/nextcloud/spreed.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJoas Schilling <213943+nickvergessen@users.noreply.github.com>2020-09-24 18:18:00 +0300
committerGitHub <noreply@github.com>2020-09-24 18:18:00 +0300
commitaf402ccbc59a19a4ea79c28981e4d2b3c51e5991 (patch)
tree271d7c4d030e93e3b31185cea8bf223158c83949
parenta0df00217b316b24b7cfb14e8894933d64e39d03 (diff)
parentf3356644d016269e98105eabfae46840b63d5566 (diff)
Merge pull request #4224 from nextcloud/backport/4218/stable20
[stable20] Remember selected input devices
-rw-r--r--src/utils/webrtc/MediaDevicesManager.js68
-rw-r--r--src/utils/webrtc/simplewebrtc/localmedia.js84
2 files changed, 121 insertions, 31 deletions
diff --git a/src/utils/webrtc/MediaDevicesManager.js b/src/utils/webrtc/MediaDevicesManager.js
index 6d6dc0a68..fd4239887 100644
--- a/src/utils/webrtc/MediaDevicesManager.js
+++ b/src/utils/webrtc/MediaDevicesManager.js
@@ -19,6 +19,14 @@
*
*/
+import BrowserStorage from '../../services/BrowserStorage'
+
+/**
+ * Special string to set null device ids in local storage (as only strings are
+ * allowed).
+ */
+const LOCAL_STORAGE_NULL_DEVICE_ID = 'local-storage-null-device-id'
+
/**
* Wrapper for MediaDevices to simplify its use.
*
@@ -57,7 +65,9 @@
* modified.
*
* The selected devices will be automatically cleared if they are no longer
- * available. When no device of certain kind is selected and there are other
+ * available, and they will be restored once they are again available
+ * (immediately if events are enabled, or otherwise the next time that devices
+ * are got). When no device of certain kind is selected and there are other
* devices of that kind the selected device will fall back to the first one
* found, or to the one with the "default" id (if any). It is possible to
* explicitly disable devices of certain kind by setting xxxInputId to "null"
@@ -83,6 +93,15 @@ export default function MediaDevicesManager() {
this._tracks = []
this._updateDevicesBound = this._updateDevices.bind(this)
+
+ this._pendingEnumerateDevicesPromise = null
+
+ if (BrowserStorage.getItem('audioInputId') === LOCAL_STORAGE_NULL_DEVICE_ID) {
+ this.attributes.audioInputId = null
+ }
+ if (BrowserStorage.getItem('videoInputId') === LOCAL_STORAGE_NULL_DEVICE_ID) {
+ this.attributes.videoInputId = null
+ }
}
MediaDevicesManager.prototype = {
@@ -94,6 +113,24 @@ MediaDevicesManager.prototype = {
this.attributes[key] = value
this._trigger('change:' + key, [value])
+
+ this._storeDeviceId(key, value)
+ },
+
+ _storeDeviceId: function(key, value) {
+ if (key !== 'audioInputId' && key !== 'videoInputId') {
+ return
+ }
+
+ if (value === null) {
+ value = LOCAL_STORAGE_NULL_DEVICE_ID
+ }
+
+ if (value) {
+ BrowserStorage.setItem(key, value)
+ } else {
+ BrowserStorage.removeItem(key)
+ }
},
on: function(event, handler) {
@@ -171,7 +208,7 @@ MediaDevicesManager.prototype = {
},
_updateDevices: function() {
- navigator.mediaDevices.enumerateDevices().then(devices => {
+ this._pendingEnumerateDevicesPromise = navigator.mediaDevices.enumerateDevices().then(devices => {
const previousAudioInputId = this.attributes.audioInputId
const previousVideoInputId = this.attributes.videoInputId
@@ -197,8 +234,12 @@ MediaDevicesManager.prototype = {
if (previousVideoInputId !== this.attributes.videoInputId) {
this._trigger('change:videoInputId', [this.attributes.videoInputId])
}
+
+ this._pendingEnumerateDevicesPromise = null
}).catch(function(error) {
console.error('Could not update known media devices: ' + error.name + ': ' + error.message)
+
+ this._pendingEnumerateDevicesPromise = null
})
},
@@ -274,9 +315,13 @@ MediaDevicesManager.prototype = {
// Always refresh the known device with the latest values.
this._knownDevices[addedDevice.kind + '-' + addedDevice.deviceId] = addedDevice
- // Set first available device as fallback, and override any
- // fallback previously set if the default device is added.
+ // Restore previously selected device if it becomes available again.
+ // Additionally, set first available device as fallback, and override
+ // any fallback previously set if the default device is added.
if (addedDevice.kind === 'audioinput') {
+ if (BrowserStorage.getItem('audioInputId') === addedDevice.deviceId) {
+ this.attributes.audioInputId = addedDevice.deviceId
+ }
if (!this._fallbackAudioInputId || addedDevice.deviceId === 'default') {
this._fallbackAudioInputId = addedDevice.deviceId
}
@@ -284,6 +329,9 @@ MediaDevicesManager.prototype = {
this.attributes.audioInputId = this._fallbackAudioInputId
}
} else if (addedDevice.kind === 'videoinput') {
+ if (BrowserStorage.getItem('videoInputId') === addedDevice.deviceId) {
+ this.attributes.videoInputId = addedDevice.deviceId
+ }
if (!this._fallbackVideoInputId || addedDevice.deviceId === 'default') {
this._fallbackVideoInputId = addedDevice.deviceId
}
@@ -318,6 +366,18 @@ MediaDevicesManager.prototype = {
})
}
+ if (!this._pendingEnumerateDevicesPromise) {
+ return this._getUserMediaInternal(constraints)
+ }
+
+ return this._pendingEnumerateDevicesPromise.then(() => {
+ return this._getUserMediaInternal(constraints)
+ }).catch(() => {
+ return this._getUserMediaInternal(constraints)
+ })
+ },
+
+ _getUserMediaInternal: function(constraints) {
if (constraints.audio && !constraints.audio.deviceId) {
if (this.attributes.audioInputId) {
if (!(constraints.audio instanceof Object)) {
diff --git a/src/utils/webrtc/simplewebrtc/localmedia.js b/src/utils/webrtc/simplewebrtc/localmedia.js
index 2d3aab187..35c1563a9 100644
--- a/src/utils/webrtc/simplewebrtc/localmedia.js
+++ b/src/utils/webrtc/simplewebrtc/localmedia.js
@@ -138,6 +138,12 @@ LocalMedia.prototype.start = function(mediaConstraints, cb, context) {
this.emit('localStreamRequested', constraints, context)
+ if (!context) {
+ // Try to get the devices list before getting user media.
+ webrtcIndex.mediaDevicesManager.enableDeviceEvents()
+ webrtcIndex.mediaDevicesManager.disableDeviceEvents()
+ }
+
webrtcIndex.mediaDevicesManager.getUserMedia(constraints).then(function(stream) {
// Although the promise should be resolved only if all the constraints
// are met Edge resolves it if both audio and video are requested but
@@ -165,7 +171,7 @@ LocalMedia.prototype.start = function(mediaConstraints, cb, context) {
}
track.addEventListener('ended', function() {
- if (isAllTracksEnded(stream)) {
+ if (isAllTracksEnded(stream) && !self._pendingAudioInputIdChangedCount && !self._pendingVideoInputIdChangedCount) {
self._removeStream(stream)
}
})
@@ -204,6 +210,26 @@ LocalMedia.prototype._handleAudioInputIdChanged = function(mediaDevicesManager,
return
}
+ this._pendingAudioInputIdChangedCount = 1
+
+ const resetPendingAudioInputIdChangedCount = () => {
+ const audioInputIdChangedAgain = this._pendingAudioInputIdChangedCount > 1
+
+ this._pendingAudioInputIdChangedCount = 0
+
+ if (audioInputIdChangedAgain) {
+ this._handleAudioInputIdChanged(webrtcIndex.mediaDevicesManager.get('audioInputId'))
+ }
+
+ if (!this._pendingAudioInputIdChangedCount && !this._pendingVideoInputIdChangedCount) {
+ this.localStreams.forEach(stream => {
+ if (isAllTracksEnded(stream)) {
+ this._removeStream(stream)
+ }
+ })
+ }
+ }
+
const localStreamsChanged = []
const localTracksReplaced = []
@@ -244,23 +270,15 @@ LocalMedia.prototype._handleAudioInputIdChanged = function(mediaDevicesManager,
this.emit('localTrackReplaced', null, trackStreamPair.track, trackStreamPair.stream)
})
- return
- }
+ resetPendingAudioInputIdChangedCount()
- if (localTracksReplaced.length === 0) {
return
}
- this._pendingAudioInputIdChangedCount = 1
-
- const resetPendingAudioInputIdChangedCount = () => {
- const audioInputIdChangedAgain = this._pendingAudioInputIdChangedCount > 1
-
- this._pendingAudioInputIdChangedCount = 0
+ if (localTracksReplaced.length === 0) {
+ resetPendingAudioInputIdChangedCount()
- if (audioInputIdChangedAgain) {
- this._handleAudioInputIdChanged(webrtcIndex.mediaDevicesManager.get('audioInputId'))
- }
+ return
}
webrtcIndex.mediaDevicesManager.getUserMedia({ audio: true }).then(stream => {
@@ -303,7 +321,7 @@ LocalMedia.prototype._handleAudioInputIdChanged = function(mediaDevicesManager,
}
clonedTrack.addEventListener('ended', () => {
- if (isAllTracksEnded(stream)) {
+ if (isAllTracksEnded(stream) && !this._pendingAudioInputIdChangedCount && !this._pendingVideoInputIdChangedCount) {
this._removeStream(stream)
}
})
@@ -337,6 +355,26 @@ LocalMedia.prototype._handleVideoInputIdChanged = function(mediaDevicesManager,
return
}
+ this._pendingVideoInputIdChangedCount = 1
+
+ const resetPendingVideoInputIdChangedCount = () => {
+ const videoInputIdChangedAgain = this._pendingVideoInputIdChangedCount > 1
+
+ this._pendingVideoInputIdChangedCount = 0
+
+ if (videoInputIdChangedAgain) {
+ this._handleVideoInputIdChanged(webrtcIndex.mediaDevicesManager.get('videoInputId'))
+ }
+
+ if (!this._pendingAudioInputIdChangedCount && !this._pendingVideoInputIdChangedCount) {
+ this.localStreams.forEach(stream => {
+ if (isAllTracksEnded(stream)) {
+ this._removeStream(stream)
+ }
+ })
+ }
+ }
+
const localStreamsChanged = []
const localTracksReplaced = []
@@ -377,23 +415,15 @@ LocalMedia.prototype._handleVideoInputIdChanged = function(mediaDevicesManager,
this.emit('localTrackReplaced', null, trackStreamPair.track, trackStreamPair.stream)
})
- return
- }
+ resetPendingVideoInputIdChangedCount()
- if (localTracksReplaced.length === 0) {
return
}
- this._pendingVideoInputIdChangedCount = 1
-
- const resetPendingVideoInputIdChangedCount = () => {
- const videoInputIdChangedAgain = this._pendingVideoInputIdChangedCount > 1
-
- this._pendingVideoInputIdChangedCount = 0
+ if (localTracksReplaced.length === 0) {
+ resetPendingVideoInputIdChangedCount()
- if (videoInputIdChangedAgain) {
- this._handleVideoInputIdChanged(webrtcIndex.mediaDevicesManager.get('videoInputId'))
- }
+ return
}
webrtcIndex.mediaDevicesManager.getUserMedia({ video: true }).then(stream => {
@@ -423,7 +453,7 @@ LocalMedia.prototype._handleVideoInputIdChanged = function(mediaDevicesManager,
}
clonedTrack.addEventListener('ended', () => {
- if (isAllTracksEnded(stream)) {
+ if (isAllTracksEnded(stream) && !this._pendingAudioInputIdChangedCount && !this._pendingVideoInputIdChangedCount) {
this._removeStream(stream)
}
})