Skip to content

Commit d302ad5

Browse files
committed
feat(ux): add StreamInterface Component
This should be re-usable by both Host and Participant.
1 parent f41573a commit d302ad5

1 file changed

Lines changed: 144 additions & 0 deletions

File tree

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<script lang="ts">
2+
import { onMount } from 'svelte'
3+
import { makeVideoDraggable, getUUIDv4 } from './Utils'
4+
import WebRTC from './WebRTC.svelte'
5+
import AudioVisualizer from './AudioVisualizer.svelte'
6+
7+
export let webRTCComponent: WebRTC
8+
9+
let remoteScreen: HTMLVideoElement
10+
let UUID = getUUIDv4()
11+
let zoomFactor = 1
12+
let microphoneActive = false
13+
let isStreaming = false
14+
let visualizerIsActive: boolean = true
15+
16+
onMount(async () => {
17+
const settings = await window.BananasApi.getSettings()
18+
microphoneActive = settings.isMicrophoneEnabledOnConnect
19+
makeVideoDraggable(remoteScreen)
20+
remoteScreen.addEventListener('dblclick', () => {
21+
webRTCComponent.PingRemoteCursor('cursor-' + UUID)
22+
})
23+
remoteScreen.addEventListener('mousemove', (e) => {
24+
const { offsetX, offsetY } = e
25+
// TODO: Batch cursor updates
26+
webRTCComponent.UpdateRemoteCursor({
27+
x: offsetX / remoteScreen.clientWidth,
28+
y: offsetY / remoteScreen.clientHeight,
29+
name: settings.username,
30+
id: 'cursor-' + UUID,
31+
color: settings.color
32+
})
33+
})
34+
remoteScreen.addEventListener('play', () => {
35+
if (!webRTCComponent.IsConnected()) return
36+
isStreaming = true
37+
})
38+
})
39+
const onDisconnectClick = async (): Promise<void> => {
40+
await webRTCComponent.Disconnect()
41+
}
42+
const onFullscreenClick = (): void => {
43+
remoteScreen.requestFullscreen()
44+
}
45+
const onZoomInClick = (): void => {
46+
zoomFactor += 0.1
47+
remoteScreen.style.scale = zoomFactor.toString()
48+
}
49+
const onZoomOutClick = (): void => {
50+
if (zoomFactor <= 1) return
51+
zoomFactor -= 0.1
52+
remoteScreen.style.scale = zoomFactor.toString()
53+
}
54+
const onMicrophoneToggle = async (): Promise<void> => {
55+
microphoneActive = !microphoneActive
56+
webRTCComponent.ToggleMicrophone()
57+
}
58+
</script>
59+
60+
<div class="container p-5">
61+
<h1 class="title">{!isStreaming ? 'Join' : 'Joined'} a session</h1>
62+
<div class={!isStreaming ? 'is-hidden' : ''}>
63+
<div class="fixed-grid">
64+
<div class="grid">
65+
<div class="cell">
66+
<button
67+
aria-label={microphoneActive ? 'Microphone active' : 'Microphone muted'}
68+
title={microphoneActive ? 'Microphone active' : 'Microphone muted'}
69+
class="button {microphoneActive ? 'is-success' : 'is-danger'}"
70+
on:click={onMicrophoneToggle}
71+
>
72+
<span class="icon">
73+
{#if microphoneActive}
74+
<AudioVisualizer
75+
className="icon {!visualizerIsActive ? 'is-hidden' : ''}"
76+
bind:visualizerIsActive
77+
stream={webRTCComponent.GetAudioStream()}
78+
/>
79+
<i class="fas fa-microphone {visualizerIsActive ? 'is-hidden' : ''}"></i>
80+
{:else}
81+
<i class="fas fa-microphone-slash"></i>
82+
{/if}
83+
</span>
84+
</button>
85+
</div>
86+
<div class="cell has-text-right">
87+
<button class="button is-danger" aria-label="Disconnect" on:click={onDisconnectClick}>
88+
<span class="icon">
89+
<i class="fas fa-unlink"></i>
90+
</span>
91+
<span>Disconnect</span>
92+
</button>
93+
</div>
94+
</div>
95+
</div>
96+
</div>
97+
</div>
98+
99+
<div class={!isStreaming ? 'is-hidden' : ''}>
100+
<div class="field">
101+
<label class="label" for="remote_screen">Remote screen</label>
102+
<div class="control">
103+
<div class="video-overflow">
104+
<video bind:this={remoteScreen} id="remote_screen" class="video" autoplay playsinline muted
105+
></video>
106+
</div>
107+
</div>
108+
</div>
109+
<div class="field">
110+
<div class="control">
111+
<button class="button is-info" on:click={onZoomInClick}>
112+
<span class="icon">
113+
<i class="fas fa-search-plus"></i>
114+
</span>
115+
<span>Zoom In</span>
116+
</button>
117+
<button class="button is-info" on:click={onZoomOutClick}>
118+
<span class="icon">
119+
<i class="fas fa-search-minus"></i>
120+
</span>
121+
<span>Zoom Out</span>
122+
</button>
123+
<button class="button is-info" on:click={onFullscreenClick}>
124+
<span class="icon">
125+
<i class="fas fa-expand"></i>
126+
</span>
127+
<span>Fullscreen</span>
128+
</button>
129+
</div>
130+
</div>
131+
</div>
132+
133+
<style>
134+
.video {
135+
width: 100%;
136+
height: auto;
137+
transition: transform 0.5s linear;
138+
}
139+
.video-overflow {
140+
width: 100%;
141+
height: auto;
142+
overflow: hidden;
143+
}
144+
</style>

0 commit comments

Comments
 (0)