|
@@ -12,6 +12,8 @@ import Recorder from './modules/recorder/Recorder';
|
12
|
12
|
import CQEvents from './service/connectionquality/CQEvents';
|
13
|
13
|
import UIEvents from './service/UI/UIEvents';
|
14
|
14
|
|
|
15
|
+import mediaDeviceHelper from './modules/devices/mediaDeviceHelper';
|
|
16
|
+
|
15
|
17
|
const ConnectionEvents = JitsiMeetJS.events.connection;
|
16
|
18
|
const ConnectionErrors = JitsiMeetJS.errors.connection;
|
17
|
19
|
|
|
@@ -22,7 +24,6 @@ const TrackEvents = JitsiMeetJS.events.track;
|
22
|
24
|
const TrackErrors = JitsiMeetJS.errors.track;
|
23
|
25
|
|
24
|
26
|
let room, connection, localAudio, localVideo, roomLocker;
|
25
|
|
-let currentAudioInputDevices, currentVideoInputDevices;
|
26
|
27
|
|
27
|
28
|
import {VIDEO_CONTAINER_TYPE} from "./modules/UI/videolayout/LargeVideo";
|
28
|
29
|
|
|
@@ -211,17 +212,6 @@ function createLocalTracks (devices, cameraDeviceId, micDeviceId) {
|
211
|
212
|
});
|
212
|
213
|
}
|
213
|
214
|
|
214
|
|
-/**
|
215
|
|
- * Stores lists of current 'audioinput' and 'videoinput' devices
|
216
|
|
- * @param {MediaDeviceInfo[]} devices
|
217
|
|
- */
|
218
|
|
-function setCurrentMediaDevices(devices) {
|
219
|
|
- currentAudioInputDevices = devices.filter(
|
220
|
|
- d => d.kind === 'audioinput');
|
221
|
|
- currentVideoInputDevices = devices.filter(
|
222
|
|
- d => d.kind === 'videoinput');
|
223
|
|
-}
|
224
|
|
-
|
225
|
215
|
/**
|
226
|
216
|
* Changes the email for the local user
|
227
|
217
|
* @param email {string} the new email
|
|
@@ -489,44 +479,8 @@ export default {
|
489
|
479
|
APP.UI.disableCameraButton();
|
490
|
480
|
}
|
491
|
481
|
|
492
|
|
- // update list of available devices
|
493
|
|
- if (JitsiMeetJS.mediaDevices.isDeviceListAvailable() &&
|
494
|
|
- JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) {
|
495
|
|
- JitsiMeetJS.mediaDevices.enumerateDevices(function(devices) {
|
496
|
|
- // Ugly way to synchronize real device IDs with local
|
497
|
|
- // storage and settings menu. This is a workaround until
|
498
|
|
- // getConstraints() method will be implemented in browsers.
|
499
|
|
- if (localAudio) {
|
500
|
|
- localAudio._setRealDeviceIdFromDeviceList(devices);
|
501
|
|
- APP.settings.setMicDeviceId(localAudio.getDeviceId());
|
502
|
|
- }
|
|
482
|
+ this._initDeviceList();
|
503
|
483
|
|
504
|
|
- if (localVideo) {
|
505
|
|
- localVideo._setRealDeviceIdFromDeviceList(devices);
|
506
|
|
- APP.settings.setCameraDeviceId(
|
507
|
|
- localVideo.getDeviceId());
|
508
|
|
- }
|
509
|
|
-
|
510
|
|
- setCurrentMediaDevices(devices);
|
511
|
|
-
|
512
|
|
- APP.UI.onAvailableDevicesChanged(devices);
|
513
|
|
- });
|
514
|
|
-
|
515
|
|
- JitsiMeetJS.mediaDevices.addEventListener(
|
516
|
|
- JitsiMeetJS.events.mediaDevices.DEVICE_LIST_CHANGED,
|
517
|
|
- (devices) => {
|
518
|
|
- // Just defer callback until other event callbacks are
|
519
|
|
- // processed.
|
520
|
|
- window.setTimeout(() => {
|
521
|
|
- checkLocalDevicesAfterDeviceListChanged(devices)
|
522
|
|
- .then(() => {
|
523
|
|
- setCurrentMediaDevices(devices);
|
524
|
|
-
|
525
|
|
- APP.UI.onAvailableDevicesChanged(devices);
|
526
|
|
- });
|
527
|
|
- }, 0);
|
528
|
|
- });
|
529
|
|
- }
|
530
|
484
|
if (config.iAmRecorder)
|
531
|
485
|
this.recorder = new Recorder();
|
532
|
486
|
|
|
@@ -535,220 +489,6 @@ export default {
|
535
|
489
|
return new Promise((resolve, reject) => {
|
536
|
490
|
(new ConferenceConnector(resolve, reject)).connect();
|
537
|
491
|
});
|
538
|
|
-
|
539
|
|
- function checkAudioOutputDeviceAfterDeviceListChanged(newDevices) {
|
540
|
|
- if (!JitsiMeetJS.mediaDevices
|
541
|
|
- .isDeviceChangeAvailable('output')) {
|
542
|
|
- return;
|
543
|
|
- }
|
544
|
|
-
|
545
|
|
- var selectedAudioOutputDeviceId =
|
546
|
|
- APP.settings.getAudioOutputDeviceId(),
|
547
|
|
- availableAudioOutputDevices = newDevices.filter(d => {
|
548
|
|
- return d.kind === 'audiooutput';
|
549
|
|
- });
|
550
|
|
-
|
551
|
|
- if (selectedAudioOutputDeviceId !== 'default' &&
|
552
|
|
- !availableAudioOutputDevices.find(d =>
|
553
|
|
- d.deviceId === selectedAudioOutputDeviceId)) {
|
554
|
|
- APP.settings.setAudioOutputDeviceId('default');
|
555
|
|
- }
|
556
|
|
- }
|
557
|
|
-
|
558
|
|
- function checkLocalDevicesAfterDeviceListChanged(newDevices) {
|
559
|
|
- // Event handler can be fire before direct enumerateDevices()
|
560
|
|
- // call, so handle this situation here.
|
561
|
|
- if (!currentAudioInputDevices && !currentVideoInputDevices) {
|
562
|
|
- setCurrentMediaDevices(newDevices);
|
563
|
|
- }
|
564
|
|
-
|
565
|
|
- checkAudioOutputDeviceAfterDeviceListChanged(newDevices);
|
566
|
|
-
|
567
|
|
- let availableAudioInputDevices = newDevices.filter(
|
568
|
|
- d => d.kind === 'audioinput'),
|
569
|
|
- availableVideoInputDevices = newDevices.filter(
|
570
|
|
- d => d.kind === 'videoinput'),
|
571
|
|
- selectedAudioInputDeviceId = APP.settings.getMicDeviceId(),
|
572
|
|
- selectedVideoInputDeviceId =
|
573
|
|
- APP.settings.getCameraDeviceId(),
|
574
|
|
- selectedAudioInputDevice = availableAudioInputDevices.find(
|
575
|
|
- d => d.deviceId === selectedAudioInputDeviceId),
|
576
|
|
- selectedVideoInputDevice = availableVideoInputDevices.find(
|
577
|
|
- d => d.deviceId === selectedVideoInputDeviceId),
|
578
|
|
- tracksToCreate = [],
|
579
|
|
- micIdToUse = null,
|
580
|
|
- cameraIdToUse = null;
|
581
|
|
-
|
582
|
|
- // Here we handle case when no device was initially plugged, but
|
583
|
|
- // then it's connected OR new device was connected when previous
|
584
|
|
- // track has ended.
|
585
|
|
- if (!localAudio || localAudio.disposed || localAudio.isEnded()){
|
586
|
|
- if (availableAudioInputDevices.length
|
587
|
|
- && availableAudioInputDevices[0].label !== '') {
|
588
|
|
- tracksToCreate.push('audio');
|
589
|
|
- micIdToUse = availableAudioInputDevices[0].deviceId;
|
590
|
|
- } else {
|
591
|
|
- APP.UI.disableMicrophoneButton();
|
592
|
|
- }
|
593
|
|
- }
|
594
|
|
-
|
595
|
|
- if ((!localVideo || localVideo.disposed || localVideo.isEnded())
|
596
|
|
- && !self.isSharingScreen){
|
597
|
|
- if (availableVideoInputDevices.length
|
598
|
|
- && availableVideoInputDevices[0].label !== '') {
|
599
|
|
- tracksToCreate.push('video');
|
600
|
|
- cameraIdToUse = availableVideoInputDevices[0].deviceId;
|
601
|
|
- } else {
|
602
|
|
- APP.UI.disableCameraButton();
|
603
|
|
- }
|
604
|
|
- }
|
605
|
|
-
|
606
|
|
- if (localAudio && !localAudio.disposed && !localAudio.isEnded()
|
607
|
|
- && selectedAudioInputDevice
|
608
|
|
- && selectedAudioInputDeviceId !== localAudio.getDeviceId()
|
609
|
|
- && tracksToCreate.indexOf('audio') === -1) {
|
610
|
|
- tracksToCreate.push('audio');
|
611
|
|
- micIdToUse = selectedAudioInputDeviceId;
|
612
|
|
- }
|
613
|
|
-
|
614
|
|
- if (localVideo && !localVideo.disposed && !localVideo.isEnded()
|
615
|
|
- && selectedVideoInputDevice
|
616
|
|
- && selectedVideoInputDeviceId !== localVideo.getDeviceId()
|
617
|
|
- && tracksToCreate.indexOf('video') === -1
|
618
|
|
- && !self.isSharingScreen) {
|
619
|
|
- tracksToCreate.push('video');
|
620
|
|
- cameraIdToUse = selectedVideoInputDeviceId;
|
621
|
|
- }
|
622
|
|
-
|
623
|
|
- if (tracksToCreate.length) {
|
624
|
|
- return createNewTracks(
|
625
|
|
- tracksToCreate, cameraIdToUse, micIdToUse);
|
626
|
|
- } else {
|
627
|
|
- return Promise.resolve();
|
628
|
|
- }
|
629
|
|
-
|
630
|
|
- function createNewTracks(type, cameraDeviceId, micDeviceId) {
|
631
|
|
- let audioTrackCreationError;
|
632
|
|
- let videoTrackCreationError;
|
633
|
|
- let audioRequested = type.indexOf('audio') !== -1;
|
634
|
|
- let videoRequested = type.indexOf('video') !== -1;
|
635
|
|
- let promise;
|
636
|
|
-
|
637
|
|
- if (audioRequested && micDeviceId !== null) {
|
638
|
|
- if (videoRequested && cameraDeviceId !== null) {
|
639
|
|
- promise = createLocalTracks(
|
640
|
|
- type, cameraDeviceId, micDeviceId)
|
641
|
|
- .catch(() => {
|
642
|
|
- return Promise.all([
|
643
|
|
- createAudioTrack(false),
|
644
|
|
- createVideoTrack(false)]);
|
645
|
|
- })
|
646
|
|
- .then((audioTracks, videoTracks) => {
|
647
|
|
- if (audioTrackCreationError) {
|
648
|
|
- if (videoTrackCreationError) {
|
649
|
|
- APP.UI.showDeviceErrorDialog(
|
650
|
|
- audioTrackCreationError,
|
651
|
|
- videoTrackCreationError);
|
652
|
|
- } else {
|
653
|
|
- APP.UI.showDeviceErrorDialog(
|
654
|
|
- audioTrackCreationError,
|
655
|
|
- null);
|
656
|
|
- }
|
657
|
|
- } else if (videoTrackCreationError) {
|
658
|
|
- APP.UI.showDeviceErrorDialog(
|
659
|
|
- null,
|
660
|
|
- videoTrackCreationError);
|
661
|
|
- }
|
662
|
|
-
|
663
|
|
- return (audioTracks || [])
|
664
|
|
- .concat(videoTracks || []);
|
665
|
|
- });
|
666
|
|
- } else {
|
667
|
|
- promise = createAudioTrack();
|
668
|
|
- }
|
669
|
|
- } else if (videoRequested && cameraDeviceId !== null) {
|
670
|
|
- promise = createVideoTrack();
|
671
|
|
- } else {
|
672
|
|
- promise = Promise.resolve([]);
|
673
|
|
- }
|
674
|
|
-
|
675
|
|
- return promise
|
676
|
|
- .then(onTracksCreated);
|
677
|
|
-
|
678
|
|
- function createAudioTrack(showError) {
|
679
|
|
- return createLocalTracks(['audio'], null, micDeviceId)
|
680
|
|
- .catch(err => {
|
681
|
|
- audioTrackCreationError = err;
|
682
|
|
-
|
683
|
|
- if (showError) {
|
684
|
|
- APP.UI.showDeviceErrorDialog(err, null);
|
685
|
|
- }
|
686
|
|
-
|
687
|
|
- return [];
|
688
|
|
- });
|
689
|
|
- }
|
690
|
|
-
|
691
|
|
- function createVideoTrack(showError) {
|
692
|
|
- return createLocalTracks(
|
693
|
|
- ['video'], cameraDeviceId, null)
|
694
|
|
- .catch(err => {
|
695
|
|
- videoTrackCreationError = err;
|
696
|
|
-
|
697
|
|
- if (showError) {
|
698
|
|
- APP.UI.showDeviceErrorDialog(null, err);
|
699
|
|
- }
|
700
|
|
-
|
701
|
|
- return [];
|
702
|
|
- });
|
703
|
|
- }
|
704
|
|
- }
|
705
|
|
-
|
706
|
|
- function onTracksCreated(tracks) {
|
707
|
|
- return Promise.all((tracks || []).map(track => {
|
708
|
|
- if (track.isAudioTrack()) {
|
709
|
|
- let audioWasMuted = self.audioMuted;
|
710
|
|
-
|
711
|
|
- return self.useAudioStream(track).then(() => {
|
712
|
|
- console.log('switched local audio');
|
713
|
|
-
|
714
|
|
- // If we plugged-in new device (and switched to
|
715
|
|
- // it), but video was muted before, or we
|
716
|
|
- // unplugged current device and selected new
|
717
|
|
- // one, then mute new video track.
|
718
|
|
- if (audioWasMuted ||
|
719
|
|
- currentAudioInputDevices.length >
|
720
|
|
- availableAudioInputDevices.length) {
|
721
|
|
- muteLocalAudio(true);
|
722
|
|
- }
|
723
|
|
- });
|
724
|
|
- } else if (track.isVideoTrack()) {
|
725
|
|
- let videoWasMuted = self.videoMuted;
|
726
|
|
-
|
727
|
|
- return self.useVideoStream(track).then(() => {
|
728
|
|
- console.log('switched local video');
|
729
|
|
-
|
730
|
|
- // TODO: maybe make video large if we
|
731
|
|
- // are not in conference yet
|
732
|
|
-
|
733
|
|
- // If we plugged-in new device (and switched to
|
734
|
|
- // it), but video was muted before, or we
|
735
|
|
- // unplugged current device and selected new
|
736
|
|
- // one, then mute new video track.
|
737
|
|
- if (videoWasMuted ||
|
738
|
|
- (currentVideoInputDevices.length >
|
739
|
|
- availableVideoInputDevices.length)) {
|
740
|
|
- muteLocalVideo(true);
|
741
|
|
- }
|
742
|
|
- });
|
743
|
|
- } else {
|
744
|
|
- console.error("Ignored not an audio nor a "
|
745
|
|
- + "video track: ", track);
|
746
|
|
-
|
747
|
|
- return Promise.resolve();
|
748
|
|
- }
|
749
|
|
- }));
|
750
|
|
- }
|
751
|
|
- }
|
752
|
492
|
});
|
753
|
493
|
},
|
754
|
494
|
/**
|
|
@@ -956,16 +696,7 @@ export default {
|
956
|
696
|
room = connection.initJitsiConference(APP.conference.roomName,
|
957
|
697
|
this._getConferenceOptions());
|
958
|
698
|
this.localId = room.myUserId();
|
959
|
|
- localTracks.forEach((track) => {
|
960
|
|
- if (track.isAudioTrack()) {
|
961
|
|
- this.useAudioStream(track);
|
962
|
|
- } else if (track.isVideoTrack()) {
|
963
|
|
- this.useVideoStream(track);
|
964
|
|
- } else {
|
965
|
|
- console.error(
|
966
|
|
- "Ignored not an audio nor a video track: ", track);
|
967
|
|
- }
|
968
|
|
- });
|
|
699
|
+ this._setLocalAudioVideoStreams(localTracks);
|
969
|
700
|
roomLocker = createRoomLocker(room);
|
970
|
701
|
this._room = room; // FIXME do not use this
|
971
|
702
|
|
|
@@ -986,6 +717,26 @@ export default {
|
986
|
717
|
this._setupListeners();
|
987
|
718
|
},
|
988
|
719
|
|
|
720
|
+ /**
|
|
721
|
+ * Sets local video and audio streams.
|
|
722
|
+ * @param {JitsiLocalTrack[]} tracks=[]
|
|
723
|
+ * @returns {Promise[]}
|
|
724
|
+ * @private
|
|
725
|
+ */
|
|
726
|
+ _setLocalAudioVideoStreams(tracks = []) {
|
|
727
|
+ return tracks.map(track => {
|
|
728
|
+ if (track.isAudioTrack()) {
|
|
729
|
+ return this.useAudioStream(track);
|
|
730
|
+ } else if (track.isVideoTrack()) {
|
|
731
|
+ return this.useVideoStream(track);
|
|
732
|
+ } else {
|
|
733
|
+ console.error(
|
|
734
|
+ "Ignored not an audio nor a video track: ", track);
|
|
735
|
+ return Promise.resolve();
|
|
736
|
+ }
|
|
737
|
+ });
|
|
738
|
+ },
|
|
739
|
+
|
989
|
740
|
_getConferenceOptions() {
|
990
|
741
|
let options = config;
|
991
|
742
|
if(config.enableRecording && !config.recordingType) {
|
|
@@ -1480,7 +1231,7 @@ export default {
|
1480
|
1231
|
APP.UI.addListener(
|
1481
|
1232
|
UIEvents.VIDEO_DEVICE_CHANGED,
|
1482
|
1233
|
(cameraDeviceId) => {
|
1483
|
|
- createLocalTracks(['video'])
|
|
1234
|
+ createLocalTracks(['video'], cameraDeviceId, null)
|
1484
|
1235
|
.then(([stream]) => {
|
1485
|
1236
|
this.useVideoStream(stream);
|
1486
|
1237
|
console.log('switched local video device');
|
|
@@ -1496,7 +1247,7 @@ export default {
|
1496
|
1247
|
APP.UI.addListener(
|
1497
|
1248
|
UIEvents.AUDIO_DEVICE_CHANGED,
|
1498
|
1249
|
(micDeviceId) => {
|
1499
|
|
- createLocalTracks(['audio'])
|
|
1250
|
+ createLocalTracks(['audio'], null, micDeviceId)
|
1500
|
1251
|
.then(([stream]) => {
|
1501
|
1252
|
this.useAudioStream(stream);
|
1502
|
1253
|
console.log('switched local audio device');
|
|
@@ -1574,11 +1325,112 @@ export default {
|
1574
|
1325
|
});
|
1575
|
1326
|
},
|
1576
|
1327
|
/**
|
1577
|
|
- * Adss any room listener.
|
1578
|
|
- * @param eventName one of the ConferenceEvents
|
1579
|
|
- * @param callBack the function to be called when the event occurs
|
1580
|
|
- */
|
1581
|
|
- addConferenceListener(eventName, callBack) {
|
|
1328
|
+ * Adds any room listener.
|
|
1329
|
+ * @param eventName one of the ConferenceEvents
|
|
1330
|
+ * @param callBack the function to be called when the event occurs
|
|
1331
|
+ */
|
|
1332
|
+ addConferenceListener(eventName, callBack) {
|
1582
|
1333
|
room.on(eventName, callBack);
|
|
1334
|
+ },
|
|
1335
|
+ /**
|
|
1336
|
+ * Inits list of current devices and event listener for device change.
|
|
1337
|
+ * @private
|
|
1338
|
+ */
|
|
1339
|
+ _initDeviceList() {
|
|
1340
|
+ if (JitsiMeetJS.mediaDevices.isDeviceListAvailable() &&
|
|
1341
|
+ JitsiMeetJS.mediaDevices.isDeviceChangeAvailable()) {
|
|
1342
|
+ JitsiMeetJS.mediaDevices.enumerateDevices(devices => {
|
|
1343
|
+ // Ugly way to synchronize real device IDs with local
|
|
1344
|
+ // storage and settings menu. This is a workaround until
|
|
1345
|
+ // getConstraints() method will be implemented in browsers.
|
|
1346
|
+ if (localAudio) {
|
|
1347
|
+ localAudio._setRealDeviceIdFromDeviceList(devices);
|
|
1348
|
+ APP.settings.setMicDeviceId(localAudio.getDeviceId());
|
|
1349
|
+ }
|
|
1350
|
+
|
|
1351
|
+ if (localVideo) {
|
|
1352
|
+ localVideo._setRealDeviceIdFromDeviceList(devices);
|
|
1353
|
+ APP.settings.setCameraDeviceId(localVideo.getDeviceId());
|
|
1354
|
+ }
|
|
1355
|
+
|
|
1356
|
+ mediaDeviceHelper.setCurrentMediaDevices(devices);
|
|
1357
|
+
|
|
1358
|
+ APP.UI.onAvailableDevicesChanged(devices);
|
|
1359
|
+ });
|
|
1360
|
+
|
|
1361
|
+ JitsiMeetJS.mediaDevices.addEventListener(
|
|
1362
|
+ JitsiMeetJS.events.mediaDevices.DEVICE_LIST_CHANGED,
|
|
1363
|
+ (devices) =>
|
|
1364
|
+ window.setTimeout(
|
|
1365
|
+ () => this._onDeviceListChanged(devices), 0));
|
|
1366
|
+ }
|
|
1367
|
+ },
|
|
1368
|
+ /**
|
|
1369
|
+ * Event listener for JitsiMediaDevicesEvents.DEVICE_LIST_CHANGED to
|
|
1370
|
+ * handle change of available media devices.
|
|
1371
|
+ * @private
|
|
1372
|
+ * @param {MediaDeviceInfo[]} devices
|
|
1373
|
+ * @returns {Promise}
|
|
1374
|
+ */
|
|
1375
|
+ _onDeviceListChanged(devices) {
|
|
1376
|
+ let currentDevices = mediaDeviceHelper.getCurrentMediaDevices();
|
|
1377
|
+
|
|
1378
|
+ // Event handler can be fired before direct
|
|
1379
|
+ // enumerateDevices() call, so handle this situation here.
|
|
1380
|
+ if (!currentDevices.audioinput &&
|
|
1381
|
+ !currentDevices.videoinput &&
|
|
1382
|
+ !currentDevices.audiooutput) {
|
|
1383
|
+ mediaDeviceHelper.setCurrentMediaDevices(devices);
|
|
1384
|
+ currentDevices = mediaDeviceHelper.getCurrentMediaDevices();
|
|
1385
|
+ }
|
|
1386
|
+
|
|
1387
|
+ let newDevices =
|
|
1388
|
+ mediaDeviceHelper.getNewMediaDevicesAfterDeviceListChanged(
|
|
1389
|
+ devices, this.isSharingScreen, localVideo, localAudio);
|
|
1390
|
+ let promises = [];
|
|
1391
|
+ let audioWasMuted = this.audioMuted;
|
|
1392
|
+ let videoWasMuted = this.videoMuted;
|
|
1393
|
+ let availableAudioInputDevices =
|
|
1394
|
+ mediaDeviceHelper.getDevicesFromListByKind(devices, 'audioinput');
|
|
1395
|
+ let availableVideoInputDevices =
|
|
1396
|
+ mediaDeviceHelper.getDevicesFromListByKind(devices, 'videoinput');
|
|
1397
|
+
|
|
1398
|
+ if (typeof newDevices.audiooutput !== 'undefined') {
|
|
1399
|
+ // Just ignore any errors in catch block.
|
|
1400
|
+ promises.push(APP.settings
|
|
1401
|
+ .setAudioOutputDeviceId(newDevices.audiooutput)
|
|
1402
|
+ .catch());
|
|
1403
|
+ }
|
|
1404
|
+
|
|
1405
|
+ promises.push(
|
|
1406
|
+ mediaDeviceHelper.createLocalTracksAfterDeviceListChanged(
|
|
1407
|
+ createLocalTracks,
|
|
1408
|
+ newDevices.videoinput,
|
|
1409
|
+ newDevices.audioinput)
|
|
1410
|
+ .then(tracks =>
|
|
1411
|
+ Promise.all(this._setLocalAudioVideoStreams(tracks)))
|
|
1412
|
+ .then(() => {
|
|
1413
|
+ // If audio was muted before, or we unplugged current device
|
|
1414
|
+ // and selected new one, then mute new audio track.
|
|
1415
|
+ if (audioWasMuted ||
|
|
1416
|
+ currentDevices.audioinput.length >
|
|
1417
|
+ availableAudioInputDevices.length) {
|
|
1418
|
+ muteLocalAudio(true);
|
|
1419
|
+ }
|
|
1420
|
+
|
|
1421
|
+ // If video was muted before, or we unplugged current device
|
|
1422
|
+ // and selected new one, then mute new video track.
|
|
1423
|
+ if (videoWasMuted ||
|
|
1424
|
+ currentDevices.videoinput.length >
|
|
1425
|
+ availableVideoInputDevices.length) {
|
|
1426
|
+ muteLocalVideo(true);
|
|
1427
|
+ }
|
|
1428
|
+ }));
|
|
1429
|
+
|
|
1430
|
+ return Promise.all(promises)
|
|
1431
|
+ .then(() => {
|
|
1432
|
+ mediaDeviceHelper.setCurrentMediaDevices(devices);
|
|
1433
|
+ APP.UI.onAvailableDevicesChanged(devices);
|
|
1434
|
+ });
|
1583
|
1435
|
}
|
1584
|
|
-};
|
|
1436
|
+};
|