123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209 |
- /** @type {RTCPeerConnection} */
- let rtc;
- const iceConnectionLog = document.getElementById('ice-connection-state'),
- iceGatheringLog = document.getElementById('ice-gathering-state'),
- signalingLog = document.getElementById('signaling-state'),
- dataChannelLog = document.getElementById('data-channel');
- function randomString(len) {
- const charSet = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
- let randomString = '';
- for (let i = 0; i < len; i++) {
- const randomPoz = Math.floor(Math.random() * charSet.length);
- randomString += charSet.substring(randomPoz, randomPoz + 1);
- }
- return randomString;
- }
- const receiveID = randomString(10);
- const websocket = new WebSocket('ws://127.0.0.1:8000/' + receiveID);
- websocket.onopen = function () {
- document.getElementById('start').disabled = false;
- }
- // data channel
- let dc = null, dcTimeout = null;
- function createPeerConnection() {
- const config = {
- sdpSemantics: 'unified-plan',
- bundlePolicy: "max-bundle",
- };
- if (document.getElementById('use-stun').checked) {
- config.iceServers = [{urls: ['stun:stun.l.google.com:19302']}];
- }
- let pc = new RTCPeerConnection(config);
- // register some listeners to help debugging
- pc.addEventListener('icegatheringstatechange', function () {
- iceGatheringLog.textContent += ' -> ' + pc.iceGatheringState;
- }, false);
- iceGatheringLog.textContent = pc.iceGatheringState;
- pc.addEventListener('iceconnectionstatechange', function () {
- iceConnectionLog.textContent += ' -> ' + pc.iceConnectionState;
- }, false);
- iceConnectionLog.textContent = pc.iceConnectionState;
- pc.addEventListener('signalingstatechange', function () {
- signalingLog.textContent += ' -> ' + pc.signalingState;
- }, false);
- signalingLog.textContent = pc.signalingState;
- // connect audio / video
- pc.addEventListener('track', function (evt) {
- if (evt.track.kind == 'video') {
- document.getElementById('media').style.display = 'block';
- document.getElementById('video').srcObject = evt.streams[0];
- } else {
- document.getElementById('audio').srcObject = evt.streams[0];
- }
- });
- let time_start = null;
- function current_stamp() {
- if (time_start === null) {
- time_start = new Date().getTime();
- return 0;
- } else {
- return new Date().getTime() - time_start;
- }
- }
- pc.ondatachannel = function (event) {
- dc = event.channel;
- dc.onopen = function () {
- dataChannelLog.textContent += '- open\n';
- dataChannelLog.scrollTop = dataChannelLog.scrollHeight;
- };
- dc.onmessage = function (evt) {
- dataChannelLog.textContent += '< ' + evt.data + '\n';
- dataChannelLog.scrollTop = dataChannelLog.scrollHeight;
- dcTimeout = setTimeout(function () {
- if (dc == null && dcTimeout != null) {
- dcTimeout = null;
- return
- }
- const message = 'Pong ' + current_stamp();
- dataChannelLog.textContent += '> ' + message + '\n';
- dataChannelLog.scrollTop = dataChannelLog.scrollHeight;
- dc.send(message);
- }, 1000);
- }
- dc.onclose = function () {
- clearTimeout(dcTimeout);
- dcTimeout = null;
- dataChannelLog.textContent += '- close\n';
- dataChannelLog.scrollTop = dataChannelLog.scrollHeight;
- };
- }
- return pc;
- }
- function sendAnswer(pc) {
- return pc.createAnswer()
- .then((answer) => rtc.setLocalDescription(answer))
- .then(function () {
- // wait for ICE gathering to complete
- return new Promise(function (resolve) {
- if (pc.iceGatheringState === 'complete') {
- resolve();
- } else {
- function checkState() {
- if (pc.iceGatheringState === 'complete') {
- pc.removeEventListener('icegatheringstatechange', checkState);
- resolve();
- }
- }
- pc.addEventListener('icegatheringstatechange', checkState);
- }
- });
- }).then(function () {
- const answer = pc.localDescription;
- document.getElementById('answer-sdp').textContent = answer.sdp;
- return websocket.send(JSON.stringify(
- {
- id: "server",
- type: answer.type,
- sdp: answer.sdp,
- }));
- }).catch(function (e) {
- alert(e);
- });
- }
- function handleOffer(offer) {
- rtc = createPeerConnection();
- return rtc.setRemoteDescription(offer)
- .then(() => sendAnswer(rtc));
- }
- function sendStreamRequest() {
- websocket.send(JSON.stringify(
- {
- id: "server",
- type: "streamRequest",
- receiver: receiveID,
- }));
- }
- async function start() {
- document.getElementById('start').style.display = 'none';
- document.getElementById('stop').style.display = 'inline-block';
- document.getElementById('media').style.display = 'block';
- sendStreamRequest();
- }
- function stop() {
- document.getElementById('stop').style.display = 'none';
- document.getElementById('media').style.display = 'none';
- document.getElementById('start').style.display = 'inline-block';
- // close data channel
- if (dc) {
- dc.close();
- dc = null;
- }
- // close transceivers
- if (rtc.getTransceivers) {
- rtc.getTransceivers().forEach(function (transceiver) {
- if (transceiver.stop) {
- transceiver.stop();
- }
- });
- }
- // close local audio / video
- rtc.getSenders().forEach(function (sender) {
- const track = sender.track;
- if (track !== null) {
- sender.track.stop();
- }
- });
- // close peer connection
- setTimeout(function () {
- rtc.close();
- rtc = null;
- }, 500);
- }
- websocket.onmessage = async function (evt) {
- const received_msg = evt.data;
- const object = JSON.parse(received_msg);
- if (object.type == "offer") {
- document.getElementById('offer-sdp').textContent = object.sdp;
- await handleOffer(object)
- }
- }
|