diff --git a/JitsiMeetJS.spec.ts b/JitsiMeetJS.spec.ts new file mode 100644 index 0000000000..6af5a6c781 --- /dev/null +++ b/JitsiMeetJS.spec.ts @@ -0,0 +1,43 @@ +import JitsiMeetJS from './JitsiMeetJS'; +import { VideoType } from './service/RTC/VideoType'; +import { MediaType } from './service/RTC/MediaType'; +import { JitsiTrackErrors } from './JitsiTrackErrors'; + +describe('JitsiMeetJS', () => { + describe('createLocalTracksFromMediaStreams', () => { + it('creates a local track from a media stream', () => { + const canvas = document.createElement('canvas'); + + const canvasStream = canvas.captureStream(5); + const trackInfo = { + stream: canvasStream, + sourceType: 'canvas', + mediaType: MediaType.VIDEO, + track: canvasStream.getVideoTracks()[0], + videoType: VideoType.DESKTOP + }; + const newTracks = JitsiMeetJS.createLocalTracksFromMediaStreams([ trackInfo ]); + + expect(newTracks).toBeDefined(); + expect(newTracks.length).toBe(1); + }); + + it('throws an error if track is not from the same stream', () => { + const canvas = document.createElement('canvas'); + const otherCanvas = document.createElement('canvas'); + + const canvasStream = canvas.captureStream(5); + const otherCanvasStream = otherCanvas.captureStream(5); + const trackInfo = { + stream: canvasStream, + sourceType: 'canvas', + mediaType: MediaType.VIDEO, + track: otherCanvasStream.getVideoTracks()[0], + videoType: VideoType.DESKTOP + }; + + expect(() => JitsiMeetJS.createLocalTracksFromMediaStreams([ trackInfo ])) + .toThrowError(JitsiTrackErrors.TRACK_MISMATCHED_STREAM); + }); + }); +}); diff --git a/JitsiMeetJS.ts b/JitsiMeetJS.ts index 2654200962..95bd6172b4 100644 --- a/JitsiMeetJS.ts +++ b/JitsiMeetJS.ts @@ -36,6 +36,7 @@ import * as ConnectionQualityEvents import * as E2ePingEvents from './service/e2eping/E2ePingEvents'; import { createGetUserMediaEvent } from './service/statistics/AnalyticsEvents'; import * as RTCStatsEvents from './modules/RTCStats/RTCStatsEvents'; +import { VideoType } from './service/RTC/VideoType'; const logger = Logger.getLogger(__filename); @@ -90,6 +91,14 @@ interface IJitsiMeetJSOptions { } } +interface ICreateLocalTrackFromMediaStreamOptions { + stream: MediaStream, + sourceType: string, + mediaType: MediaType, + track: MediaStreamTrack, + videoType?: VideoType +} + /** * The public API of the Jitsi Meet library (a.k.a. {@code JitsiMeetJS}). */ @@ -424,11 +433,30 @@ export default { /** * Manually create JitsiLocalTrack's from the provided track info, by exposing the RTC method * - * @param {Array} tracksInfo - array of track information + * @param {Array} tracksInfo - array of track information * @returns {Array} - created local tracks */ createLocalTracksFromMediaStreams(tracksInfo) { - return RTC.createLocalTracks(tracksInfo); + return RTC.createLocalTracks(tracksInfo.map((trackInfo) => { + const tracks = trackInfo.stream.getTracks(); + if (!tracks || tracks.length === 0) { + throw new JitsiTrackError(JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND); + } + + if (tracks.length > 1) { + throw new JitsiTrackError(JitsiTrackErrors.TRACK_TOO_MANY_TRACKS_IN_STREAM); + } + + if (tracks.indexOf(trackInfo.track) === -1) { + throw new JitsiTrackError(JitsiTrackErrors.TRACK_MISMATCHED_STREAM); + } + + if (!trackInfo.sourceId) { + trackInfo.sourceId = 'GENERATEDVALUEHERE'; + } + + return trackInfo; + })); }, /** diff --git a/JitsiTrackErrors.ts b/JitsiTrackErrors.ts index 01535292f8..9a06fad839 100644 --- a/JitsiTrackErrors.ts +++ b/JitsiTrackErrors.ts @@ -68,7 +68,22 @@ export enum JitsiTrackErrors { * An error which indicates that requested video resolution is not supported * by a webcam. */ - UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution' + UNSUPPORTED_RESOLUTION = 'gum.unsupported_resolution', + + /** + * An error which indicates that there are too many tracks in the provided media stream + */ + TRACK_TOO_MANY_TRACKS_IN_STREAM = 'track.too_many_tracks_in_stream', + + /** + * An error which indicates that no tracks were found in the media stream + */ + TRACK_NO_STREAM_TRACKS_FOUND = 'track.no_stream_tracks_found', + + /** + * An error which indicates that the track does not belong to the provided media stream + */ + TRACK_MISMATCHED_STREAM = 'track.mismatched_stream' } // exported for backward compatibility @@ -84,3 +99,6 @@ export const TIMEOUT = JitsiTrackErrors.TIMEOUT; export const TRACK_IS_DISPOSED = JitsiTrackErrors.TRACK_IS_DISPOSED; export const TRACK_NO_STREAM_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_FOUND; export const UNSUPPORTED_RESOLUTION = JitsiTrackErrors.UNSUPPORTED_RESOLUTION; +export const TRACK_TOO_MANY_TRACKS_IN_STREAM = JitsiTrackErrors.TRACK_TOO_MANY_TRACKS_IN_STREAM; +export const TRACK_NO_STREAM_TRACKS_FOUND = JitsiTrackErrors.TRACK_NO_STREAM_TRACKS_FOUND; +export const TRACK_MISMATCHED_STREAM = JitsiTrackErrors.TRACK_MISMATCHED_STREAM;