Skip to content

Commit

Permalink
media: removeDeviceHandlerFactory VegaRtcManager init option
Browse files Browse the repository at this point in the history
This was added to support using the sdk in a node client, but now we
have two custom factories it makes sense to use them in the same way
  • Loading branch information
kevinwhereby committed Dec 10, 2024
1 parent 0b34a8a commit 1e95320
Show file tree
Hide file tree
Showing 6 changed files with 47 additions and 53 deletions.
3 changes: 1 addition & 2 deletions packages/core/src/redux/slices/rtcConnection/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import { createReactor, startAppListening } from "../../listenerMiddleware";
import { selectRemoteClients, streamStatusUpdated } from "../remoteParticipants";
import { StreamState } from "../../../RoomParticipant";
import { selectAppIsNodeSdk, selectAppIsActive, doAppStop } from "../app";
import { Safari12 as MediasoupDeviceHandler } from "mediasoup-client/lib/handlers/Safari12.js";

import {
selectIsCameraEnabled,
selectIsMicrophoneEnabled,
Expand Down Expand Up @@ -197,7 +197,6 @@ export const doConnectRtc = createAppThunk(() => (dispatch, getState) => {
vp9On: false,
h264On: false,
simulcastScreenshareOn: false,
deviceHandlerFactory: isNodeSdk ? MediasoupDeviceHandler.createFactory() : undefined,
},
});

Expand Down
10 changes: 8 additions & 2 deletions packages/media/src/utils/getHandler.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,14 @@
import { detectDevice } from "mediasoup-client";
import { BuiltinHandlerName } from "mediasoup-client/lib/types";
import { UAParser } from "ua-parser-js";

