mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-19 05:55:34 +09:00
fix(voice): judge H.264 hardware support by negotiated format (#2680)
This commit is contained in:
1 parent
81fd8c9aad
commit
67e01be34a
6 files changed
+429
-28
No files matched your search
@@ -1,11 +1,38 @@
|
||||
// @vitest-environment happy-dom
|
||||
// SPDX-License-Identifier: AGPL-3.0-or-later
|
||||
|
||||
import {findStalledVideoEncoder} from '@app/features/voice/engine/voice_screen_share_manager/shared';
|
||||
import {describe, expect, test, vi} from 'vitest';
|
||||
import {
|
||||
findStalledVideoEncoder,
|
||||
scheduleScreenShareEncoderVerification,
|
||||
shouldTriggerSoftwareEncoderWarning,
|
||||
} from '@app/features/voice/engine/voice_screen_share_manager/shared';
|
||||
import SoftwareEncoderWarning from '@app/features/voice/state/SoftwareEncoderWarning';
|
||||
import VoiceSettings from '@app/features/voice/state/VoiceSettings';
|
||||
import {afterEach, beforeEach, describe, expect, test, vi} from 'vitest';
|
||||
|
||||
vi.mock('@app/features/voice/utils/VideoQualityEntitlement', () => ({hasHigherVideoQuality: () => false}));
|
||||
|
||||
let h264Acceleration = 'hardware';
|
||||
const markSoftwareEncodeObserved = vi.fn();
|
||||
|
||||
vi.mock('@app/features/voice/utils/CodecCapabilityDetector', () => ({
|
||||
adjustScreenShareEncodingForCodec: (encoding: unknown) => encoding,
|
||||
getCodecCapabilityReport: () => ({
|
||||
vp8: {hardwareAccelerated: 'software'},
|
||||
vp9: {hardwareAccelerated: 'software'},
|
||||
h264: {hardwareAccelerated: h264Acceleration},
|
||||
h265: {hardwareAccelerated: 'software'},
|
||||
av1: {hardwareAccelerated: 'software'},
|
||||
}),
|
||||
markScreenShareCodecSoftwareEncodeObserved: (codec: string) => markSoftwareEncodeObserved(codec),
|
||||
resolveVideoPublishCodecPolicy: (requested: string) => ({
|
||||
allowed: [requested],
|
||||
requested,
|
||||
primary: requested,
|
||||
backupCodec: false,
|
||||
}),
|
||||
}));
|
||||
|
||||
function makeStats(entries: ReadonlyArray<Record<string, unknown>>): RTCStatsReport {
|
||||
return new Map(entries.map((entry) => [entry.id as string, entry])) as unknown as RTCStatsReport;
|
||||
}
|
||||
@@ -59,3 +86,72 @@ describe('findStalledVideoEncoder', () => {
|
||||
expect(findStalledVideoEncoder(stats, 'h264')?.sourceFrames).toBe(240);
|
||||
});
|
||||
});
|
||||
|
||||
describe('the screen share encoder verification', () => {
|
||||
function openH264Stats(): RTCStatsReport {
|
||||
return makeStats([
|
||||
CODEC_REPORT,
|
||||
SOURCE_REPORT,
|
||||
outboundReport({
|
||||
active: true,
|
||||
framesEncoded: 120,
|
||||
framesSent: 120,
|
||||
encoderImplementation: 'OpenH264',
|
||||
powerEfficientEncoder: false,
|
||||
}),
|
||||
]);
|
||||
}
|
||||
|
||||
async function verifyOpenH264Share(): Promise<void> {
|
||||
scheduleScreenShareEncoderVerification(async () => openH264Stats(), 'h264');
|
||||
await vi.advanceTimersByTimeAsync(2500);
|
||||
}
|
||||
|
||||
beforeEach(() => {
|
||||
vi.useFakeTimers();
|
||||
h264Acceleration = 'hardware';
|
||||
markSoftwareEncodeObserved.mockClear();
|
||||
SoftwareEncoderWarning.reset();
|
||||
});
|
||||
|
||||
afterEach(() => {
|
||||
vi.useRealTimers();
|
||||
vi.restoreAllMocks();
|
||||
SoftwareEncoderWarning.reset();
|
||||
});
|
||||
|
||||
test('records a software session verdict when the encoder turns out to be OpenH264', async () => {
|
||||
await verifyOpenH264Share();
|
||||
expect(markSoftwareEncodeObserved).toHaveBeenCalledWith('h264');
|
||||
});
|
||||
|
||||
test('warns about the software encoder while the capability layer still claims hardware', async () => {
|
||||
await verifyOpenH264Share();
|
||||
expect(SoftwareEncoderWarning.showWarning).toBe(true);
|
||||
});
|
||||
|
||||
test('does not warn once the session verdict says the codec encodes in software', async () => {
|
||||
h264Acceleration = 'software';
|
||||
await verifyOpenH264Share();
|
||||
expect(SoftwareEncoderWarning.showWarning).toBe(false);
|
||||
expect(markSoftwareEncodeObserved).toHaveBeenCalledWith('h264');
|
||||
});
|
||||
|
||||
test('records no verdict when the user asked for the software encoder', async () => {
|
||||
vi.spyOn(VoiceSettings, 'getScreenShareEncoderMode').mockReturnValue('software');
|
||||
await verifyOpenH264Share();
|
||||
expect(markSoftwareEncodeObserved).not.toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
describe('the software encoder warning gate', () => {
|
||||
test('stays quiet once the session verdict says the codec encodes in software', () => {
|
||||
h264Acceleration = 'software';
|
||||
expect(shouldTriggerSoftwareEncoderWarning('h264')).toBe(false);
|
||||
});
|
||||
|
||||
test('still speaks up while the capability layer claims hardware', () => {
|
||||
h264Acceleration = 'hardware';
|
||||
expect(shouldTriggerSoftwareEncoderWarning('h264')).toBe(true);
|
||||
});
|
||||
});
|
||||
@@ -9,6 +9,7 @@ import VoiceSettings from '@app/features/voice/state/VoiceSettings';
|
||||
import {
|
||||
adjustScreenShareEncodingForCodec,
|
||||
getCodecCapabilityReport,
|
||||
markScreenShareCodecSoftwareEncodeObserved,
|
||||
resolveVideoPublishCodecPolicy,
|
||||
type VideoPublishCodecPolicy,
|
||||
} from '@app/features/voice/utils/CodecCapabilityDetector';
|
||||
@@ -681,7 +682,11 @@ export function scheduleScreenShareEncoderVerification(
|
||||
powerEfficientEncoder: encoder.powerEfficientEncoder,
|
||||
expectedHardware,
|
||||
});
|
||||
if (shouldTriggerSoftwareEncoderWarning(codec)) {
|
||||
const warnAboutSoftwareEncoder = shouldTriggerSoftwareEncoderWarning(codec);
|
||||
if (VoiceSettings.getScreenShareEncoderMode() !== 'software') {
|
||||
markScreenShareCodecSoftwareEncodeObserved(codec);
|
||||
}
|
||||
if (warnAboutSoftwareEncoder) {
|
||||
SoftwareEncoderWarning.triggerWarning(codec, encoder.implementation);
|
||||
}
|
||||
} else {
|
||||
|
||||
Reference in new issue
Block a user