-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.js
158 lines (129 loc) · 5.17 KB
/
index.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
import './style.css';
let localName = '';
// from https://github.com/wild-times/vnet-signal
const signalServerUrl = (code) => `ws://${window.location.hostname}:8000/sig/chn/${code}/`;
const signalTypes = {
SIGNAL_CONNECTED: 'signal_connected',
SIGNAL_DISCONNECTED: 'signal_disconnected',
OFFER: 'offer',
ANSWER: 'answer',
CANDIDATE: 'candidate'
};
function signaling (url) {
const socket = new WebSocket(url);
socket.onopen = () => document.getElementById('sig-status').innerText = 'CONNECTED';
socket.onclose = () => document.getElementById('sig-status').innerText = 'DISCONNECTED';
return socket;
}
function buildVideo (stream, home) {
const exists = [...home.children].find((child) => child.id === stream.id);
if (!exists) {
const videoEl = document.createElement('video');
videoEl.id = stream.id;
videoEl.autoplay = true;
videoEl.srcObject = stream;
home.appendChild(videoEl);
}
}
async function localsStream (localName = '') {
const media = await navigator.mediaDevices.getUserMedia({
audio: true,
video: true,
peerIdentity: localName
});
buildVideo(media, document.getElementById('me'));
return media;
}
async function makePeerConn (signal, stream, b = false) {
const conn = new RTCPeerConnection();
stream.getTracks().forEach((track) => conn.addTrack(track, stream));
conn.addEventListener('connectionstatechange', () => {
if (conn.connectionState === 'connected') {
signal.close();
}
});
// send candidates
conn.addEventListener('icecandidate', (event_) => {
if (event_.candidate) {
// send candidates
signal.send(JSON.stringify({
'type': signalTypes.CANDIDATE,
'content': event_.candidate,
'name': localName
}));
}
});
// add tracks
conn.addEventListener('track', (event_) => {
buildVideo(event_.streams[0], document.getElementById('others'))
});
if (b) {
// send offer on negotiation
conn.addEventListener('negotiationneeded', async () => {
await conn.setLocalDescription(await conn.createOffer());
// send offer
signal.send(JSON.stringify({
type: signalTypes.OFFER,
content: conn.localDescription,
name: localName
}));
});
}
// listen for other (answer, candidates)
signal.addEventListener('message', async (event_) => {
const data = JSON.parse(event_.data);
if (data.sent_by !== localName) {
if (data.type === signalTypes.OFFER && !b) {
await conn.setRemoteDescription(new RTCSessionDescription(data.description));
await conn.setLocalDescription(await conn.createAnswer());
// send answer
signal.send(JSON.stringify({
type: signalTypes.ANSWER,
content: conn.localDescription,
name: localName
}));
}
if (data.type === signalTypes.ANSWER) {
await conn.setRemoteDescription(new RTCSessionDescription(data.description));
}
if (data.type === signalTypes.CANDIDATE) {
await conn.addIceCandidate(new RTCIceCandidate(data.candidates));
}
}
});
}
document.forms['name-form'].addEventListener('submit', (event_) => {
event_.preventDefault();
const f = new FormData(event_.target);
[...event_.target].forEach((i) => i.disabled = true);
localName = f.get('cl-name');
if (localName) {
localsStream(localName).then((stream) => {
// start
document.getElementById('gen').addEventListener('click', (event_) => {
event_.target.disabled = true;
const code = Math.floor(Math.random() * (1000000 - 100000 + 1) + 100000);
document.getElementById('code').innerText = code.toString();
const sig = signalServerUrl(code);
const sc = signaling(sig);
// create peer connection
sc.addEventListener('message', async (event_) => {
const data = JSON.parse(event_.data);
if (data.type === "signal_connected" && data.peers_count === 2) {
await makePeerConn(sc, stream, true);
}
});
});
// join
document.forms['join'].addEventListener('submit', async (event_) => {
event_.preventDefault();
const f = new FormData(event_.target);
const code = f.get('join-code');
[...event_.target].forEach((input) => input.disabled = true);
const sig = signalServerUrl(code);
const sc = signaling(sig);
await makePeerConn(sc, stream);
});
});
}
});