1
0
mirror of https://github.com/matrix-org/matrix-js-sdk.git synced 2025-08-07 23:02:56 +03:00

1:1 screenshare tests (#2617)

* 1:1 screenshare tests

Fixes https://github.com/vector-im/element-call/issues/548

* Always hang up calls after tests

to prevent hanging tests

Also fix a null dereference as we may not have an invitee or opponent
member when sending voip events if not using to-device messages.

* use mockImplementationOnce

Co-authored-by: Robin <robin@robin.town>

* use mockImplementationOnce

Co-authored-by: Robin <robin@robin.town>

* Add type on mock

* Add corresponding call.off

* Merge enable & disable screenshare tests

Co-authored-by: Robin <robin@robin.town>
This commit is contained in:
David Baker
2022-08-24 15:45:53 +01:00
committed by GitHub
parent c527f85fb1
commit 9e1b126854
3 changed files with 85 additions and 11 deletions

View File

@@ -56,6 +56,9 @@ export const DUMMY_SDP = (
"a=ssrc:3619738545 cname:2RWtmqhXLdoF4sOi\r\n" "a=ssrc:3619738545 cname:2RWtmqhXLdoF4sOi\r\n"
); );
export const USERMEDIA_STREAM_ID = "mock_stream_from_media_handler";
export const SCREENSHARE_STREAM_ID = "mock_screen_stream_from_media_handler";
class MockMediaStreamAudioSourceNode { class MockMediaStreamAudioSourceNode {
connect() {} connect() {}
} }
@@ -128,6 +131,10 @@ export class MockRTCPeerConnection {
return new MockRTCRtpSender(track); return new MockRTCRtpSender(track);
} }
removeTrack() {
this.needsNegotiation = true;
}
doNegotiation() { doNegotiation() {
if (this.needsNegotiation && this.negotiationNeededListener) { if (this.needsNegotiation && this.negotiationNeededListener) {
this.needsNegotiation = false; this.needsNegotiation = false;
@@ -222,7 +229,7 @@ export class MockMediaHandler {
if (audio) tracks.push(new MockMediaStreamTrack("audio_track", "audio")); if (audio) tracks.push(new MockMediaStreamTrack("audio_track", "audio"));
if (video) tracks.push(new MockMediaStreamTrack("video_track", "video")); if (video) tracks.push(new MockMediaStreamTrack("video_track", "video"));
const stream = new MockMediaStream("mock_stream_from_media_handler", tracks); const stream = new MockMediaStream(USERMEDIA_STREAM_ID, tracks);
this.userMediaStreams.push(stream); this.userMediaStreams.push(stream);
return stream; return stream;
} }
@@ -233,7 +240,7 @@ export class MockMediaHandler {
const tracks = [new MockMediaStreamTrack("video_track", "video")]; const tracks = [new MockMediaStreamTrack("video_track", "video")];
if (opts?.audio) tracks.push(new MockMediaStreamTrack("audio_track", "audio")); if (opts?.audio) tracks.push(new MockMediaStreamTrack("audio_track", "audio"));
const stream = new MockMediaStream("mock_screen_stream_from_media_handler", tracks); const stream = new MockMediaStream(SCREENSHARE_STREAM_ID, tracks);
this.screensharingStreams.push(stream); this.screensharingStreams.push(stream);
return stream; return stream;
} }

View File

@@ -30,6 +30,8 @@ import {
MockMediaStream, MockMediaStream,
MockMediaStreamTrack, MockMediaStreamTrack,
installWebRTCMocks, installWebRTCMocks,
MockRTCPeerConnection,
SCREENSHARE_STREAM_ID,
} from "../../test-utils/webrtc"; } from "../../test-utils/webrtc";
import { CallFeed } from "../../../src/webrtc/callFeed"; import { CallFeed } from "../../../src/webrtc/callFeed";
import { EventType, MatrixEvent } from "../../../src"; import { EventType, MatrixEvent } from "../../../src";
@@ -117,6 +119,9 @@ describe('Call', function() {
}); });
afterEach(function() { afterEach(function() {
// Hangup to stop timers
call.hangup(CallErrorCode.UserHangup, true);
client.stop(); client.stop();
global.navigator = prevNavigator; global.navigator = prevNavigator;
global.window = prevWindow; global.window = prevWindow;
@@ -178,9 +183,6 @@ describe('Call', function() {
getSender: () => "@test:foo", getSender: () => "@test:foo",
}); });
expect(call.peerConn.addIceCandidate.mock.calls.length).toBe(1); expect(call.peerConn.addIceCandidate.mock.calls.length).toBe(1);
// Hangup to stop timers
call.hangup(CallErrorCode.UserHangup, true);
}); });
it('should add candidates received before answer if party ID is correct', async function() { it('should add candidates received before answer if party ID is correct', async function() {
@@ -283,9 +285,6 @@ describe('Call', function() {
const ident = call.getRemoteAssertedIdentity(); const ident = call.getRemoteAssertedIdentity();
expect(ident.id).toEqual("@steve:example.com"); expect(ident.id).toEqual("@steve:example.com");
expect(ident.displayName).toEqual("Steve Gibbons"); expect(ident.displayName).toEqual("Steve Gibbons");
// Hangup to stop timers
call.hangup(CallErrorCode.UserHangup, true);
}); });
it("should map SDPStreamMetadata to feeds", async () => { it("should map SDPStreamMetadata to feeds", async () => {
@@ -734,16 +733,18 @@ describe('Call', function() {
describe("ignoring streams with ids for which we already have a feed", () => { describe("ignoring streams with ids for which we already have a feed", () => {
const STREAM_ID = "stream_id"; const STREAM_ID = "stream_id";
const FEEDS_CHANGED_CALLBACK = jest.fn(); let FEEDS_CHANGED_CALLBACK: jest.Mock<void, []>;
beforeEach(async () => { beforeEach(async () => {
FEEDS_CHANGED_CALLBACK = jest.fn();
await startVoiceCall(client, call); await startVoiceCall(client, call);
call.on(CallEvent.FeedsChanged, FEEDS_CHANGED_CALLBACK); call.on(CallEvent.FeedsChanged, FEEDS_CHANGED_CALLBACK);
jest.spyOn(call, "pushLocalFeed"); jest.spyOn(call, "pushLocalFeed");
}); });
afterEach(() => { afterEach(() => {
FEEDS_CHANGED_CALLBACK.mockReset(); call.off(CallEvent.FeedsChanged, FEEDS_CHANGED_CALLBACK);
}); });
it("should ignore stream passed to pushRemoteFeed()", async () => { it("should ignore stream passed to pushRemoteFeed()", async () => {
@@ -941,4 +942,70 @@ describe('Call', function() {
expect(call.state).toEqual(CallState.Ended); expect(call.state).toEqual(CallState.Ended);
}); });
describe("Screen sharing", () => {
beforeEach(async () => {
await startVoiceCall(client, call);
await call.onAnswerReceived({
getContent: () => {
return {
"version": 1,
"call_id": call.callId,
"party_id": 'party_id',
"answer": {
sdp: DUMMY_SDP,
},
"org.matrix.msc3077.sdp_stream_metadata": {
"foo": {
"purpose": "m.usermedia",
"audio_muted": false,
"video_muted": false,
},
},
};
},
getSender: () => "@test:foo",
});
});
afterEach(() => {
// Hangup to stop timers
call.hangup(CallErrorCode.UserHangup, true);
});
it("enables and disables screensharing", async () => {
await call.setScreensharingEnabled(true);
expect(call.feeds.filter(f => f.purpose == SDPStreamMetadataPurpose.Screenshare).length).toEqual(1);
client.client.sendEvent.mockReset();
const sendNegotiatePromise = new Promise<void>(resolve => {
client.client.sendEvent.mockImplementationOnce(() => {
resolve();
});
});
MockRTCPeerConnection.triggerAllNegotiations();
await sendNegotiatePromise;
expect(client.client.sendEvent).toHaveBeenCalledWith(
FAKE_ROOM_ID,
EventType.CallNegotiate,
expect.objectContaining({
"version": "1",
"call_id": call.callId,
"org.matrix.msc3077.sdp_stream_metadata": expect.objectContaining({
[SCREENSHARE_STREAM_ID]: expect.objectContaining({
purpose: SDPStreamMetadataPurpose.Screenshare,
}),
}),
}),
);
await call.setScreensharingEnabled(false);
expect(call.feeds.filter(f => f.purpose == SDPStreamMetadataPurpose.Screenshare).length).toEqual(0);
});
});
}); });

View File

@@ -2240,7 +2240,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap
eventType, eventType,
roomId: this.roomId, roomId: this.roomId,
content: realContent, content: realContent,
userId: this.invitee || this.getOpponentMember().userId, userId: this.invitee || this.getOpponentMember()?.userId,
}); });
await this.client.sendEvent(this.roomId, eventType, realContent); await this.client.sendEvent(this.roomId, eventType, realContent);