Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 5 additions & 0 deletions .changeset/moody-experts-admire.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@whereby.com/media": minor
---

Fix Safari simulcast maxBitrate bug
3 changes: 3 additions & 0 deletions packages/media/jest.config.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@ export default buildConfig(__dirname, {
transform: {
"^.+\\.(j|t)sx?$": "ts-jest",
},
moduleNameMapper: {
"^mediasoup-client/lib/(.*)$": "<rootDir>/../../node_modules/mediasoup-client/lib/$1",
},
roots: ["<rootDir>"],
coverageDirectory: "test-report/unit-tests",
});
23 changes: 22 additions & 1 deletion packages/media/src/utils/__tests__/getMediasoupDevice.spec.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,23 @@
import { getMediasoupDeviceAsync } from "../getMediasoupDevice";
import { Safari17 } from "../../webrtc/VegaRtcManager/Safari17Handler";

jest.mock("mediasoup-client", () => ({
Device: jest.fn(),
detectDeviceAsync: jest.fn(),
}));

jest.mock("../../webrtc/VegaRtcManager/Safari17Handler")

const mediasoupClient = jest.requireMock("mediasoup-client");

const safari17UserAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/17.4 Safari/605.1.15";
const safari18UserAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/18.1.1 Safari/605.1.15";
const safari26UserAgent =
"Mozilla/5.0 (Macintosh; Intel Mac OS X 15_7_2) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0 Safari/605.1.15";
const safari26MobileUserAgent =
"Mozilla/5.0 (iPhone; CPU iPhone OS 18_7 like Mac OS X) AppleWebKit/605.1.15 (KHTML, like Gecko) Version/26.0.1 Mobile/15E148 Safari/604.1";

describe("getMediasoupClient", () => {
const features = {};
Expand Down Expand Up @@ -37,7 +45,9 @@ describe("getMediasoupClient", () => {
describe.each([
{ version: 17, userAgent: safari17UserAgent },
{ version: 18, userAgent: safari18UserAgent },
])("when the user agent version is $version", ({ userAgent }) => {
{ version: 26, userAgent: safari26UserAgent },
{ version: 26, userAgent: safari26MobileUserAgent },
])("when the safari user agent version is $version", ({ userAgent }) => {
beforeEach(() => {
(global as any).userAgent.mockReturnValue(userAgent);
});
Expand All @@ -47,6 +57,17 @@ describe("getMediasoupClient", () => {

expect(mediasoupClient.Device).toHaveBeenCalledWith({ handlerName: "Safari12" });
});

describe("and the safari17 handler is enabled", () => {
it("returns the Safari17 Handler", async () => {
const factory = jest.fn();
(Safari17.createFactory as jest.Mock).mockImplementationOnce(() => factory);

await getMediasoupDeviceAsync({ ...features, safari17HandlerOn: true });

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

Expand Down
10 changes: 9 additions & 1 deletion packages/media/src/utils/getMediasoupDevice.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
import { detectDeviceAsync, Device } from "mediasoup-client";
import { BuiltinHandlerName } from "mediasoup-client/lib/types";
import { Safari17 } from "../webrtc/VegaRtcManager/Safari17Handler";

type SupportedDevice = BuiltinHandlerName | "NodeJS" | undefined;
type SupportedDevice = BuiltinHandlerName | "NodeJS" | "Safari17" | undefined;
const SAFARI_17_REGEXP = new RegExp(
/^(?=.*\bSafari\/)(?!.*\b(?:Chrome|Chromium|CriOS|Edg|OPR)\b).*?\bVersion\/(?:1[8-9]|[2-9]\d|17\.(?:0\.(?:[1-9]\d*)|[1-9]\d*))\b/,
);
export const getMediasoupDeviceAsync = async (features: Record<string, boolean | undefined>): Promise<Device> => {
if (features.isNodeSdk) {
return new Device({ handlerName: "Safari12" });
Expand All @@ -16,5 +20,9 @@ export const getMediasoupDeviceAsync = async (features: Record<string, boolean |
handlerName = "Safari12";
}

if (features.safari17HandlerOn && handlerName === "Safari12" && SAFARI_17_REGEXP.test(navigator.userAgent)) {
return new Device({ handlerFactory: Safari17.createFactory() });
}

return new Device({ handlerName });
};
Loading