mirror of
https://github.com/fluxerapp/fluxer
synced 2026-10-18 21:45:31 +09:00
feat(voice): drive screen share quality from viewer demand (#2421)
This commit is contained in:
1 parent
66517c925b
commit
2426a5769d
5 files changed
+316
-40
No files matched your search
@@ -18,6 +18,10 @@ import {
|
||||
type ScreenSharePublicationOperation,
|
||||
ScreenShareWatchErrorCode,
|
||||
} from '@app/features/voice/state/ScreenShareWatchFailures';
|
||||
import {
|
||||
clearScreenShareViewerDemand,
|
||||
resolveScreenSharePublicationVideoRequest,
|
||||
} from '@app/features/voice/utils/ScreenShareSubscriptionPolicy';
|
||||
import type {RemoteParticipant, RemoteTrackPublication, Room} from 'livekit-client';
|
||||
import {VideoQuality} from 'livekit-client';
|
||||
|
||||
@@ -30,6 +34,13 @@ const qualityMap: Record<VoiceMediaGraphVideoQuality, VideoQuality> = {
|
||||
high: VideoQuality.HIGH,
|
||||
};
|
||||
|
||||
const graphQualityMap = new Map<VideoQuality, VoiceMediaGraphVideoQuality>(
|
||||
Object.entries(qualityMap).map(([graphQuality, videoQuality]): [VideoQuality, VoiceMediaGraphVideoQuality] => [
|
||||
videoQuality,
|
||||
graphQuality as VoiceMediaGraphVideoQuality,
|
||||
]),
|
||||
);
|
||||
|
||||
export class ScreenShareSubscriptionManager extends Store {
|
||||
private room: Room | null = null;
|
||||
private observers = new Map<string, IntersectionObserver>();
|
||||
@@ -44,6 +55,7 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
};
|
||||
|
||||
setRoom(room: Room | null): void {
|
||||
clearScreenShareViewerDemand();
|
||||
this.update(() => {
|
||||
this.room = room;
|
||||
});
|
||||
@@ -292,10 +304,17 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
participantIdentity: string,
|
||||
publication: RemoteTrackPublication,
|
||||
quality: VoiceMediaGraphVideoQuality,
|
||||
): boolean {
|
||||
return this.runPublicationOperation(participantIdentity, publication, 'setVideoQuality', () => {
|
||||
publication.setVideoQuality(qualityMap[quality]);
|
||||
): VoiceMediaGraphVideoQuality | null {
|
||||
const request = resolveScreenSharePublicationVideoRequest(publication, qualityMap[quality]);
|
||||
const applied = this.runPublicationOperation(participantIdentity, publication, request.operation, () => {
|
||||
if (request.operation === 'setVideoDimensions') {
|
||||
publication.setVideoDimensions(request.dimensions);
|
||||
return;
|
||||
}
|
||||
publication.setVideoQuality(request.quality);
|
||||
});
|
||||
if (!applied) return null;
|
||||
return graphQualityMap.get(request.quality) ?? null;
|
||||
}
|
||||
|
||||
private createObserver(participantIdentity: string, element: HTMLElement): IntersectionObserver {
|
||||
@@ -400,15 +419,16 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
publication: RemoteTrackPublication,
|
||||
enabled: boolean,
|
||||
quality: VoiceMediaGraphVideoQuality,
|
||||
): boolean {
|
||||
): VoiceMediaGraphVideoQuality | null {
|
||||
const subscribedApplied = this.runPublicationOperation(participantIdentity, publication, 'setSubscribed', () => {
|
||||
publication.setSubscribed(true);
|
||||
});
|
||||
const enabledApplied = this.runPublicationOperation(participantIdentity, publication, 'setEnabled', () => {
|
||||
publication.setEnabled(enabled);
|
||||
});
|
||||
const qualityApplied = this.applyQuality(participantIdentity, publication, quality);
|
||||
return subscribedApplied && enabledApplied && qualityApplied;
|
||||
const appliedQuality = this.applyQuality(participantIdentity, publication, quality);
|
||||
if (!subscribedApplied || !enabledApplied) return null;
|
||||
return appliedQuality;
|
||||
}
|
||||
|
||||
private subscribePublication(
|
||||
@@ -421,9 +441,12 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
return;
|
||||
}
|
||||
this.withActiveScreenSharePublications(participantIdentity, (publications, participant) => {
|
||||
let appliedQuality: VoiceMediaGraphVideoQuality | null = null;
|
||||
let applied = true;
|
||||
for (const publication of publications) {
|
||||
applied = this.applySubscribeOperations(participantIdentity, publication, enabled, quality) && applied;
|
||||
const publicationQuality = this.applySubscribeOperations(participantIdentity, publication, enabled, quality);
|
||||
if (publicationQuality === null) applied = false;
|
||||
else appliedQuality = publicationQuality;
|
||||
}
|
||||
for (const publication of ScreenSharePublicationMigration.getScreenSharePublicationsToDisable(participant)) {
|
||||
this.runPublicationOperation(participantIdentity, publication, 'setSubscribed', () => {
|
||||
@@ -433,7 +456,7 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
if (!applied) return;
|
||||
this.reportActualChanged(participantIdentity, {
|
||||
enabled,
|
||||
quality,
|
||||
quality: appliedQuality,
|
||||
trackSid: publications[0]?.trackSid ?? null,
|
||||
});
|
||||
logger.debug('Screen share subscribe command applied', {participantIdentity});
|
||||
@@ -510,10 +533,11 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
}
|
||||
this.pendingResubscribePulses.delete(participantIdentity);
|
||||
if (!this.isSubscriptionStillWanted(participantIdentity)) return;
|
||||
if (!this.applySubscribeOperations(participantIdentity, publication, enabled, quality)) return;
|
||||
const appliedQuality = this.applySubscribeOperations(participantIdentity, publication, enabled, quality);
|
||||
if (appliedQuality === null) return;
|
||||
this.reportActualChanged(participantIdentity, {
|
||||
enabled,
|
||||
quality,
|
||||
quality: appliedQuality,
|
||||
trackSid: publication.trackSid ?? null,
|
||||
});
|
||||
logger.debug('Screen share resubscribe pulse command applied after republish', {
|
||||
@@ -555,13 +579,16 @@ export class ScreenShareSubscriptionManager extends Store {
|
||||
|
||||
private setPublicationQuality(participantIdentity: string, quality: VoiceMediaGraphVideoQuality): void {
|
||||
this.withActiveScreenSharePublications(participantIdentity, (publications) => {
|
||||
let appliedQuality: VoiceMediaGraphVideoQuality | null = null;
|
||||
let applied = true;
|
||||
for (const publication of publications) {
|
||||
applied = this.applyQuality(participantIdentity, publication, quality) && applied;
|
||||
const publicationQuality = this.applyQuality(participantIdentity, publication, quality);
|
||||
if (publicationQuality === null) applied = false;
|
||||
else appliedQuality = publicationQuality;
|
||||
}
|
||||
if (!applied) return;
|
||||
this.reportActualChanged(participantIdentity, {quality});
|
||||
logger.debug('Quality updated', {participantIdentity, quality});
|
||||
this.reportActualChanged(participantIdentity, {quality: appliedQuality});
|
||||
logger.debug('Quality updated', {participantIdentity, quality: appliedQuality});
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user