Procházet zdrojové kódy

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

dev1
Andrei Gavrilescu před 5 roky
rodič
revize
960eea3c50
Žádný účet není propojen s e-mailovou adresou tvůrce revize
3 změnil soubory, kde provedl 49 přidání a 23 odebrání
  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 Zobrazit soubor

162
  * @param {Object} options.frameRate - used only for dekstop sharing.
162
  * @param {Object} options.frameRate - used only for dekstop sharing.
163
  * @param {Object} options.frameRate.min - Minimum fps
163
  * @param {Object} options.frameRate.min - Minimum fps
164
  * @param {Object} options.frameRate.max - Maximum fps
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
 function getConstraints(um, options = {}) {
168
 function getConstraints(um, options = {}) {
167
     const constraints = {
169
     const constraints = {
308
             }),
310
             }),
309
             optional: []
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
     if (options.bandwidth) {
330
     if (options.bandwidth) {
930
     * @param {Object} options.frameRate - used only for dekstop sharing.
947
     * @param {Object} options.frameRate - used only for dekstop sharing.
931
     * @param {Object} options.frameRate.min - Minimum fps
948
     * @param {Object} options.frameRate.min - Minimum fps
932
     * @param {Object} options.frameRate.max - Maximum fps
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
     * @returns {Promise} Returns a media stream on success or a JitsiTrackError
952
     * @returns {Promise} Returns a media stream on success or a JitsiTrackError
934
     * on failure.
953
     * on failure.
935
     **/
954
     **/
940
 
959
 
941
         return new Promise((resolve, reject) => {
960
         return new Promise((resolve, reject) => {
942
             navigator.mediaDevices.getUserMedia(constraints)
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 Zobrazit soubor

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

+ 12
- 9
modules/webaudio/AudioMixer.js Zobrazit soubor

18
     constructor() {
18
     constructor() {
19
         this._started = false;
19
         this._started = false;
20
         this._streamsToMix = [];
20
         this._streamsToMix = [];
21
+        this._streamMSSArray = [];
21
     }
22
     }
22
 
23
 
23
     /**
24
     /**
56
 
57
 
57
         this._started = true;
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
         for (const stream of this._streamsToMix) {
62
         for (const stream of this._streamsToMix) {
63
             const streamMSS = this._audioContext.createMediaStreamSource(stream);
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
         return this._mixedMSD.stream;
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
      * @returns {void}
77
      * @returns {void}
78
      */
78
      */
80
         this._started = false;
80
         this._started = false;
81
         this._streamsToMix = [];
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
         if (this._audioContext) {
90
         if (this._audioContext) {
88
             this._audioContext = undefined;
91
             this._audioContext = undefined;
89
         }
92
         }

Načítá se…
Zrušit
Uložit