|
@@ -120,6 +120,7 @@ import {
|
120
|
120
|
import { mediaPermissionPromptVisibilityChanged } from './react/features/overlay';
|
121
|
121
|
import { suspendDetected } from './react/features/power-monitor';
|
122
|
122
|
import { setSharedVideoStatus } from './react/features/shared-video';
|
|
123
|
+import { AudioMixerEffect } from './react/features/stream-effects/audio-mixer/AudioMixerEffect';
|
123
|
124
|
import { createPresenterEffect } from './react/features/stream-effects/presenter';
|
124
|
125
|
import { endpointMessageReceived } from './react/features/subtitles';
|
125
|
126
|
import { createRnnoiseProcessorPromise } from './react/features/rnnoise';
|
|
@@ -659,10 +660,10 @@ export default {
|
659
|
660
|
startAudioOnly: config.startAudioOnly,
|
660
|
661
|
startScreenSharing: config.startScreenSharing,
|
661
|
662
|
startWithAudioMuted: config.startWithAudioMuted
|
662
|
|
- || config.startSilent
|
663
|
|
- || isUserInteractionRequiredForUnmute(APP.store.getState()),
|
|
663
|
+ || config.startSilent
|
|
664
|
+ || isUserInteractionRequiredForUnmute(APP.store.getState()),
|
664
|
665
|
startWithVideoMuted: config.startWithVideoMuted
|
665
|
|
- || isUserInteractionRequiredForUnmute(APP.store.getState())
|
|
666
|
+ || isUserInteractionRequiredForUnmute(APP.store.getState())
|
666
|
667
|
}))
|
667
|
668
|
.then(([ tracks, con ]) => {
|
668
|
669
|
tracks.forEach(track => {
|
|
@@ -1417,7 +1418,7 @@ export default {
|
1417
|
1418
|
* in case it fails.
|
1418
|
1419
|
* @private
|
1419
|
1420
|
*/
|
1420
|
|
- _turnScreenSharingOff(didHaveVideo) {
|
|
1421
|
+ async _turnScreenSharingOff(didHaveVideo) {
|
1421
|
1422
|
this._untoggleScreenSharing = null;
|
1422
|
1423
|
this.videoSwitchInProgress = true;
|
1423
|
1424
|
const { receiver } = APP.remoteControl;
|
|
@@ -1446,6 +1447,20 @@ export default {
|
1446
|
1447
|
}
|
1447
|
1448
|
});
|
1448
|
1449
|
|
|
1450
|
+ // If system audio was also shared stop the AudioMixerEffect and dispose of the desktop audio track.
|
|
1451
|
+ if (this._mixerEffect) {
|
|
1452
|
+ await this.localAudio.setEffect(undefined);
|
|
1453
|
+ await this._desktopAudioStream.dispose();
|
|
1454
|
+ this._mixerEffect = undefined;
|
|
1455
|
+ this._desktopAudioStream = undefined;
|
|
1456
|
+
|
|
1457
|
+ // In case there was no local audio when screen sharing was started the fact that we set the audio stream to
|
|
1458
|
+ // null will take care of the desktop audio stream cleanup.
|
|
1459
|
+ } else if (this._desktopAudioStream) {
|
|
1460
|
+ await this.useAudioStream(null);
|
|
1461
|
+ this._desktopAudioStream = undefined;
|
|
1462
|
+ }
|
|
1463
|
+
|
1449
|
1464
|
if (didHaveVideo) {
|
1450
|
1465
|
promise = promise.then(() => createLocalTracksF({ devices: [ 'video' ] }))
|
1451
|
1466
|
.then(([ stream ]) => this.useVideoStream(stream))
|
|
@@ -1585,26 +1600,31 @@ export default {
|
1585
|
1600
|
}
|
1586
|
1601
|
});
|
1587
|
1602
|
|
1588
|
|
- return getDesktopStreamPromise.then(([ desktopStream ]) => {
|
|
1603
|
+ return getDesktopStreamPromise.then(desktopStreams => {
|
1589
|
1604
|
// Stores the "untoggle" handler which remembers whether was
|
1590
|
1605
|
// there any video before and whether was it muted.
|
1591
|
1606
|
this._untoggleScreenSharing
|
1592
|
1607
|
= this._turnScreenSharingOff.bind(this, didHaveVideo);
|
1593
|
|
- desktopStream.on(
|
1594
|
|
- JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
1595
|
|
- () => {
|
1596
|
|
- // If the stream was stopped during screen sharing
|
1597
|
|
- // session then we should switch back to video.
|
1598
|
|
- this.isSharingScreen
|
1599
|
|
- && this._untoggleScreenSharing
|
1600
|
|
- && this._untoggleScreenSharing();
|
1601
|
|
- }
|
1602
|
|
- );
|
|
1608
|
+
|
|
1609
|
+ const desktopVideoStream = desktopStreams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
|
1610
|
+
|
|
1611
|
+ if (desktopVideoStream) {
|
|
1612
|
+ desktopVideoStream.on(
|
|
1613
|
+ JitsiTrackEvents.LOCAL_TRACK_STOPPED,
|
|
1614
|
+ () => {
|
|
1615
|
+ // If the stream was stopped during screen sharing
|
|
1616
|
+ // session then we should switch back to video.
|
|
1617
|
+ this.isSharingScreen
|
|
1618
|
+ && this._untoggleScreenSharing
|
|
1619
|
+ && this._untoggleScreenSharing();
|
|
1620
|
+ }
|
|
1621
|
+ );
|
|
1622
|
+ }
|
1603
|
1623
|
|
1604
|
1624
|
// close external installation dialog on success.
|
1605
|
1625
|
externalInstallation && $.prompt.close();
|
1606
|
1626
|
|
1607
|
|
- return desktopStream;
|
|
1627
|
+ return desktopStreams;
|
1608
|
1628
|
}, error => {
|
1609
|
1629
|
DSExternalInstallationInProgress = false;
|
1610
|
1630
|
|
|
@@ -1755,7 +1775,29 @@ export default {
|
1755
|
1775
|
this.videoSwitchInProgress = true;
|
1756
|
1776
|
|
1757
|
1777
|
return this._createDesktopTrack(options)
|
1758
|
|
- .then(stream => this.useVideoStream(stream))
|
|
1778
|
+ .then(async streams => {
|
|
1779
|
+ const desktopVideoStream = streams.find(stream => stream.getType() === MEDIA_TYPE.VIDEO);
|
|
1780
|
+
|
|
1781
|
+ if (desktopVideoStream) {
|
|
1782
|
+ this.useVideoStream(desktopVideoStream);
|
|
1783
|
+ }
|
|
1784
|
+
|
|
1785
|
+ this._desktopAudioStream = streams.find(stream => stream.getType() === MEDIA_TYPE.AUDIO);
|
|
1786
|
+
|
|
1787
|
+ if (this._desktopAudioStream) {
|
|
1788
|
+ // If there is a localAudio stream, mix in the desktop audio stream captured by the screen sharing
|
|
1789
|
+ // api.
|
|
1790
|
+ if (this.localAudio) {
|
|
1791
|
+ this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
|
|
1792
|
+
|
|
1793
|
+ await this.localAudio.setEffect(this._mixerEffect);
|
|
1794
|
+ } else {
|
|
1795
|
+ // If no local stream is present ( i.e. no input audio devices) we use the screen share audio
|
|
1796
|
+ // stream as we would use a regular stream.
|
|
1797
|
+ await this.useAudioStream(this._desktopAudioStream);
|
|
1798
|
+ }
|
|
1799
|
+ }
|
|
1800
|
+ })
|
1759
|
1801
|
.then(() => {
|
1760
|
1802
|
this.videoSwitchInProgress = false;
|
1761
|
1803
|
if (config.enableScreenshotCapture) {
|
|
@@ -2288,7 +2330,17 @@ export default {
|
2288
|
2330
|
|
2289
|
2331
|
return stream;
|
2290
|
2332
|
})
|
2291
|
|
- .then(stream => this.useAudioStream(stream))
|
|
2333
|
+ .then(async stream => {
|
|
2334
|
+ // In case screen sharing audio is also shared we mix it with new input stream. The old _mixerEffect
|
|
2335
|
+ // will be cleaned up when the existing track is replaced.
|
|
2336
|
+ if (this._mixerEffect) {
|
|
2337
|
+ this._mixerEffect = new AudioMixerEffect(this._desktopAudioStream);
|
|
2338
|
+
|
|
2339
|
+ await stream.setEffect(this._mixerEffect);
|
|
2340
|
+ }
|
|
2341
|
+
|
|
2342
|
+ return this.useAudioStream(stream);
|
|
2343
|
+ })
|
2292
|
2344
|
.then(() => {
|
2293
|
2345
|
logger.log(`switched local audio device: ${this.localAudio?.getDeviceId()}`);
|
2294
|
2346
|
|