diff --git a/package.json b/package.json index 7f3d2be3..650512cc 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "@whereby.com/browser-sdk", - "version": "2.0.0-alpha21", + "version": "2.0.0-alpha22", "description": "Modules for integration Whereby video in web apps", "author": "Whereby AS", "license": "MIT", diff --git a/src/lib/RoomConnection.ts b/src/lib/RoomConnection.ts index 80d2d918..607158f6 100644 --- a/src/lib/RoomConnection.ts +++ b/src/lib/RoomConnection.ts @@ -173,6 +173,34 @@ function createSocket() { return new ServerSocket(SOCKET_HOST, socketConf); } +export function handleStreamAdded( + remoteParticipants: RemoteParticipant[], + { clientId, stream, streamId, streamType }: RtcStreamAddedPayload +) { + if (!streamId) { + streamId = stream.id; + } + const remoteParticipant = remoteParticipants.find((p) => p.id === clientId); + if (!remoteParticipant) { + return; + } + + const remoteParticipantStream = + remoteParticipant.streams.find((s) => s.id === streamId) || remoteParticipant.streams[0]; + + if ( + (remoteParticipant.stream && remoteParticipant.stream.id === streamId) || + (!remoteParticipant.stream && streamType === "webcam") || + (!remoteParticipant.stream && !streamType && remoteParticipant.streams.indexOf(remoteParticipantStream) < 1) + ) { + return new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }); + } + // screenshare + return new CustomEvent("screenshare_started", { + detail: { participantId: clientId, stream, id: streamId, isLocal: false }, + }); +} + /* * This is the topmost interface when dealing with Whereby. * @@ -717,35 +745,11 @@ export default class RoomConnection extends TypedEventTarget { }); } - private _handleStreamAdded({ clientId, stream, streamId, streamType }: RtcStreamAddedPayload) { - const remoteParticipant = this.remoteParticipants.find((p) => p.id === clientId); - if (!remoteParticipant) { - this.logger.log("WARN: Could not find participant for incoming stream"); - return; - } - - const remoteParticipantStream = remoteParticipant.streams.find((s) => s.id === streamId); - - if ( - (remoteParticipant.stream && remoteParticipant.stream.id === streamId) || - (!remoteParticipant.stream && streamType === "webcam") || - (!remoteParticipant.stream && - !streamType && - remoteParticipantStream && - remoteParticipant.streams.indexOf(remoteParticipantStream) < 1) - ) { - this.dispatchEvent( - new CustomEvent("participant_stream_added", { detail: { participantId: clientId, stream, streamId } }) - ); - return; + private _handleStreamAdded(args: RtcStreamAddedPayload) { + const streamAddedEvent = handleStreamAdded(this.remoteParticipants, args); + if (streamAddedEvent) { + this.dispatchEvent(streamAddedEvent); } - - // screenshare - this.dispatchEvent( - new CustomEvent("screenshare_started", { - detail: { participantId: clientId, stream, id: streamId, isLocal: false }, - }) - ); } private _joinRoom() { diff --git a/src/lib/__tests__/RoomConnection.spec.ts b/src/lib/__tests__/RoomConnection.spec.ts index b64ff0fd..41bc333a 100644 --- a/src/lib/__tests__/RoomConnection.spec.ts +++ b/src/lib/__tests__/RoomConnection.spec.ts @@ -1,6 +1,8 @@ import { jest } from "@jest/globals"; -import RoomConnection from "../RoomConnection"; +import RoomConnection, { handleStreamAdded } from "../RoomConnection"; +import { RemoteParticipant } from "../RoomParticipant"; +import MockMediaStream from "../__mocks__/MediaStream"; jest.mock("@whereby/jslib-media/src/utils/ServerSocket", () => { return jest.fn().mockImplementation(() => { @@ -40,3 +42,63 @@ describe("RoomConnection", () => { }); }); }); + +describe("handleStreamAdded", () => { + let remoteParticipants: RemoteParticipant[]; + + beforeEach(() => { + remoteParticipants = [ + new RemoteParticipant({ + displayName: "Participant", + id: "id", + newJoiner: false, + streams: ["0", "screenshare"], + isAudioEnabled: true, + isVideoEnabled: true, + }), + ]; + }); + + it("should return undefined if remote participant cannot be found", () => { + const res = handleStreamAdded(remoteParticipants, { + clientId: "zzz", + stream: new MockMediaStream(), + streamId: undefined, + streamType: undefined, + }); + + expect(res).toEqual(undefined); + }); + + it("should return `participant_stream_added` when stream id cannot be matched", () => { + const clientId = "id"; + const stream = new MockMediaStream(); + const streamId = undefined; + + const res = handleStreamAdded(remoteParticipants, { + clientId, + stream, + streamId, + streamType: undefined, + }); + + expect(res?.type).toEqual("participant_stream_added"); + expect(res?.detail).toEqual({ participantId: clientId, stream, streamId: stream.id }); + }); + + it("should return `screenshare_started` when stream id is matched", () => { + const clientId = "id"; + const stream = new MockMediaStream(); + const streamId = "screenshare"; + + const res = handleStreamAdded(remoteParticipants, { + clientId, + stream, + streamId, + streamType: undefined, + }); + + expect(res?.type).toEqual("screenshare_started"); + expect(res?.detail).toEqual({ participantId: clientId, stream, id: streamId, isLocal: false }); + }); +}); diff --git a/src/stories/components/VideoExperience.tsx b/src/stories/components/VideoExperience.tsx index e6ba634c..33d4a372 100644 --- a/src/stories/components/VideoExperience.tsx +++ b/src/stories/components/VideoExperience.tsx @@ -23,8 +23,14 @@ export default function VideoExperience({ logger: console, }); - const { localParticipant, mostRecentChatMessage, remoteParticipants, roomConnectionStatus, waitingParticipants } = - state; + const { + localParticipant, + mostRecentChatMessage, + remoteParticipants, + roomConnectionStatus, + waitingParticipants, + screenshares, + } = state; const { knock, sendChatMessage, @@ -108,6 +114,12 @@ export default function VideoExperience({ ) : null} ))} + {screenshares.map( + (s) => + s.stream && ( + + ) + )}
diff --git a/src/types.d.ts b/src/types.d.ts index d4381d49..9d21cb3b 100644 --- a/src/types.d.ts +++ b/src/types.d.ts @@ -32,8 +32,8 @@ declare module "@whereby/jslib-media/src/webrtc/RtcManagerDispatcher" { interface RtcStreamAddedPayload { clientId: string; stream: MediaStream; - streamId: string; - streamType: "webcam" | "screenshare"; + streamId: string | undefined; + streamType: "webcam" | "screenshare" | undefined; } type RtcEvents = {