Add minimum frame rate constraint for screen share

This commit is contained in:
automated-signal 2024-10-16 12:48:18 -05:00 committed by GitHub
parent ee1e15646b
commit a23d107343
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 56 additions and 20 deletions

8
package-lock.json generated
View file

@ -14,7 +14,7 @@
"@formatjs/icu-messageformat-parser": "2.3.0", "@formatjs/icu-messageformat-parser": "2.3.0",
"@formatjs/intl-localematcher": "0.2.32", "@formatjs/intl-localematcher": "0.2.32",
"@indutny/dicer": "0.3.2", "@indutny/dicer": "0.3.2",
"@indutny/mac-screen-share": "1.0.11", "@indutny/mac-screen-share": "1.0.13",
"@indutny/range-finder": "1.3.4", "@indutny/range-finder": "1.3.4",
"@indutny/simple-windows-notifications": "2.0.7", "@indutny/simple-windows-notifications": "2.0.7",
"@indutny/sneequals": "4.0.0", "@indutny/sneequals": "4.0.0",
@ -4086,9 +4086,9 @@
} }
}, },
"node_modules/@indutny/mac-screen-share": { "node_modules/@indutny/mac-screen-share": {
"version": "1.0.11", "version": "1.0.13",
"resolved": "https://registry.npmjs.org/@indutny/mac-screen-share/-/mac-screen-share-1.0.11.tgz", "resolved": "https://registry.npmjs.org/@indutny/mac-screen-share/-/mac-screen-share-1.0.13.tgz",
"integrity": "sha512-0UHiWyUBYn3VjjwpaS0nD6bppunyaTdFGXU84uGmzlV1R9RYcXQOF4EDCWQLpMlw4TieLOBvsh10gLEP116MPw==", "integrity": "sha512-fCOYWGaIuZAwfk/eUUjqPKge4+PKKCwTsuH9SSoaBZMP8IsWQtyyrTVpeuq84oDren4b9EUgRGgh2t950sQA0w==",
"hasInstallScript": true, "hasInstallScript": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {

View file

@ -98,7 +98,7 @@
"@formatjs/icu-messageformat-parser": "2.3.0", "@formatjs/icu-messageformat-parser": "2.3.0",
"@formatjs/intl-localematcher": "0.2.32", "@formatjs/intl-localematcher": "0.2.32",
"@indutny/dicer": "0.3.2", "@indutny/dicer": "0.3.2",
"@indutny/mac-screen-share": "1.0.11", "@indutny/mac-screen-share": "1.0.13",
"@indutny/range-finder": "1.3.4", "@indutny/range-finder": "1.3.4",
"@indutny/simple-windows-notifications": "2.0.7", "@indutny/simple-windows-notifications": "2.0.7",
"@indutny/sneequals": "4.0.0", "@indutny/sneequals": "4.0.0",

View file

@ -18,6 +18,8 @@ import { strictAssert } from './assert';
import { explodePromise } from './explodePromise'; import { explodePromise } from './explodePromise';
import { isNotNil } from './isNotNil'; import { isNotNil } from './isNotNil';
import { drop } from './drop'; import { drop } from './drop';
import { SECOND } from './durations';
import { isOlderThan } from './timestamp';
// Chrome-only API for now, thus a declaration: // Chrome-only API for now, thus a declaration:
declare class MediaStreamTrackGenerator extends MediaStreamTrack { declare class MediaStreamTrackGenerator extends MediaStreamTrack {
@ -176,19 +178,26 @@ export class DesktopCapturer {
liveCapturers.add(this); liveCapturers.add(this);
try { try {
const stream = await navigator.mediaDevices.getDisplayMedia({ const stream = await navigator.mediaDevices.getDisplayMedia({
video: { video: true,
width: { });
max: REQUESTED_SCREEN_SHARE_WIDTH,
ideal: REQUESTED_SCREEN_SHARE_WIDTH, const videoTrack = stream.getVideoTracks()[0];
}, strictAssert(videoTrack, 'videoTrack does not exist');
height: {
max: REQUESTED_SCREEN_SHARE_HEIGHT, // Apply constraints and ensure that there is at least 1 frame per second.
ideal: REQUESTED_SCREEN_SHARE_HEIGHT, await videoTrack.applyConstraints({
}, width: {
frameRate: { max: REQUESTED_SCREEN_SHARE_WIDTH,
max: REQUESTED_SCREEN_SHARE_FRAMERATE, ideal: REQUESTED_SCREEN_SHARE_WIDTH,
ideal: REQUESTED_SCREEN_SHARE_FRAMERATE, },
}, height: {
max: REQUESTED_SCREEN_SHARE_HEIGHT,
ideal: REQUESTED_SCREEN_SHARE_HEIGHT,
},
frameRate: {
min: 1,
max: REQUESTED_SCREEN_SHARE_FRAMERATE,
ideal: REQUESTED_SCREEN_SHARE_FRAMERATE,
}, },
}); });
@ -222,6 +231,20 @@ export class DesktopCapturer {
let isRunning = false; let isRunning = false;
let lastFrame: VideoFrame | undefined;
let lastFrameSentAt = 0;
let frameRepeater: NodeJS.Timeout | undefined;
const cleanup = () => {
lastFrame?.close();
if (frameRepeater != null) {
clearInterval(frameRepeater);
}
frameRepeater = undefined;
lastFrame = undefined;
};
const stream = new macScreenShare.Stream({ const stream = new macScreenShare.Stream({
width: REQUESTED_SCREEN_SHARE_WIDTH, width: REQUESTED_SCREEN_SHARE_WIDTH,
height: REQUESTED_SCREEN_SHARE_HEIGHT, height: REQUESTED_SCREEN_SHARE_HEIGHT,
@ -230,6 +253,17 @@ export class DesktopCapturer {
onStart: () => { onStart: () => {
isRunning = true; isRunning = true;
// Repeat last frame every second to match "min" constraint above.
frameRepeater = setInterval(() => {
if (isRunning && track.readyState !== 'ended' && lastFrame != null) {
if (isOlderThan(lastFrameSentAt, SECOND)) {
drop(writer.write(lastFrame.clone()));
}
} else {
cleanup();
}
}, SECOND);
this.options.onMediaStream(mediaStream); this.options.onMediaStream(mediaStream);
}, },
onStop() { onStop() {
@ -253,13 +287,15 @@ export class DesktopCapturer {
return; return;
} }
const videoFrame = new VideoFrame(frame, { lastFrame?.close();
lastFrameSentAt = Date.now();
lastFrame = new VideoFrame(frame, {
format: 'NV12', format: 'NV12',
codedWidth: width, codedWidth: width,
codedHeight: height, codedHeight: height,
timestamp: 0, timestamp: 0,
}); });
drop(writer.write(videoFrame)); drop(writer.write(lastFrame.clone()));
}, },
}); });