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 && (
+