export const getHandler = (features: Record<string, boolean | undefined>) => {
let handlerName =
type SupportedDevice = BuiltinHandlerName | "NodeJS" | "Safari17" | undefined;
export const getHandler = (features: Record<string, boolean | undefined>): SupportedDevice => {
if (features.isNodeSdk) {
return "NodeJS";
}

let handlerName: SupportedDevice =
detectDevice() || (/applecoremedia|applewebkit|safari/i.test(navigator.userAgent) ? "Safari17" : undefined);

if (handlerName === "Safari12" && typeof navigator === "object" && typeof navigator.userAgent === "string") {
Expand Down
1 change: 0 additions & 1 deletion packages/media/src/webrtc/RtcManagerDispatcher.ts
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,6 @@ export default class RtcManagerDispatcher {
webrtcProvider,
features,
eventClaim,
deviceHandlerFactory: features?.deviceHandlerFactory,
};
const isSfu = !!room.sfuServer;
if (this.currentManager) {
Expand Down
54 changes: 29 additions & 25 deletions packages/media/src/webrtc/VegaRtcManager/__tests__/index.spec.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import * as mediasoupClient from "mediasoup-client";
const mediasoupClient = jest.requireActual("mediasoup-client");

import VegaRtcManager from "../";

Expand All @@ -10,10 +10,18 @@ import WS from "jest-websocket-mock";
import Logger from "../../../utils/Logger";
import { setTimeout } from "timers/promises";

jest.mock("../../../utils/getHandler");
jest.mock("../../../utils/Safari17Handler");
const { getHandler } = jest.requireMock("../../../utils/getHandler");
const { Safari17 } = jest.requireMock("../../../utils/Safari17Handler");
jest.mock("mediasoup-client/lib/handlers/Safari12");
const { Safari12 } = jest.requireMock("mediasoup-client/lib/handlers/Safari12");
jest.mock("../../../utils/getHandler");
const { getHandler } = jest.requireMock("../../../utils/getHandler");

jest.mock("mediasoup-client", () => ({
...mediasoupClient,
Device: jest.fn(),
}));
const mediasoupClientMock = jest.requireMock("mediasoup-client");

const logger = new Logger();

Expand All @@ -24,7 +32,6 @@ jest.mock("webrtc-adapter", () => {
});

const originalNavigator = global.navigator;
const originalMediasoupDevice = mediasoupClient.Device;

describe("VegaRtcManager", () => {
let navigator: any;
Expand Down Expand Up @@ -67,16 +74,12 @@ describe("VegaRtcManager", () => {
value: navigator,
});

Object.defineProperty(mediasoupClient, "Device", {
value: jest.fn().mockImplementation(() => {
return {
load: jest.fn(),
rtpCapabilities: {},
createSendTransport: () => mockSendTransport,
createRecvTransport: () => new MockTransport(),
};
}),
});
mediasoupClientMock.Device.mockImplementation(() => ({
load: jest.fn(),
rtpCapabilities: {},
createSendTransport: () => mockSendTransport,
createRecvTransport: () => new MockTransport(),
}));

rtcManager = new VegaRtcManager({
selfId: helpers.randomString("client-"),
Expand All @@ -99,33 +102,33 @@ describe("VegaRtcManager", () => {
Object.defineProperty(global, "navigator", {
value: originalNavigator,
});
Object.defineProperty(mediasoupClient, "Device", {
value: originalMediasoupDevice,
});
});

describe("constructor", () => {
const selfId = helpers.randomString("client-");
const room = { name: helpers.randomString("/room-"), iceServers: {} };

it("handles custom device handler factories", () => {
const deviceHandlerFactory = function () {};
it("uses the custom Safari17 handler", () => {
const factory = jest.fn();
getHandler.mockImplementation(() => "Safari17");
Safari17.createFactory.mockImplementation(() => factory);

//eslint-disable-next-line no-new
new VegaRtcManager({
selfId,
room,
emitter,
serverSocket,
webrtcProvider,
deviceHandlerFactory,
});
expect(mediasoupClient.Device).toHaveBeenCalledWith({ handlerFactory: deviceHandlerFactory });

expect(mediasoupClientMock.Device).toHaveBeenCalledWith({ handlerFactory: factory });
});

it("uses the custom Safari17 handler", () => {
getHandler.mockImplementation(() => "Safari17");
it("uses the nodejs handler when isNodeJs", () => {
getHandler.mockImplementation(() => "NodeJS");
const factory = jest.fn();
Safari17.createFactory.mockImplementation(() => factory);
Safari12.createFactory.mockImplementation(() => factory);

//eslint-disable-next-line no-new
new VegaRtcManager({
Expand All @@ -134,9 +137,10 @@ describe("VegaRtcManager", () => {
emitter,
serverSocket,
webrtcProvider,
features: { isNodeSdk: true },
});

expect(mediasoupClient.Device).toHaveBeenCalledWith({ handlerFactory: factory });
expect(mediasoupClientMock.Device).toHaveBeenCalledWith({ handlerFactory: factory });
});
});

Expand Down
19 changes: 9 additions & 10 deletions packages/media/src/webrtc/VegaRtcManager/index.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { Device } from "mediasoup-client";
import adapterRaw from "webrtc-adapter";
import { v4 as uuidv4 } from "uuid";
// of the provided ones, this seems to work best in NodeJS
import { Safari12 as NodeDeviceHandler } from "mediasoup-client/lib/handlers/Safari12.js";

import rtcManagerEvents from "../rtcManagerEvents";
import rtcStats from "../rtcStatsService";
Expand Down Expand Up @@ -99,7 +101,6 @@ export default class VegaRtcManager implements RtcManager {
webrtcProvider,
features,
eventClaim,
deviceHandlerFactory,
}: {
selfId: any;
room: any;
Expand All @@ -108,7 +109,6 @@ export default class VegaRtcManager implements RtcManager {
webrtcProvider: any;
features?: any;
eventClaim?: string;
deviceHandlerFactory?: any;
}) {
const { session, iceServers, sfuServer, mediaserverConfigTtlSeconds } = room;

Expand All @@ -128,15 +128,14 @@ export default class VegaRtcManager implements RtcManager {

const handlerName = getHandler(this._features);

if (handlerName === "Safari17" && !deviceHandlerFactory) {
// Patched Safari12 handler to fix simulcast bandwith limitsp
deviceHandlerFactory = Safari17.createFactory();
}

if (deviceHandlerFactory) {
this._mediasoupDevice = new Device({ handlerFactory: deviceHandlerFactory });
if (handlerName === "Safari17") {
// Patched Safari12 handler to fix simulcast bandwith limits
this._mediasoupDevice = new Device({ handlerFactory: Safari17.createFactory() });
} else if (handlerName === "NodeJS") {
this._mediasoupDevice = new Device({ handlerFactory: NodeDeviceHandler.createFactory() });
} else {
this._mediasoupDevice = new Device({ handlerName: handlerName as BuiltinHandlerName });
console.warn("handlerName", handlerName, features);
this._mediasoupDevice = new Device({ handlerName });
}

this._routerRtpCapabilities = null;
Expand Down
13 changes: 0 additions & 13 deletions packages/media/tests/webrtc/RtcManagerDispatcher.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,19 +68,6 @@ describe("RtcManagerDispatcher", () => {
const rtcManager = mockEmitRoomJoined({ sfuServer: { url: helpers.randomString("sfu-") + ":443" } });
expect(rtcManager).toBeInstanceOf(VegaRtcManager);
});
it("allows custom device handler factories when sfuServer", () => {
features.deviceHandlerFactory = function () {};
jest.mock("../../src/webrtc/VegaRtcManager", () => {
return {
default: jest.fn(),
};
});
const rtcManager = mockEmitRoomJoined({ sfuServer: { url: helpers.randomString("sfu-") + ":443" } });
expect(rtcManager).toBeInstanceOf(VegaRtcManager);
expect(mediasoupClient.Device).toHaveBeenCalledWith({
handlerFactory: features.deviceHandlerFactory,
});
});

it("emits nothing when error is set", () => {
const rtcManager = mockEmitRoomJoined({ error: "yo" });
Expand Down

0 comments on commit 1e95320

Please sign in to comment.