diff --git a/spec/test-utils/webrtc.ts b/spec/test-utils/webrtc.ts index 5d994a454..e79207df4 100644 --- a/spec/test-utils/webrtc.ts +++ b/spec/test-utils/webrtc.ts @@ -33,6 +33,7 @@ import { ReEmitter } from "../../src/ReEmitter"; import { SyncState } from "../../src/sync"; import { CallEvent, CallEventHandlerMap, MatrixCall } from "../../src/webrtc/call"; import { CallEventHandlerEvent, CallEventHandlerEventHandlerMap } from "../../src/webrtc/callEventHandler"; +import { CallFeed } from "../../src/webrtc/callFeed"; import { GroupCallEventHandlerMap } from "../../src/webrtc/groupCall"; import { GroupCallEventHandlerEvent } from "../../src/webrtc/groupCallEventHandler"; import { IScreensharingOpts, MediaHandler } from "../../src/webrtc/mediaHandler"; @@ -384,6 +385,20 @@ export class MockCallMatrixClient extends TypedEventEmitter(), stream: new MockMediaStream("stream"), }; + public remoteUsermediaFeed: CallFeed; + public remoteScreensharingFeed: CallFeed; public reject = jest.fn(); public answerWithCallFeeds = jest.fn(); @@ -157,6 +160,14 @@ describe('Group Call', function() { groupCall = new GroupCall(mockClient, room, GroupCallType.Video, false, GroupCallIntent.Prompt); }); + it("does not initialize local call feed, if it already is", async () => { + await groupCall.initLocalCallFeed(); + jest.spyOn(groupCall, "initLocalCallFeed"); + await groupCall.enter(); + + expect(groupCall.initLocalCallFeed).not.toHaveBeenCalled(); + }); + it("sends state event to room when creating", async () => { await groupCall.create(); @@ -280,6 +291,119 @@ describe('Group Call', function() { } }); + describe("call feeds changing", () => { + let call: MockCall; + const currentFeed = new MockCallFeed(FAKE_USER_ID_1, new MockMediaStream("current")); + const newFeed = new MockCallFeed(FAKE_USER_ID_1, new MockMediaStream("new")); + + beforeEach(async () => { + jest.spyOn(currentFeed, "dispose"); + jest.spyOn(newFeed, "measureVolumeActivity"); + + jest.spyOn(groupCall, "emit"); + + call = new MockCall(room.roomId, groupCall.groupCallId); + + await groupCall.create(); + }); + + it("ignores changes, if we can't get user id of opponent", async () => { + const call = new MockCall(room.roomId, groupCall.groupCallId); + jest.spyOn(call, "getOpponentMember").mockReturnValue({ userId: undefined }); + + // @ts-ignore Mock + expect(() => groupCall.onCallFeedsChanged(call)).toThrowError(); + }); + + describe("usermedia feeds", () => { + it("adds new usermedia feed", async () => { + call.remoteUsermediaFeed = newFeed.typed(); + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.userMediaFeeds).toStrictEqual([newFeed]); + }); + + it("replaces usermedia feed", async () => { + groupCall.userMediaFeeds = [currentFeed.typed()]; + + call.remoteUsermediaFeed = newFeed.typed(); + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.userMediaFeeds).toStrictEqual([newFeed]); + }); + + it("removes usermedia feed", async () => { + groupCall.userMediaFeeds = [currentFeed.typed()]; + + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.userMediaFeeds).toHaveLength(0); + }); + }); + + describe("screenshare feeds", () => { + it("adds new screenshare feed", async () => { + call.remoteScreensharingFeed = newFeed.typed(); + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.screenshareFeeds).toStrictEqual([newFeed]); + }); + + it("replaces screenshare feed", async () => { + groupCall.screenshareFeeds = [currentFeed.typed()]; + + call.remoteScreensharingFeed = newFeed.typed(); + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.screenshareFeeds).toStrictEqual([newFeed]); + }); + + it("removes screenshare feed", async () => { + groupCall.screenshareFeeds = [currentFeed.typed()]; + + // @ts-ignore Mock + groupCall.onCallFeedsChanged(call); + + expect(groupCall.screenshareFeeds).toHaveLength(0); + }); + }); + + describe("feed replacing", () => { + it("replaces usermedia feed", async () => { + groupCall.userMediaFeeds = [currentFeed.typed()]; + + // @ts-ignore Mock + groupCall.replaceUserMediaFeed(currentFeed, newFeed); + + const newFeeds = [newFeed]; + + expect(groupCall.userMediaFeeds).toStrictEqual(newFeeds); + expect(currentFeed.dispose).toHaveBeenCalled(); + expect(newFeed.measureVolumeActivity).toHaveBeenCalledWith(true); + expect(groupCall.emit).toHaveBeenCalledWith(GroupCallEvent.UserMediaFeedsChanged, newFeeds); + }); + + it("replaces screenshare feed", async () => { + groupCall.screenshareFeeds = [currentFeed.typed()]; + + // @ts-ignore Mock + groupCall.replaceScreenshareFeed(currentFeed, newFeed); + + const newFeeds = [newFeed]; + + expect(groupCall.screenshareFeeds).toStrictEqual(newFeeds); + expect(currentFeed.dispose).toHaveBeenCalled(); + expect(newFeed.measureVolumeActivity).toHaveBeenCalledWith(true); + expect(groupCall.emit).toHaveBeenCalledWith(GroupCallEvent.ScreenshareFeedsChanged, newFeeds); + }); + }); + }); + describe("PTT calls", () => { beforeEach(async () => { // replace groupcall with a PTT one @@ -801,6 +925,19 @@ describe('Group Call', function() { expect(newMockCall.answerWithCallFeeds).toHaveBeenCalled(); expect(groupCall.calls).toEqual([newMockCall]); }); + + it("starts to process incoming calls when we've entered", async () => { + // First we leave the call since we have already entered + groupCall.leave(); + + const call = new MockCall(room.roomId, groupCall.groupCallId); + mockClient.callEventHandler.calls = new Map([ + [call.callId, call.typed()], + ]); + await groupCall.enter(); + + expect(call.answerWithCallFeeds).toHaveBeenCalled(); + }); }); describe("screensharing", () => { @@ -885,10 +1022,29 @@ describe('Group Call', function() { ])); expect(groupCall.screenshareFeeds).toHaveLength(1); - expect(groupCall.getScreenshareFeedByUserId(call.invitee)).toBeDefined(); + expect(groupCall.getScreenshareFeedByUserId(call.invitee!)).toBeDefined(); groupCall.terminate(); }); + + it("cleans up screensharing when terminating", async () => { + // @ts-ignore Mock + jest.spyOn(groupCall, "removeScreenshareFeed"); + jest.spyOn(mockClient.getMediaHandler(), "stopScreensharingStream"); + + await groupCall.setScreensharingEnabled(true); + + const screensharingFeed = groupCall.localScreenshareFeed; + + groupCall.terminate(); + + expect(mockClient.getMediaHandler()!.stopScreensharingStream).toHaveBeenCalledWith( + screensharingFeed!.stream, + ); + // @ts-ignore Mock + expect(groupCall.removeScreenshareFeed).toHaveBeenCalledWith(screensharingFeed); + expect(groupCall.localScreenshareFeed).toBeUndefined(); + }); }); describe("active speaker events", () => {