Changing the way we focus a video element.

Now, only one video element can be important.
This commit is contained in:
David Négrier 2021-06-15 14:45:01 +02:00
parent ac7fa164b6
commit 5cf5e0ce2b
12 changed files with 164 additions and 158 deletions

View file

@ -1,5 +1,6 @@
<script lang="typescript">
import {ScreenSharingLocalMedia} from "../../Stores/ScreenSharingStore";
import {videoFocusStore} from "../../Stores/VideoFocusStore";
function srcObject(node, stream) {
node.srcObject = stream;
@ -18,6 +19,6 @@
</script>
<div class="video-container {cssClass}" class:hide={!stream}>
<video class="myCamVideo" use:srcObject={stream} autoplay muted playsinline on:click={() => peer.importanceStore.toggle()}></video>
<div class="video-container {cssClass ? cssClass : ''}" class:hide={!stream}>
<video use:srcObject={stream} autoplay muted playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
</div>

View file

@ -1,5 +1,6 @@
<script lang="ts">
import {ScreenSharingPeer} from "../../WebRtc/ScreenSharingPeer";
import {videoFocusStore} from "../../Stores/VideoFocusStore";
export let peer: ScreenSharingPeer;
let streamStore = peer.streamStore;
@ -45,7 +46,7 @@
{#if $streamStore === null}
<i style="background-color: {getColorByString(name)};">{name}</i>
{/if}
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => peer.importanceStore.toggle()}></video>
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
</div>
<style lang="scss">

View file

@ -5,13 +5,13 @@
import reportImg from "./images/report.svg";
import blockSignImg from "./images/blockSign.svg";
import {DivImportance} from "../../WebRtc/LayoutManager";
import {videoFocusStore} from "../../Stores/VideoFocusStore";
export let peer: VideoPeer;
let streamStore = peer.streamStore;
let name = peer.userName;
let statusStore = peer.statusStore;
let constraintStore = peer.constraintsStore;
let importanceStore = peer.importanceStore;
constraintStore.subscribe((vl) => console.log('CONS', vl));
@ -62,17 +62,10 @@
<img alt="Report this user" src={reportImg}>
<span>Report/Block</span>
</button>
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => peer.importanceStore.toggle()}></video>
<video use:srcObject={$streamStore} autoplay playsinline on:click={() => videoFocusStore.toggleFocus(peer)}></video>
<img src={blockSignImg} class="block-logo" alt="Block">
{#if $constraintStore && $constraintStore.audio !== false}
<SoundMeterWidget stream={$streamStore}></SoundMeterWidget>
{/if}
</div>
<style lang="scss">
.video-container {
video {
width: 100%;
}
}
</style>

View file

@ -3,18 +3,23 @@
import {DivImportance} from "../../WebRtc/LayoutManager";
import Peer from "./Peer.svelte";
import {layoutStore} from "../../Stores/LayoutStore";
import {videoFocusStore} from "../../Stores/VideoFocusStore";
</script>
<div class="video-overlay">
<div class="main-section">
{#each [...$layoutStore.get(DivImportance.Important).values()] as peer (peer.uniqueId)}
<Peer peer={peer}></Peer>
{#each [...$layoutStore.values()] as peer (peer.uniqueId)}
{#if $videoFocusStore && peer === $videoFocusStore }
<Peer peer={peer}></Peer>
{/if}
{/each}
</div>
<aside class="sidebar">
{#each [...$layoutStore.get(DivImportance.Normal).values()] as peer (peer.uniqueId)}
<Peer peer={peer}></Peer>
{#each [...$layoutStore.values()] as peer (peer.uniqueId)}
{#if peer !== $videoFocusStore }
<Peer peer={peer}></Peer>
{/if}
{/each}
</aside>
<div class="chat-mode three-col" style="display: none;">

View file

@ -95,6 +95,7 @@ import {DEPTH_OVERLAY_INDEX} from "./DepthIndexes";
import {waScaleManager} from "../Services/WaScaleManager";
import {peerStore, screenSharingPeerStore} from "../../Stores/PeerStore";
import {EmoteManager} from "./EmoteManager";
import {videoFocusStore} from "../../Stores/VideoFocusStore";
export interface GameSceneInitInterface {
initPosition: PointInterface|null,
@ -647,6 +648,7 @@ export class GameScene extends DirtyScene implements CenterListener {
this.simplePeer = new SimplePeer(this.connection, !this.room.isPublic, this.playerName);
peerStore.connectToSimplePeer(this.simplePeer);
screenSharingPeerStore.connectToSimplePeer(this.simplePeer);
videoFocusStore.connectToSimplePeer(this.simplePeer);
this.GlobalMessageManager = new GlobalMessageManager(this.connection);
userMessageManager.setReceiveBanListener(this.bannedUser.bind(this));

View file

@ -1,26 +0,0 @@
import {VideoPeer} from "../WebRtc/VideoPeer";
import {Subscriber, Unsubscriber, writable} from "svelte/store";
import {RemotePeer, SimplePeer} from "../WebRtc/SimplePeer";
import {DivImportance} from "../WebRtc/LayoutManager";
export interface ImportanceStore {
subscribe: (this:void, run: Subscriber<DivImportance>, invalidate?: ((value?: DivImportance) => void | undefined)) => Unsubscriber,
toggle: () => void,
}
export function createImportanceStore(defaultImportance: DivImportance): ImportanceStore {
const { subscribe, set, update } = writable<DivImportance>(defaultImportance);
return {
subscribe,
toggle: () => {
update((importance) => {
if (importance === DivImportance.Important) {
return DivImportance.Normal;
} else {
return DivImportance.Important;
}
});
}
};
}

View file

@ -1,6 +1,5 @@
import {derived, get} from "svelte/store";
import {derived, get, writable} from "svelte/store";
import {ScreenSharingLocalMedia, screenSharingLocalMedia} from "./ScreenSharingStore";
import {DivImportance} from "../WebRtc/LayoutManager";
import { peerStore, screenSharingStreamStore} from "./PeerStore";
import type {RemotePeer} from "../WebRtc/SimplePeer";
@ -27,26 +26,15 @@ function createLayoutStore() {
}
unsubscribes = [];
const peers = new Map<DivImportance, Map<string, DisplayableMedia>>();
peers.set(DivImportance.Normal, new Map<string, DisplayableMedia>());
peers.set(DivImportance.Important, new Map<string, DisplayableMedia>());
const peers = new Map<string, DisplayableMedia>();
const addPeer = (peer: DisplayableMedia) => {
const importance = get(peer.importanceStore);
peers.get(importance)?.set(peer.uniqueId, peer);
unsubscribes.push(peer.importanceStore.subscribe((importance) => {
peers.forEach((category) => {
category.delete(peer.uniqueId);
});
peers.get(importance)?.set(peer.uniqueId, peer);
set(peers);
}));
peers.set(peer.uniqueId, peer);
};
$screenSharingStreamStore.forEach(addPeer);
$peerStore.forEach(addPeer);
if ($screenSharingLocalMedia?.stream) {
addPeer($screenSharingLocalMedia);
}

View file

@ -5,7 +5,6 @@ import type {
} from "./MediaStore";
import {DivImportance} from "../WebRtc/LayoutManager";
import {gameOverlayVisibilityStore} from "./GameOverlayStoreVisibility";
import {createImportanceStore, ImportanceStore} from "./ImportanceStore";
declare const navigator:any; // eslint-disable-line @typescript-eslint/no-explicit-any
@ -189,7 +188,6 @@ export const screenSharingAvailableStore = derived(peerStore, ($peerStore, set)
export interface ScreenSharingLocalMedia {
uniqueId: string;
importanceStore: ImportanceStore;
stream: MediaStream|null;
//subscribe(this: void, run: Subscriber<ScreenSharingLocalMedia>, invalidate?: (value?: ScreenSharingLocalMedia) => void): Unsubscriber;
}
@ -201,7 +199,6 @@ export const screenSharingLocalMedia = readable<ScreenSharingLocalMedia|null>(nu
const localMedia: ScreenSharingLocalMedia = {
uniqueId: "localScreenSharingStream",
importanceStore: createImportanceStore(DivImportance.Normal),
stream: null
}

View file

@ -0,0 +1,48 @@
import {writable} from "svelte/store";
import type {RemotePeer, SimplePeer} from "../WebRtc/SimplePeer";
import {VideoPeer} from "../WebRtc/VideoPeer";
import {ScreenSharingPeer} from "../WebRtc/ScreenSharingPeer";
import type {DisplayableMedia} from "./LayoutStore";
/**
* A store that contains the peer / media that has currently the "importance" focus.
*/
function createVideoFocusStore() {
const { subscribe, set, update } = writable<DisplayableMedia | null>(null);
let focusedMedia: DisplayableMedia | null = null;
return {
subscribe,
focus: (media: DisplayableMedia) => {
focusedMedia = media;
set(media);
},
removeFocus: () => {
focusedMedia = null;
set(null);
},
toggleFocus: (media: DisplayableMedia) => {
if (media !== focusedMedia) {
focusedMedia = media;
} else {
focusedMedia = null;
}
console.log('MEDIA', focusedMedia)
set(focusedMedia);
},
connectToSimplePeer: (simplePeer: SimplePeer) => {
simplePeer.registerPeerConnectionListener({
onConnect(peer: RemotePeer) {
},
onDisconnect(userId: number) {
if ((focusedMedia instanceof VideoPeer || focusedMedia instanceof ScreenSharingPeer) && focusedMedia.userId === userId) {
set(null);
}
}
})
}
};
}
export const videoFocusStore = createVideoFocusStore();

View file

@ -5,9 +5,7 @@ import type {RoomConnection} from "../Connexion/RoomConnection";
import {MESSAGE_TYPE_CONSTRAINT} from "./VideoPeer";
import type {UserSimplePeerInterface} from "./SimplePeer";
import {Readable, readable, writable, Writable} from "svelte/store";
import {DivImportance} from "./LayoutManager";
import type {ImportanceStore} from "../Stores/ImportanceStore";
import {createImportanceStore} from "../Stores/ImportanceStore";
import {videoFocusStore} from "../Stores/VideoFocusStore";
const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
@ -24,7 +22,6 @@ export class ScreenSharingPeer extends Peer {
public readonly userId: number;
public readonly uniqueId: string;
public readonly streamStore: Readable<MediaStream | null>;
public readonly importanceStore: ImportanceStore;
public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">;
constructor(user: UserSimplePeerInterface, initiator: boolean, public readonly userName: string, private connection: RoomConnection, stream: MediaStream | null) {
@ -50,6 +47,7 @@ export class ScreenSharingPeer extends Peer {
this.streamStore = readable<MediaStream|null>(null, (set) => {
const onStream = (stream: MediaStream|null) => {
videoFocusStore.focus(this);
set(stream);
};
const onData = (chunk: Buffer) => {
@ -73,8 +71,6 @@ export class ScreenSharingPeer extends Peer {
};
});
this.importanceStore = createImportanceStore(DivImportance.Important);
this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => {
const onConnect = () => {
set('connected');

View file

@ -5,11 +5,9 @@ import type {RoomConnection} from "../Connexion/RoomConnection";
import {blackListManager} from "./BlackListManager";
import type {Subscription} from "rxjs";
import type {UserSimplePeerInterface} from "./SimplePeer";
import {get, readable, Readable, writable, Writable} from "svelte/store";
import {get, readable, Readable} from "svelte/store";
import {obtainedMediaConstraintStore} from "../Stores/MediaStore";
import {DivImportance} from "./LayoutManager";
import type {ImportanceStore} from "../Stores/ImportanceStore";
import {createImportanceStore} from "../Stores/ImportanceStore";
const Peer: SimplePeerNamespace.SimplePeer = require('simple-peer');
@ -30,7 +28,6 @@ export class VideoPeer extends Peer {
private onBlockSubscribe: Subscription;
private onUnBlockSubscribe: Subscription;
public readonly streamStore: Readable<MediaStream | null>;
public readonly importanceStore: ImportanceStore;
public readonly statusStore: Readable<"connecting" | "connected" | "error" | "closed">;
public readonly constraintsStore: Readable<MediaStreamConstraints|null>;
@ -94,8 +91,6 @@ export class VideoPeer extends Peer {
};
});
this.importanceStore = createImportanceStore(DivImportance.Normal);
this.statusStore = readable<"connecting" | "connected" | "error" | "closed">("connecting", (set) => {
const onConnect = () => {
set('connected');

View file

@ -35,102 +35,108 @@ body .message-info.info{
body .message-info.warning{
background: #ffa500d6;
}
.video-container{
.video-container {
position: relative;
transition: all 0.2s ease;
background-color: #00000099;
cursor: url('./images/cursor_pointer.png'), pointer;
}
.video-container i{
position: absolute;
width: 100px;
height: 100px;
left: calc(50% - 50px);
top: calc(50% - 50px);
background-color: black;
border-radius: 50%;
text-align: center;
padding-top: 32px;
font-size: 28px;
color: white;
overflow: hidden;
}
.video-container img{
position: absolute;
display: none;
width: 40px;
height: 40px;
left: 5px;
bottom: 5px;
padding: 10px;
z-index: 2;
}
.video-container img.block-logo {
left: 30%;
bottom: 15%;
width: 150px;
height: 150px;
}
video {
width: 100%;
height: 100%;
cursor: url('./images/cursor_pointer.png'), pointer;
}
.video-container button.report{
display: block;
cursor: url('./images/cursor_pointer.png'), pointer;
background: none;
background-color: rgba(0, 0, 0, 0);
border: none;
background-color: black;
border-radius: 15px;
position: absolute;
width: 0px;
height: 35px;
right: 5px;
bottom: 5px;
padding: 0px;
overflow: hidden;
z-index: 2;
transition: all .5s ease;
}
i {
position: absolute;
width: 100px;
height: 100px;
left: calc(50% - 50px);
top: calc(50% - 50px);
background-color: black;
border-radius: 50%;
text-align: center;
padding-top: 32px;
font-size: 28px;
color: white;
overflow: hidden;
}
.video-container:hover button.report{
width: 35px;
padding: 10px;
}
img {
position: absolute;
display: none;
width: 40px;
height: 40px;
left: 5px;
bottom: 5px;
padding: 10px;
z-index: 2;
}
.video-container button.report:hover {
width: 160px;
}
img.block-logo {
left: 30%;
bottom: 15%;
width: 150px;
height: 150px;
}
.video-container button.report img{
position: absolute;
display: block;
bottom: 5px;
left: 5px;
margin: 0;
padding: 0;
cursor: url('./images/cursor_pointer.png'), pointer;
width: 25px;
height: 25px;
}
.video-container button.report span{
position: absolute;
bottom: 6px;
left: 36px;
color: white;
font-size: 16px;
cursor: url('./images/cursor_pointer.png'), pointer;
}
.video-container img.active {
display: block !important;
}
button.report{
display: block;
cursor: url('./images/cursor_pointer.png'), pointer;
background: none;
background-color: rgba(0, 0, 0, 0);
border: none;
background-color: black;
border-radius: 15px;
position: absolute;
width: 0px;
height: 35px;
right: 5px;
bottom: 5px;
padding: 0px;
overflow: hidden;
z-index: 2;
transition: all .5s ease;
.video-container video{
height: 100%;
cursor: url('./images/cursor_pointer.png'), pointer;
}
img{
position: absolute;
display: block;
bottom: 5px;
left: 5px;
margin: 0;
padding: 0;
cursor: url('./images/cursor_pointer.png'), pointer;
width: 25px;
height: 25px;
}
.video-container video:focus{
outline: none;
span {
position: absolute;
bottom: 6px;
left: 36px;
color: white;
font-size: 16px;
cursor: url('./images/cursor_pointer.png'), pointer;
}
img.active {
display: block !important;
}
}
&:hover button.report{
width: 35px;
padding: 10px;
&:hover {
width: 160px;
}
}
video:focus{
outline: none;
}
}
.video-container.div-myCamVideo{