Переглянути джерело

feat(RTC): add support for creating non-standard tracks (#2409)

* feat(RTC): add support for creating non-standard tracks

* fix(RTC): add additional checks for creating tracks via mediastream

* fix(RTC): simplify options to create track

* fix(RTC): fix tests

* fix(RTC): update sourceId documentation
release-8443
Daniel McAssey 1 рік тому
джерело
коміт
8bee4514a0
Аккаунт користувача з таким Email не знайдено

+ 39
- 0
JitsiMeetJS.spec.ts Переглянути файл

@@ -0,0 +1,39 @@
1
+import JitsiMeetJS from './JitsiMeetJS';
2
+import { VideoType } from './service/RTC/VideoType';
3
+import { MediaType } from './service/RTC/MediaType';
4
+import { JitsiTrackErrors } from './JitsiTrackErrors';
5
+
6
+describe('JitsiMeetJS', () => {
7
+    describe('createLocalTracksFromMediaStreams', () => {
8
+        it('creates a local track from a media stream', () => {
9
+            const canvas = document.createElement('canvas');
10
+
11
+            const canvasStream = canvas.captureStream(5);
12
+            const trackInfo = {
13
+                stream: canvasStream,
14
+                sourceType: 'canvas',
15
+                mediaType: MediaType.VIDEO,
16
+                videoType: VideoType.DESKTOP
17
+            };
18
+            const newTracks = JitsiMeetJS.createLocalTracksFromMediaStreams([ trackInfo ]);
19
+
20
+            expect(newTracks).toBeDefined();
21
+            expect(newTracks.length).toBe(1);
22
+        });
23
+
24
+        it('throws an error if track is not the correct media type', () => {
25
+            const canvas = document.createElement('canvas');
26
+
27
+            const canvasStream = canvas.captureStream(5);
28
+            const trackInfo = {
29
+                stream: canvasStream,
30
+                sourceType: 'canvas',
31
+                mediaType: MediaType.AUDIO,
32
+                videoType: VideoType.DESKTOP
33
+            };
34
+
35
+            expect(() => JitsiMeetJS.createLocalTracksFromMediaStreams([ trackInfo ]))
36
+                .toThrowError(JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND);
37
+        });
38
+    });
39
+});

+ 33
- 0
JitsiMeetJS.ts Переглянути файл

@@ -36,6 +36,7 @@ import * as ConnectionQualityEvents
36 36
 import * as E2ePingEvents from './service/e2eping/E2ePingEvents';
37 37
 import { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents';
38 38
 import *  as RTCStatsEvents from './modules/RTCStats/RTCStatsEvents';
39
+import { VideoType } from './service/RTC/VideoType';
39 40
 
40 41
 const logger = Logger.getLogger(__filename);
41 42
 
@@ -90,6 +91,13 @@ interface IJitsiMeetJSOptions {
90 91
     }
91 92
 }
92 93
 
94
+interface ICreateLocalTrackFromMediaStreamOptions {
95
+    stream: MediaStream,
96
+    sourceType: string,
97
+    mediaType: MediaType,
98
+    videoType?: VideoType
99
+}
100
+
93 101
 /**
94 102
  * The public API of the Jitsi Meet library (a.k.a. {@code JitsiMeetJS}).
95 103
  */
@@ -421,6 +429,31 @@ export default {
421 429
             });
422 430
     },
423 431
 
