Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

chore(AVS): remove simulcast support [WPB-16287] #18798

Open
wants to merge 5 commits into
base: dev
Choose a base branch
from
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
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@
"@lexical/rich-text": "0.24.0",
"@mediapipe/tasks-vision": "0.10.21",
"@tanstack/react-virtual": "^3.13.0",
"@wireapp/avs": "10.0.5",
"@wireapp/avs": "9.10.16",
"@wireapp/avs-debugger": "0.0.7",
"@wireapp/commons": "5.4.1",
"@wireapp/core": "46.19.1",
Expand Down
2 changes: 1 addition & 1 deletion src/script/calling/Call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,7 @@ export class Call {
public currentPage: ko.Observable<number> = ko.observable(0);
public pages: ko.ObservableArray<Participant[]> = ko.observableArray();
public numberOfParticipantsInOnePage: number = 9;
public readonly maximizedParticipant: ko.Observable<Participant | null>;
readonly maximizedParticipant: ko.Observable<Participant | null>;
public readonly isActive: ko.PureComputed<boolean>;

private readonly audios: Record<string, {audioElement: HTMLAudioElement; stream: MediaStream}> = {};
Expand Down
13 changes: 2 additions & 11 deletions src/script/calling/CallState.ts
Original file line number Diff line number Diff line change
Expand Up @@ -70,9 +70,8 @@ export class CallState {
public readonly activeCalls: ko.PureComputed<Call[]>;
public readonly joinedCall: ko.PureComputed<Call | undefined>;
public readonly activeCallViewTab = ko.observable(CallViewTab.ALL);
public readonly hasAvailableScreensToShare: ko.PureComputed<boolean>;
public readonly isSpeakersViewActive: ko.PureComputed<boolean>;
public readonly isMaximisedViewActive: ko.PureComputed<boolean>;
readonly hasAvailableScreensToShare: ko.PureComputed<boolean>;
readonly isSpeakersViewActive: ko.PureComputed<boolean>;
public readonly viewMode = ko.observable<CallingViewMode>(CallingViewMode.MINIMIZED);
public readonly detachedWindow = ko.observable<Window | null>(null);
public readonly isScreenSharingSourceFromDetachedWindow = ko.observable<boolean>(false);
Expand All @@ -97,14 +96,6 @@ export class CallState {
});
this.isSpeakersViewActive = ko.pureComputed(() => this.activeCallViewTab() === CallViewTab.SPEAKERS);

this.isMaximisedViewActive = ko.pureComputed(() => {
const call = this.joinedCall();
if (!call) {
return false;
}
return call.maximizedParticipant() !== null;
});

this.hasAvailableScreensToShare = ko.pureComputed(
() => this.selectableScreens().length > 0 || this.selectableWindows().length > 0,
);
Expand Down
84 changes: 6 additions & 78 deletions src/script/calling/CallingRepository.ts
Original file line number Diff line number Diff line change
Expand Up @@ -43,15 +43,13 @@ import {
LOG_LEVEL,
QUALITY,
REASON,
RESOLUTION,
STATE as CALL_STATE,
VIDEO_STATE,
VSTREAMS,
Wcall,
WcallClient,
WcallMember,
} from '@wireapp/avs';
import {AvsDebugger} from '@wireapp/avs-debugger';
import {Runtime} from '@wireapp/commons';
import {WebAppEvents} from '@wireapp/webapp-events';

Expand Down Expand Up @@ -258,47 +256,14 @@ export class CallingRepository {

this.onChooseScreen = (deviceId: string) => {};

// Request the video streams whenever the mode changes to active speaker
ko.computed(() => {
const call = this.callState.joinedCall();
if (!call) {
return;
}
const isSpeakersViewActive = this.callState.isSpeakersViewActive();
if (isSpeakersViewActive) {
const videoQuality = call.activeSpeakers().length > 2 ? RESOLUTION.LOW : RESOLUTION.HIGH;

const speakes = call.activeSpeakers();
speakes.forEach(p => {
// This is a temporary solution. The SFT does not send a response when a track change has occurred.
// To prevent the wrong video from being briefly displayed, we introduce a timeout here.
p.isSwitchingVideoResolution(true);
window.setTimeout(() => {
p.isSwitchingVideoResolution(false);
}, 1000);
});

this.requestVideoStreams(call.conversation.qualifiedId, speakes, videoQuality);
}
});

// Request the video streams whenever toggle display maximised Participant.
ko.computed(() => {
const call = this.callState.joinedCall();
if (!call) {
return;
}
const maximizedParticipant = call.maximizedParticipant();
if (maximizedParticipant !== null) {
maximizedParticipant.isSwitchingVideoResolution(true);
// This is a temporary solution. The SFT does not send a response when a track change has occurred. To prevent
// the wrong video from being briefly displayed, we introduce a timeout here.
window.setTimeout(() => {
maximizedParticipant.isSwitchingVideoResolution(false);
}, 1000);
this.requestVideoStreams(call.conversation.qualifiedId, [maximizedParticipant], RESOLUTION.HIGH);
} else {
this.requestCurrentPageVideoStreams(call);
this.requestVideoStreams(call.conversation.qualifiedId, call.activeSpeakers());
}
});
}
Expand Down Expand Up @@ -1080,9 +1045,6 @@ export class CallingRepository {

try {
const mediaStream = await this.getMediaStream({audio: true, screen: true}, call.isGroupOrConference);
if ('contentHint' in mediaStream.getVideoTracks()[0]) {
mediaStream.getVideoTracks()[0].contentHint = 'detail';
}

// If the screen share is stopped by the os system or the browser, an "ended" event is triggered. We listen for
// this event to clean up the screen share state in this case.
Expand Down Expand Up @@ -1308,7 +1270,6 @@ export class CallingRepository {
const conversationIdStr = this.serializeQualifiedId(conversationId);
this.wCall?.end(this.wUser, conversationIdStr);
callingSubscriptions.removeCall(conversationId);
AvsDebugger.reset();
};

private readonly leaveMLSConference = async (conversationId: QualifiedId) => {
Expand Down Expand Up @@ -1405,47 +1366,24 @@ export class CallingRepository {
this.wCall?.reject(this.wUser, this.serializeQualifiedId(conversationId));
}

/**
* This method monitors every change in the call and is therefore the main method for handling video requests.
* These changes include mute/unmute, screen sharing, or camera switching, joining or leaving of participants, or...
* @param call
* @param newPage
*/
changeCallPage(call: Call, newPage: number): void {
call.currentPage(newPage);
if (!this.callState.isSpeakersViewActive() && !this.callState.isMaximisedViewActive()) {
if (!this.callState.isSpeakersViewActive()) {
this.requestCurrentPageVideoStreams(call);
}
}

/**
* This method queries streams for the participants who are displayed on the active page! This can include up to nine
* participants and is used when flipping pages or starting a call.
* @param call
*/
requestCurrentPageVideoStreams(call: Call): void {
const currentPageParticipants = call.pages()[call.currentPage()] ?? [];
const videoQuality: RESOLUTION = currentPageParticipants.length <= 2 ? RESOLUTION.HIGH : RESOLUTION.LOW;
this.requestVideoStreams(call.conversation.qualifiedId, currentPageParticipants, videoQuality);
const currentPageParticipants = call.pages()[call.currentPage()];
this.requestVideoStreams(call.conversation.qualifiedId, currentPageParticipants);
}

requestVideoStreams(conversationId: QualifiedId, participants: Participant[], videoQuality: RESOLUTION) {
if (participants.length === 0) {
return;
}
// Filter myself out and do not request my own stream.
const requestParticipants = participants.filter(p => !this.isSelfUser(p));
if (requestParticipants.length === 0) {
return;
}

requestVideoStreams(conversationId: QualifiedId, participants: Participant[]) {
const convId = this.serializeQualifiedId(conversationId);

const payload = {
clients: requestParticipants.map(participant => ({
clients: participants.map(participant => ({
clientid: participant.clientId,
userid: this.serializeQualifiedId(participant.user.qualifiedId),
quality: videoQuality,
})),
convid: convId,
};
Expand Down Expand Up @@ -1496,7 +1434,6 @@ export class CallingRepository {
const conversationIdStr = this.serializeQualifiedId(conversationId);
delete this.poorCallQualityUsers[conversationIdStr];
this.wCall?.end(this.wUser, conversationIdStr);
AvsDebugger.reset();
};

muteCall(call: Call, shouldMute: boolean, reason?: MuteState): void {
Expand Down Expand Up @@ -2408,8 +2345,6 @@ export class CallingRepository {
this.callState
.calls()
.forEach((call: Call) => this.wCall?.end(this.wUser, this.serializeQualifiedId(call.conversation.qualifiedId)));

AvsDebugger.reset();
this.wCall?.destroy(this.wUser);
}

Expand Down Expand Up @@ -2460,13 +2395,6 @@ export class CallingRepository {
PrimaryModal.show(PrimaryModal.type.ACKNOWLEDGE, modalOptions);
}

private isSelfUser(participant: Participant): boolean {
if (this.selfUser == null || this.selfClientId == null) {
return false;
}
return participant.doesMatchIds(this.selfUser.qualifiedId, this.selfClientId);
}

//##############################################################################
// Logging
//##############################################################################
Expand Down
19 changes: 1 addition & 18 deletions src/script/calling/Participant.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@
*/

import {QualifiedId} from '@wireapp/api-client/lib/user';
import ko, {computed, observable, pureComputed} from 'knockout';
import ko, {observable, pureComputed} from 'knockout';

import {VIDEO_STATE} from '@wireapp/avs';
import {AvsDebugger} from '@wireapp/avs-debugger';

import {matchQualifiedIds} from 'Util/QualifiedId';

Expand All @@ -40,7 +39,6 @@ export class Participant {
public readonly hasPausedVideo: ko.PureComputed<boolean>;
public readonly sharesScreen: ko.PureComputed<boolean>;
public readonly sharesCamera: ko.PureComputed<boolean>;
public readonly isSwitchingVideoResolution = observable(false);
public readonly startedScreenSharingAt = observable<number>(0);
public readonly isActivelySpeaking = observable(false);
public readonly isSendingVideo: ko.PureComputed<boolean>;
Expand Down Expand Up @@ -70,18 +68,6 @@ export class Participant {
this.isSendingVideo = pureComputed(() => {
return this.videoState() !== VIDEO_STATE.STOPPED;
});
this.isSwitchingVideoResolution(false);

computed(() => {
const stream = this.videoStream();

if (stream && stream.getVideoTracks().length > 0) {
if (AvsDebugger.hasTrack(this.user.id)) {
AvsDebugger.removeTrack(this.user.id);
}
AvsDebugger.addTrack(this.user.id, this.user.name(), stream.getVideoTracks()[0], this.sharesScreen());
}
});
}

public releaseBlurredVideoStream(): void {
Expand Down Expand Up @@ -156,9 +142,6 @@ export class Participant {
track.stop();
}
mediaStream.removeTrack(track);
if (track.kind == 'video' && AvsDebugger.hasTrack(this.user.id)) {
AvsDebugger.removeTrack(this.user.id);
}
});
}
}
27 changes: 0 additions & 27 deletions src/script/components/ConfigToolbar/ConfigToolbar.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ export function ConfigToolbar() {
const messageCountRef = useRef<number>(0); // For the message count
const [prefix, setPrefix] = useState('Message -'); // Prefix input
const wrapperRef = useRef(null);
const [avsDebuggerEnabled, setAvsDebuggerEnabled] = useState(!!window.wire?.app?.debug?.isEnabledAvsDebugger()); //

// Toggle config tool on 'cmd/ctrl + shift + 2'
useEffect(() => {
Expand Down Expand Up @@ -161,25 +160,6 @@ export function ConfigToolbar() {

useClickOutside(wrapperRef, () => setShowConfig(false));

const handleAvsEnable = (isChecked: boolean) => {
setAvsDebuggerEnabled(!!window.wire?.app?.debug?.enableAvsDebugger(isChecked));
};

const renderAvsSwitch = (value: boolean) => {
return (
<div style={{marginBottom: '10px'}}>
<label htmlFor="avs-debugger-checkbox" style={{display: 'block', fontWeight: 'bold'}}>
ENABLE AVS TRACK DEBUGGER
</label>
<Switch
id="avs-debugger-checkbox"
checked={avsDebuggerEnabled}
onToggle={isChecked => handleAvsEnable(isChecked)}
/>
</div>
);
};

if (!showConfig) {
return null;
}
Expand All @@ -193,18 +173,11 @@ export function ConfigToolbar() {
</h4>
<div>{renderConfig(configFeaturesState)}</div>

<hr />

<h3>Debug Functions</h3>

<Button onClick={() => window.wire?.app?.debug?.reconnectWebSocket()}>reconnectWebSocket</Button>
<Button onClick={() => window.wire?.app?.debug?.enablePressSpaceToUnmute()}>enablePressSpaceToUnmute</Button>
<Button onClick={() => window.wire?.app?.debug?.disablePressSpaceToUnmute()}>disablePressSpaceToUnmute</Button>

<div>{renderAvsSwitch(avsDebuggerEnabled)}</div>

<hr />

<h3>Message Automation</h3>
<Input
type="text"
Expand Down
34 changes: 12 additions & 22 deletions src/script/components/calling/GroupVideoGridTile.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -69,26 +69,16 @@ const GroupVideoGridTile: React.FC<GroupVideoGridTileProps> = ({
isMaximized,
onTileDoubleClick,
}) => {
const {
isMuted,
videoState,
handRaisedAt,
videoStream,
blurredVideoStream,
isActivelySpeaking,
isAudioEstablished,
isSwitchingVideoResolution,
} = useKoSubscribableChildren(participant, [
'isMuted',
'handRaisedAt',
'videoStream',
'blurredVideoStream',
'isActivelySpeaking',
'videoState',
'isAudioEstablished',
'isSwitchingVideoResolution',
]);

const {isMuted, videoState, handRaisedAt, videoStream, blurredVideoStream, isActivelySpeaking, isAudioEstablished} =
useKoSubscribableChildren(participant, [
'isMuted',
'handRaisedAt',
'videoStream',
'blurredVideoStream',
'isActivelySpeaking',
'videoState',
'isAudioEstablished',
]);
const {name} = useKoSubscribableChildren(participant?.user, ['name']);

const sharesScreen = videoState === VIDEO_STATE.SCREENSHARE;
Expand Down Expand Up @@ -233,7 +223,7 @@ const GroupVideoGridTile: React.FC<GroupVideoGridTileProps> = ({

{nameContainer}

{(hasPausedVideo || isSwitchingVideoResolution) && (
{hasPausedVideo && (
<div className="group-video-grid__pause-overlay">
<div className="background">
<div className="background-image"></div>
Expand All @@ -245,7 +235,7 @@ const GroupVideoGridTile: React.FC<GroupVideoGridTileProps> = ({
css={{fontsize: minimized ? '0.6875rem' : '0.875rem'}}
data-uie-name="status-video-paused"
>
{hasPausedVideo ? t('videoCallPaused') : t('videoCallParticipantConnecting')}
{t('videoCallPaused')}
</div>
{nameContainer}
</div>
Expand Down
Loading
Loading