Don't auto-open expressly closed videos + other fixes

* If a user expressly closes a webcam (by clicking the 'X' button),
  record this intent so that the webcam will not auto-open in case the
  "auto-open my viewer's camera" happens again. Only clear the expressly
  close intent when the user expressly clicks the video button on the
  Who List to open someone's camera back up.
* Fix some bugs around booting and muting from cameras:
  * If you boot someone off your camera, you can not open THEIR camera
    anymore (similar to muting them)
  * When opening a user who auto-opens your camera back: do not attach
    your local video if you are an Admin and you have previously
    muted/booted that user from your camera.
  * Draw the slash mark over videos that you can not re-open because you
    had booted that user off your camera.
This commit is contained in:
Noah 2023-10-10 18:43:03 -07:00
parent 802fab3862
commit 30c5538ce6
2 changed files with 56 additions and 8 deletions

View File

@ -219,6 +219,18 @@ export default {
// a camera, the icon changes to a spinner for a few seconds to see
// whether the video goes on to open.
openTimeouts: {}, // map usernames to timeouts
// Map of usernames whose cameras were expressly closed by us.
// Example: we have mutualOpen enabled, someone opens our cam
// so we open theirs back, and then we expressly 'X' out and
// close their camera. If they close and re-open ours, we don't
// want to auto-open their cam back because we had previously
// closed out of it manually.
//
// Usernames are added when we 'X' out of their video,
// and usernames are removed when we expressly re-open their
// video (e.g., by clicking their Who List video button).
expresslyClosed: {}, // bool per username
},
// Chat history.
@ -1390,6 +1402,16 @@ export default {
pc.ontrack = event => {
const stream = event.streams[0];
// Had we expressly closed this user's cam before? e.g.: if we have auto-open their
// video enabled, and we 'X' out, and they reopen ours - we may be receiving their
// video right now. If we had expressly closed it, do not accept their video
// and hang up the connection.
if (this.WebRTC.expresslyClosed[username]) {
if (!isOfferer) {
return;
}
}
// We've received a video! If we had an "open camera spinner timeout",
// clear it before it expires.
if (this.WebRTC.openTimeouts[username] != undefined) {
@ -1457,7 +1479,12 @@ export default {
// is also the only way that iPads/iPhones/Safari browsers can make a call
// (two-way video is the only option for them; send-only/receive-only channels seem
// not to work in Safari).
if (isOfferer && (this.whoMap[username].video & this.VideoFlag.MutualOpen) && this.webcam.active) {
if (isOfferer &&
(this.whoMap[username].video & this.VideoFlag.MutualOpen) // They auto-open us
&& this.webcam.active // Our camera is active (to add it)
&& !this.isBooted(username) // We had not booted them off ours before
&& !this.isMutedUser(username) // We had not muted them before
) {
let stream = this.webcam.stream;
stream.getTracks().forEach(track => {
pc.addTrack(track, stream)
@ -1503,7 +1530,7 @@ export default {
// Add the new ICE candidate.
pc.addIceCandidate(candidate).catch(e => {
this.ChatClient(`addIceCandidate: ${e}`);
console.error(`addIceCandidate: ${e}`);
});
},
onSDP(msg) {
@ -2002,11 +2029,17 @@ export default {
}
// If we have muted the target, we shouldn't view their video.
if (this.isMutedUser(user.username)) {
if (this.isMutedUser(user.username) && !this.isOp) {
this.ChatClient(`You have muted <strong>${user.username}</strong> and so should not see their camera.`);
return;
}
// If we have booted the target off our cam, we shouldn't view their video.
if (this.isBooted(user.username) && !this.isOp) {
this.ChatClient(`You had kicked <strong>${user.username}</strong> off your camera and so it wouldn't be right to still watch their camera.`);
return;
}
// Is the target user NSFW? Go thru the modal.
let dontShowAgain = LocalStorage.get("skip-nsfw-modal") === true;
if ((user.video & this.VideoFlag.NSFW) && !dontShowAgain && !force) {
@ -2015,6 +2048,10 @@ export default {
return;
}
// If the local user had expressly closed this user's camera before, forget
// this action because the user now is expressly OPENING this camera on purpose.
delete(this.WebRTC.expresslyClosed[user.username]);
// Debounce so we don't spam too much for the same user.
if (this.WebRTC.debounceOpens[user.username]) return;
this.WebRTC.debounceOpens[user.username] = true;
@ -2028,7 +2065,7 @@ export default {
}
// If this user requests mutual viewership...
if (this.isVideoNotAllowed(user)) {
if (this.isVideoNotAllowed(user) && !this.isOp) {
this.ChatClient(
`<strong>${user.username}</strong> has requested that you should share your own camera too before opening theirs.`
);
@ -2121,6 +2158,14 @@ export default {
// Inform backend we have closed it.
this.sendWatch(username, false);
},
expresslyCloseVideo(username, name) {
// Like closeVideo but communicates the user's intent to expressly
// close the video for a user. e.g. they clicked the 'X' icon to
// close it out. As opposed to a user went off camera and were closed
// out automatically.
this.WebRTC.expresslyClosed[username] = true;
return this.closeVideo(username, name);
},
closeOpenVideos() {
// Close all videos open of other users.
for (let username of Object.keys(this.WebRTC.streams)) {
@ -2218,7 +2263,7 @@ export default {
}
// We have muted them and it wouldn't be appropriate to still watch their video but not get their messages.
if (this.isMutedUser(user.username)) {
if (this.isMutedUser(user.username) || this.isBooted(user.username)) {
return true;
}
@ -2270,9 +2315,9 @@ export default {
this.sendBoot(username);
this.WebRTC.booted[username] = true;
// Close the WebRTC peer connection.
// Close the WebRTC peer connections.
if (this.WebRTC.pc[username] != undefined) {
this.closeVideo(username, "answerer");
this.closeVideo(username);
}
// Remove them from our list.
@ -3653,7 +3698,7 @@ export default {
@reopen-video="openVideoByUsername"
@mute-video="muteVideo"
@popout="popoutVideo"
@close-video="closeVideo"
@close-video="expresslyCloseVideo"
@set-volume="setVideoVolume">
</VideoFeed>
@ -3952,6 +3997,7 @@ export default {
:website-url="config.website"
:is-dnd="isUsernameDND(u.username)"
:is-muted="isMutedUser(u.username)"
:is-booted="isBooted(u.username)"
:is-op="isOp"
:is-video-not-allowed="isVideoNotAllowed(u)"
:video-icon-class="webcamIconClass(u)"
@ -3973,6 +4019,7 @@ export default {
:website-url="config.website"
:is-dnd="isUsernameDND(username)"
:is-muted="isMutedUser(username)"
:is-booted="isBooted(u.username)"
:is-op="isOp"
:is-video-not-allowed="isVideoNotAllowed(u)"
:video-icon-class="webcamIconClass(u)"

View File

@ -8,6 +8,7 @@ export default {
websiteUrl: String, // Base URL to website (for profile/avatar URLs)
isDnd: Boolean, // user is not accepting DMs
isMuted: Boolean, // user is muted by current user
isBooted: Boolean, // user is booted by current user
vipConfig: Object, // VIP config settings for BareRTC
isOp: Boolean, // current user is operator (can always DM)
isVideoNotAllowed: Boolean, // whether opening this camera is not allowed