432
+    /**
433
+     * Manually create JitsiLocalTrack's from the provided track info, by exposing the RTC method
434
+     *
435
+     * @param {Array<ICreateLocalTrackFromMediaStreamOptions>} tracksInfo - array of track information
436
+     * @returns {Array<JitsiLocalTrack>} - created local tracks
437
+     */
438
+    createLocalTracksFromMediaStreams(tracksInfo) {
439
+        return RTC.createLocalTracks(tracksInfo.map((trackInfo) => {
440
+            const tracks = trackInfo.stream.getTracks()
441
+                .filter(track => track.kind === trackInfo.mediaType);
442
+
443
+            if (!tracks || tracks.length === 0) {
444
+                throw new JitsiTrackError(JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND, null, null);
445
+            }
446
+
447
+            if (tracks.length > 1) {
448
+                throw new JitsiTrackError(JitsiTrackErrors.TRACK_TOO_MANY_TRACKS_IN_STREAM, null, null);
449
+            }
450
+
451
+            trackInfo.track = tracks[0];
452
+
453
+            return trackInfo;
454
+        }));
455
+    },
456
+
424 457
     /**
425 458
      * Create a TrackVADEmitter service that connects an audio track to an VAD (voice activity detection) processor in
426 459
      * order to obtain VAD scores for individual PCM audio samples.

+ 7
- 1
JitsiTrackErrors.spec.ts Переглянути файл

@@ -16,6 +16,8 @@ describe( "/JitsiTrackErrors members", () => {
16 16
         TRACK_IS_DISPOSED,
17 17
         TRACK_NO_STREAM_FOUND,
18 18
         UNSUPPORTED_RESOLUTION,
19
+        TRACK_TOO_MANY_TRACKS_IN_STREAM,
20
+        TRACK_NO_STREAM_TRACKS_FOUND,
19 21
         JitsiTrackErrors,
20 22
         ...others
21 23
     } = exported;
@@ -33,6 +35,8 @@ describe( "/JitsiTrackErrors members", () => {
33 35
         expect( TRACK_IS_DISPOSED ).toBe( 'track.track_is_disposed' );
34 36
         expect( TRACK_NO_STREAM_FOUND ).toBe( 'track.no_stream_found' );
35 37
         expect( UNSUPPORTED_RESOLUTION ).toBe( 'gum.unsupported_resolution' );
38
+        expect( TRACK_TOO_MANY_TRACKS_IN_STREAM ).toBe( 'track.too_many_tracks_in_stream' );
39
+        expect( TRACK_NO_STREAM_TRACKS_FOUND ).toBe( 'track.no_stream_tracks_found' );
36 40
 
37 41
         expect( JitsiTrackErrors ).toBeDefined();
38 42
 
@@ -48,10 +52,12 @@ describe( "/JitsiTrackErrors members", () => {
48 52
         expect( JitsiTrackErrors.TRACK_IS_DISPOSED ).toBe( 'track.track_is_disposed' );
49 53
         expect( JitsiTrackErrors.TRACK_NO_STREAM_FOUND ).toBe( 'track.no_stream_found' );
50 54
         expect( JitsiTrackErrors.UNSUPPORTED_RESOLUTION ).toBe( 'gum.unsupported_resolution' );
55
+        expect( JitsiTrackErrors.TRACK_TOO_MANY_TRACKS_IN_STREAM ).toBe( 'track.too_many_tracks_in_stream' );
56
+        expect( JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND ).toBe( 'track.no_stream_tracks_found' );
51 57
     } );
52 58
 
53 59
     it( "unknown members", () => {
54 60
         const keys = Object.keys( others );
55 61
         expect( keys ).withContext( `Extra members: ${ keys.join( ", " ) }` ).toEqual( [] );
56 62
     } );
57
-} );
63
+} );

+ 13
- 1
JitsiTrackErrors.ts Переглянути файл

@@ -68,7 +68,17 @@ export enum JitsiTrackErrors {
68 68
      * An error which indicates that requested video resolution is not supported
69 69
      * by a webcam.
70 70
      */
71
-    UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution'
71
+    UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution',
72
+
73
+    /**
74
+     * An error which indicates that there are too many tracks in the provided media stream
75
+     */
76
+    TRACK_TOO_MANY_TRACKS_IN_STREAM = 'track.too_many_tracks_in_stream',
77
+
78
+    /**
79
+     * An error which indicates that no tracks were found in the media stream
80
+     */
81
+    TRACK_NO_STREAM_TRACKS_FOUND = 'track.no_stream_tracks_found',
72 82
 }
73 83
 
74 84
 // exported for backward compatibility
@@ -84,3 +94,5 @@ export const TIMEOUT = JitsiTrackErrors.TIMEOUT;
84 94
 export const TRACK_IS_DISPOSED = JitsiTrackErrors.TRACK_IS_DISPOSED;
85 95
 export const TRACK_NO_STREAM_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_FOUND;
86 96
 export const UNSUPPORTED_RESOLUTION = JitsiTrackErrors.UNSUPPORTED_RESOLUTION;
97
+export const TRACK_TOO_MANY_TRACKS_IN_STREAM = JitsiTrackErrors.TRACK_TOO_MANY_TRACKS_IN_STREAM;
98
+export const TRACK_NO_STREAM_TRACKS_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND;

+ 2
- 2
modules/RTC/JitsiLocalTrack.js Переглянути файл

@@ -47,8 +47,8 @@ export default class JitsiLocalTrack extends JitsiTrack {
47 47
      * @param {number} trackInfo.resolution - The the video resolution if it's a video track
48 48
      * @param {string} trackInfo.deviceId - The ID of the local device for this track.
49 49
      * @param {string} trackInfo.facingMode - Thehe camera facing mode used in getUserMedia call (for mobile only).
50
-     * @param {sourceId} trackInfo.sourceId - The id of the desktop sharing source. NOTE: defined for desktop sharing
51
-     * tracks only.
50
+     * @param {sourceId} trackInfo.sourceId - The id of the desktop sharing source, which is the Chrome media source ID,
51
+     * returned by Desktop Picker on Electron. NOTE: defined for desktop sharing tracks only.
52 52
      */
53 53
     constructor({
54 54
         deviceId,

+ 2
- 0
types/hand-crafted/JitsiMeetJS.d.ts Переглянути файл

@@ -122,6 +122,8 @@ export type JitsiMeetJSType = {
122 122
 
123 123
   getActiveAudioDevice: () => Promise<Object>; // TODO: can we improve on object?
124 124
 
125
+  createLocalTracksFromMediaStreams: ( tracksInfo: unknown[] ) => JitsiLocalTrack[]; // TODO:
126
+
125 127
   // isDeviceListAvailable: () => boolean; // obsosete
126 128
 
127 129
   // isDeviceChangeAvailable: ( deviceType: string ) => boolean; // obsosete

Завантаження…
Відмінити
Зберегти