Skip to content

Commit

Permalink
Don't expose calls on GroupCall
Browse files Browse the repository at this point in the history
Signed-off-by: Šimon Brandner <simon.bra.ag@gmail.com>
  • Loading branch information
SimonBrandner committed Dec 4, 2022
1 parent 0af2f79 commit 76b255b
Show file tree
Hide file tree
Showing 4 changed files with 53 additions and 11 deletions.
26 changes: 16 additions & 10 deletions spec/unit/webrtc/groupCall.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -515,7 +515,7 @@ describe('Group Call', function() {

it("sends metadata updates before unmuting in PTT mode", async () => {
const mockCall = new MockCall(FAKE_ROOM_ID, groupCall.groupCallId);
groupCall.calls.set(
(groupCall as any).calls.set(
mockCall.getOpponentMember() as RoomMember,
new Map([[mockCall.getOpponentDeviceId(), mockCall.typed()]]),
);
Expand All @@ -540,7 +540,7 @@ describe('Group Call', function() {

it("sends metadata updates after muting in PTT mode", async () => {
const mockCall = new MockCall(FAKE_ROOM_ID, groupCall.groupCallId);
groupCall.calls.set(
(groupCall as any).calls.set(
mockCall.getOpponentMember() as RoomMember,
new Map([[mockCall.getOpponentDeviceId(), mockCall.typed()]]),
);
Expand Down Expand Up @@ -698,7 +698,7 @@ describe('Group Call', function() {

expect(client1.sendToDevice).toHaveBeenCalled();

const oldCall = groupCall1.calls.get(
const oldCall = (groupCall1 as any).calls.get(
groupCall1.room.getMember(client2.userId)!,
)!.get(client2.deviceId)!;
oldCall.emit(CallEvent.Hangup, oldCall!);
Expand All @@ -719,7 +719,7 @@ describe('Group Call', function() {
// to even be created...
let newCall: MatrixCall | undefined;
while (
(newCall = groupCall1.calls.get(
(newCall = (groupCall1 as any).calls.get(
groupCall1.room.getMember(client2.userId)!,
)?.get(client2.deviceId)) === undefined
|| newCall.peerConn === undefined
Expand Down Expand Up @@ -763,7 +763,7 @@ describe('Group Call', function() {
groupCall1.setMicrophoneMuted(false);
groupCall1.setLocalVideoMuted(false);

const call = groupCall1.calls.get(
const call = (groupCall1 as any).calls.get(
groupCall1.room.getMember(client2.userId)!,
)!.get(client2.deviceId)!;
call.isMicrophoneMuted = jest.fn().mockReturnValue(true);
Expand Down Expand Up @@ -874,7 +874,9 @@ describe('Group Call', function() {
// It takes a bit of time for the calls to get created
await sleep(10);

const call = groupCall.calls.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!.get(FAKE_DEVICE_ID_2)!;
const call = (groupCall as any).calls
.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!
.get(FAKE_DEVICE_ID_2)!;
call.getOpponentMember = () => ({ userId: call.invitee }) as RoomMember;
// @ts-ignore Mock
call.pushRemoteFeed(new MockMediaStream("stream", [
Expand All @@ -897,7 +899,9 @@ describe('Group Call', function() {
// It takes a bit of time for the calls to get created
await sleep(10);

const call = groupCall.calls.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!.get(FAKE_DEVICE_ID_2)!;
const call = (groupCall as any).calls
.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!
.get(FAKE_DEVICE_ID_2)!;
call.getOpponentMember = () => ({ userId: call.invitee }) as RoomMember;
// @ts-ignore Mock
call.pushRemoteFeed(new MockMediaStream("stream", [
Expand Down Expand Up @@ -972,7 +976,7 @@ describe('Group Call', function() {

expect(mockCall.reject).not.toHaveBeenCalled();
expect(mockCall.answerWithCallFeeds).toHaveBeenCalled();
expect(groupCall.calls).toEqual(new Map([[
expect((groupCall as any).calls).toEqual(new Map([[
groupCall.room.getMember(FAKE_USER_ID_1)!,
new Map([[FAKE_DEVICE_ID_1, mockCall]]),
]]));
Expand All @@ -989,7 +993,7 @@ describe('Group Call', function() {

expect(oldMockCall.hangup).toHaveBeenCalled();
expect(newMockCall.answerWithCallFeeds).toHaveBeenCalled();
expect(groupCall.calls).toEqual(new Map([[
expect((groupCall as any).calls).toEqual(new Map([[
groupCall.room.getMember(FAKE_USER_ID_1)!,
new Map([[FAKE_DEVICE_ID_1, newMockCall]]),
]]));
Expand Down Expand Up @@ -1072,7 +1076,9 @@ describe('Group Call', function() {
// It takes a bit of time for the calls to get created
await sleep(10);

const call = groupCall.calls.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!.get(FAKE_DEVICE_ID_2)!;
const call = (groupCall as any).calls
.get(groupCall.room.getMember(FAKE_USER_ID_2)!)!
.get(FAKE_DEVICE_ID_2)!;
call.getOpponentMember = () => ({ userId: call.invitee }) as RoomMember;
call.onNegotiateReceived({
getContent: () => ({
Expand Down
2 changes: 2 additions & 0 deletions src/webrtc/call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -656,6 +656,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap

this.feeds.push(new CallFeed({
client: this.client,
call: this,
roomId: this.roomId,
userId,
deviceId: this.getOpponentDeviceId(),
Expand Down Expand Up @@ -699,6 +700,7 @@ export class MatrixCall extends TypedEventEmitter<CallEvent, CallEventHandlerMap

this.feeds.push(new CallFeed({
client: this.client,
call: this,
roomId: this.roomId,
audioMuted: false,
videoMuted: false,
Expand Down
34 changes: 34 additions & 0 deletions src/webrtc/callFeed.ts
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import { MatrixClient } from "../client";
import { RoomMember } from "../models/room-member";
import { logger } from "../logger";
import { TypedEventEmitter } from "../models/typed-event-emitter";
import { CallEvent, CallState, MatrixCall } from "./call";

const POLLING_INTERVAL = 200; // ms
export const SPEAKING_THRESHOLD = -60; // dB
Expand All @@ -40,13 +41,18 @@ export interface ICallFeedOpts {
* Whether or not the remote SDPStreamMetadata says video is muted
*/
videoMuted: boolean;
/**
* The MatrixCall which is the source of this CallFeed
*/
call?: MatrixCall;
}

export enum CallFeedEvent {
NewStream = "new_stream",
MuteStateChanged = "mute_state_changed",
LocalVolumeChanged = "local_volume_changed",
VolumeChanged = "volume_changed",
ConnectedChanged = "connected_changed",
Speaking = "speaking",
Disposed = "disposed",
}
Expand All @@ -56,6 +62,7 @@ type EventHandlerMap = {
[CallFeedEvent.MuteStateChanged]: (audioMuted: boolean, videoMuted: boolean) => void;
[CallFeedEvent.LocalVolumeChanged]: (localVolume: number) => void;
[CallFeedEvent.VolumeChanged]: (volume: number) => void;
[CallFeedEvent.ConnectedChanged]: (connected: boolean) => void;
[CallFeedEvent.Speaking]: (speaking: boolean) => void;
[CallFeedEvent.Disposed]: () => void;
};
Expand All @@ -69,6 +76,7 @@ export class CallFeed extends TypedEventEmitter<CallFeedEvent, EventHandlerMap>
public speakingVolumeSamples: number[];

private client: MatrixClient;
private call?: MatrixCall;
private roomId?: string;
private audioMuted: boolean;
private videoMuted: boolean;
Expand All @@ -81,11 +89,13 @@ export class CallFeed extends TypedEventEmitter<CallFeedEvent, EventHandlerMap>
private speaking = false;
private volumeLooperTimeout?: ReturnType<typeof setTimeout>;
private _disposed = false;
private _connected = false;

public constructor(opts: ICallFeedOpts) {
super();

this.client = opts.client;
this.call = opts.call;
this.roomId = opts.roomId;
this.userId = opts.userId;
this.deviceId = opts.deviceId;
Expand All @@ -101,6 +111,21 @@ export class CallFeed extends TypedEventEmitter<CallFeedEvent, EventHandlerMap>
if (this.hasAudioTrack) {
this.initVolumeMeasuring();
}

if (opts.call) {
opts.call.addListener(CallEvent.State, this.onCallState);
this.onCallState(opts.call.state);
}
}

public get connected(): boolean {
// Local feeds are always considered connected
return this.isLocal() || this._connected;
}

private set connected(connected: boolean) {
this._connected = connected;
this.emit(CallFeedEvent.ConnectedChanged, connected);
}

private get hasAudioTrack(): boolean {
Expand Down Expand Up @@ -145,6 +170,14 @@ export class CallFeed extends TypedEventEmitter<CallFeedEvent, EventHandlerMap>
this.emit(CallFeedEvent.NewStream, this.stream);
};

private onCallState = (state: CallState): void => {
if (state === CallState.Connected) {
this.connected = true;
} else if (state === CallState.Connecting) {
this.connected = false;
}
};

/**
* Returns callRoom member
* @returns member of the callRoom
Expand Down Expand Up @@ -297,6 +330,7 @@ export class CallFeed extends TypedEventEmitter<CallFeedEvent, EventHandlerMap>
public dispose(): void {
clearTimeout(this.volumeLooperTimeout);
this.stream?.removeEventListener("addtrack", this.onAddTrack);
this.call?.removeListener(CallEvent.State, this.onCallState);
if (this.audioContext) {
this.audioContext = undefined;
this.analyser = undefined;
Expand Down
2 changes: 1 addition & 1 deletion src/webrtc/groupCall.ts
Original file line number Diff line number Diff line change
Expand Up @@ -168,11 +168,11 @@ export class GroupCall extends TypedEventEmitter<
public localCallFeed?: CallFeed;
public localScreenshareFeed?: CallFeed;
public localDesktopCapturerSourceId?: string;
public readonly calls = new Map<RoomMember, Map<string, MatrixCall>>();
public readonly userMediaFeeds: CallFeed[] = [];
public readonly screenshareFeeds: CallFeed[] = [];
public groupCallId: string;

private readonly calls = new Map<RoomMember, Map<string, MatrixCall>>(); // RoomMember -> device ID -> MatrixCall
private callHandlers = new Map<string, Map<string, ICallHandlers>>(); // User ID -> device ID -> handlers
private activeSpeakerLoopInterval?: ReturnType<typeof setTimeout>;
private retryCallLoopInterval?: ReturnType<typeof setTimeout>;
Expand Down

0 comments on commit 76b255b

Please sign in to comment.