Преглед изворни кода

feat(screenSharing): Add support for audio screen sharing on electron

dev1
Andrei Gavrilescu пре 5 година
родитељ
комит
960eea3c50
No account linked to committer's email address
3 измењених фајлова са 49 додато и 23 уклоњено
  1. 30
    11
      modules/RTC/RTCUtils.js
  2. 7
    3
      modules/RTC/ScreenObtainer.js
  3. 12
    9
      modules/webaudio/AudioMixer.js

+ 30
- 11
modules/RTC/RTCUtils.js Прегледај датотеку

@@ -162,6 +162,8 @@ function setResolutionConstraints(
162 162
  * @param {Object} options.frameRate - used only for dekstop sharing.
163 163
  * @param {Object} options.frameRate.min - Minimum fps
164 164
  * @param {Object} options.frameRate.max - Maximum fps
165
+ * @param {bool}   options.screenShareAudio - Used by electron clients to
166
+ * enable system audio screen sharing.
165 167
  */
166 168
 function getConstraints(um, options = {}) {
167 169
     const constraints = {
@@ -308,6 +310,21 @@ function getConstraints(um, options = {}) {
308 310
             }),
309 311
             optional: []
310 312
         };
313
+
314
+        // Audio screen sharing for electron only works for screen type devices.
315
+        // i.e. when the user shares the whole desktop.
316
+        if (browser.isElectron() && options.screenShareAudio
317
+            && (options.desktopStream.indexOf('screen') >= 0)) {
318
+
319
+            // Provide constraints as described by the electron desktop capturer
320
+            // documentation here:
321
+            // https://www.electronjs.org/docs/api/desktop-capturer
322
+            constraints.audio = { mandatory: {
323
+                chromeMediaSource: constraints.video.mandatory.chromeMediaSource
324
+            } };
325
+
326
+            delete constraints.video.mandatory.chromeMediaSourceId;
327
+        }
311 328
     }
312 329
 
