export async function PeerConnection(media: string) { const pc = new RTCPeerConnection({ iceServers: [{ urls: 'stun:stun.l.google.com:19302' }], }) const localTracks = [] if (/camera|microphone/.test(media)) { const tracks = await getMediaTracks('user', { video: media.indexOf('camera') >= 0, audio: media.indexOf('microphone') >= 0, }) tracks.forEach((track) => { pc.addTransceiver(track, { direction: 'sendonly' }) if (track.kind === 'video') localTracks.push(track) }) } if (media.indexOf('display') >= 0) { const tracks = await getMediaTracks('display', { video: true, audio: media.indexOf('speaker') >= 0, }) tracks.forEach((track) => { pc.addTransceiver(track, { direction: 'sendonly' }) if (track.kind === 'video') localTracks.push(track) }) } if (/video|audio/.test(media)) { const tracks = ['video', 'audio'] .filter((kind) => media.indexOf(kind) >= 0) .map((kind) => pc.addTransceiver(kind, { direction: 'recvonly' }).receiver.track) localTracks.push(...tracks) } return { pc, localTracks } } export async function getMediaTracks(media: string, constraints?: MediaStreamConstraints) { try { const stream = media === 'user' ? await navigator.mediaDevices.getUserMedia(constraints) : await navigator.mediaDevices.getDisplayMedia(constraints) return stream.getTracks() } catch (e) { console.warn(e) return [] } } export async function connect(url: string, media: string) { const { pc, localTracks } = await PeerConnection(media) let ws = new WebSocket('ws' + url.toString().substring(4)) ws.onopen = function () { pc.addEventListener('icecandidate', (ev) => { if (!ev.candidate) return const msg = { type: 'webrtc/candidate', value: ev.candidate.candidate } ws.send(JSON.stringify(msg)) }) pc.createOffer() .then((offer) => pc.setLocalDescription(offer)) .then(() => { const msg = { type: 'webrtc/offer', value: pc.localDescription?.sdp } ws.send(JSON.stringify(msg)) }) } ws.onmessage = function (ev) { const msg = JSON.parse(ev.data) if (msg.type === 'webrtc/candidate') { pc.addIceCandidate({ candidate: msg.value, sdpMid: '0' }) } else if (msg.type === 'webrtc/answer') { pc.setRemoteDescription({ type: 'answer', sdp: msg.value }) } } ws.onerror = function (ev) { console.log({ ev }) } ws.onclose = function () { setTimeout(function () { var ws2 = new WebSocket(ws.url) ws2.onopen = ws.onopen ws2.onmessage = ws.onmessage ws2.onclose = ws.onclose ws2.onerror = ws.onerror ws = ws2 }, 2000) } return new MediaStream(localTracks) }