313 330
     if (options.bandwidth) {
@@ -930,6 +947,8 @@ class RTCUtils extends Listenable {
930 947
     * @param {Object} options.frameRate - used only for dekstop sharing.
931 948
     * @param {Object} options.frameRate.min - Minimum fps
932 949
     * @param {Object} options.frameRate.max - Maximum fps
950
+    * @param {bool}   options.screenShareAudio - Used by electron clients to
951
+    * enable system audio screen sharing.
933 952
     * @returns {Promise} Returns a media stream on success or a JitsiTrackError
934 953
     * on failure.
935 954
     **/
@@ -940,17 +959,17 @@ class RTCUtils extends Listenable {
940 959
 
941 960
         return new Promise((resolve, reject) => {
942 961
             navigator.mediaDevices.getUserMedia(constraints)
943
-                .then(stream => {
944
-                    logger.log('onUserMediaSuccess');
945
-                    updateGrantedPermissions(um, stream);
946
-                    resolve(stream);
947
-                })
948
-                .catch(error => {
949
-                    logger.warn('Failed to get access to local media. '
950
-                        + ` ${error} ${constraints} `);
951
-                    updateGrantedPermissions(um, undefined);
952
-                    reject(new JitsiTrackError(error, constraints, um));
953
-                });
962
+            .then(stream => {
963
+                logger.log('onUserMediaSuccess');
964
+                updateGrantedPermissions(um, stream);
965
+                resolve(stream);
966
+            })
967
+            .catch(error => {
968
+                logger.warn('Failed to get access to local media. '
969
+                    + ` ${error} ${constraints} `);
970
+                updateGrantedPermissions(um, undefined);
971
+                reject(new JitsiTrackError(error, constraints, um));
972
+            });
954 973
         });
955 974
     }
956 975
 

+ 7
- 3
modules/RTC/ScreenObtainer.js Прегледај датотеку

@@ -189,12 +189,13 @@ const ScreenObtainer = {
189 189
                     desktopSharingSources: desktopSharingSources
190 190
                         || this.options.desktopSharingChromeSources
191 191
                 },
192
-                (streamId, streamType) =>
192
+                (streamId, streamType, screenShareAudio = false) =>
193 193
                     onGetStreamResponse(
194 194
                         {
195 195
                             response: {
196 196
                                 streamId,
197
-                                streamType
197
+                                streamType,
198
+                                screenShareAudio
198 199
                             },
199 200
                             gumOptions
200 201
                         },
@@ -575,6 +576,8 @@ function waitForExtensionAfterInstall(options, waitInterval, retries) {
575 576
  * @param {object} options.response
576 577
  * @param {string} options.response.streamId - the streamId for the desktop
577 578
  * stream.
579
+ * @param {bool}   options.response.screenShareAudio - Used by electron clients to
580
+ * enable system audio screen sharing.
578 581
  * @param {string} options.response.error - error to be reported.
579 582
  * @param {object} options.gumOptions - options passed to GUM.
580 583
  * @param {Function} onSuccess - callback for success.
@@ -588,11 +591,12 @@ function onGetStreamResponse(
588 591
         },
589 592
         onSuccess,
590 593
         onFailure) {
591
-    const { streamId, streamType, error } = options.response || {};
594
+    const { streamId, streamType, screenShareAudio, error } = options.response || {};
592 595
 
593 596
     if (streamId) {
594 597
         const gumOptions = {
595 598
             desktopStream: streamId,
599
+            screenShareAudio,
596 600
             ...options.gumOptions
597 601
         };
598 602
 

+ 12
- 9
modules/webaudio/AudioMixer.js Прегледај датотеку

@@ -18,6 +18,7 @@ export default class AudioMixer {
18 18
     constructor() {
19 19
         this._started = false;
20 20
         this._streamsToMix = [];
21
+        this._streamMSSArray = [];
21 22
     }
22 23
 
23 24
     /**
@@ -56,23 +57,22 @@ export default class AudioMixer {
56 57
 
57 58
         this._started = true;
58 59
 
59
-        // Create ChannelMergerNode and connect all MediaStreams to it.
60
-        this._channelMerger = this._audioContext.createChannelMerger(this._streamsToMix.length);
60
+        this._mixedMSD = this._audioContext.createMediaStreamDestination();
61 61
 
62 62
         for (const stream of this._streamsToMix) {
63 63
             const streamMSS = this._audioContext.createMediaStreamSource(stream);
64 64
 
65
-            streamMSS.connect(this._channelMerger);
66
-        }
65
+            streamMSS.connect(this._mixedMSD);
67 66
 
68
-        this._mixedMSD = this._audioContext.createMediaStreamDestination();
69
-        this._channelMerger.connect(this._mixedMSD);
67
+            // Maintain a list of MediaStreamAudioSourceNode so we can disconnect them on reset.
68
+            this._streamMSSArray.push(streamMSS);
69
+        }
70 70
 
71 71
         return this._mixedMSD.stream;
72 72
     }
73 73
 
74 74
     /**
75
-     * Disconnect the ChannelMergerNode stopping the audio mix process.References to MediaStreams are also cleared.
75
+     * Disconnect MediaStreamAudioSourceNode and clear references.
76 76
      *
77 77
      * @returns {void}
78 78
      */
@@ -80,10 +80,13 @@ export default class AudioMixer {
80 80
         this._started = false;
81 81
         this._streamsToMix = [];
82 82
 
83
-        if (this._channelMerger) {
84
-            this._channelMerger.disconnect();
83
+        // Clean up created MediaStreamAudioSourceNode.
84
+        for (const streamMSS of this._streamMSSArray) {
85
+            streamMSS.disconnect();
85 86
         }
86 87
 
88
+        this._streamMSSArray = [];
89
+
87 90
         if (this._audioContext) {
88 91
             this._audioContext = undefined;
89 92
         }

Loading…
Откажи
Сачувај