Skip to content

Instantly share code, notes, and snippets.

@image72
Last active September 8, 2023 15:13
Show Gist options
  • Save image72/3932ea081221ca02bf3ed9814dcd8d1b to your computer and use it in GitHub Desktop.
Save image72/3932ea081221ca02bf3ed9814dcd8d1b to your computer and use it in GitHub Desktop.
WebRTC peer to peer, simple codes.
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Peer-to-Peer Cue System --- Reciever</title>
<style>
body {
font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
background-color: white;
min-width: 450px;
}
h1 {
font-size: 1.75em;
}
h2 {
text-align: center;
font-size: 4em;
}
td {
width: 50%;
}
input {
margin-bottom: 5px;
}
a:visited {
color: blue;
}
.display {
width: 100%;
min-height: 400px;
padding-bottom: 20px;
}
.control {
width: 100%;
padding-bottom: 20px;
}
.control-button {
width: 100%;
min-height: 50px;
}
.display-box {
border: 2px solid black;
}
.title {
vertical-align: top;
}
.standby {
background-color: red;
}
.go {
background-color: green;
}
.fade {
background-color: yellow;
}
.off {
background-color: gray;
}
.hidden {
visibility: hidden;
}
.no-display {
display: none;
}
.status {
height: 125px;
vertical-align: text-top;
font-weight: bold;
margin-bottom: 10px;
border-bottom: 2px solid black;
}
.message {
height: 125px;
max-height: 125px;
margin-bottom: 10px;
border-bottom: 2px solid black;
overflow: auto;
}
.msg-time {
color: blue;
}
.cueMsg {
color: orange;
}
.selfMsg {
color: green;
}
.peerMsg {
color: red;
}
</style>
</head>
<body>
<table class="display">
<tr>
<td class="title">Status:</td>
<td class="title">Messages:</td>
</tr>
<tr>
<td>
<div id="receiver-id" style="font-weight: bold" title="Copy this ID to the input on send.html.">
ID:
</div>
</td>
<td>
<input type="text" id="sendMessageBox" placeholder="Enter a message..." autofocus="true" />
<button type="button" id="sendButton">Send</button>
<button type="button" id="clearMsgsButton">Clear Msgs (Local)</button>
</td>
</tr>
<tr>
<td>
<div id="status" class="status"></div>
</td>
<td>
<div class="message" id="message"></div>
</td>
</tr>
<tr>
<td class="display-box standby" id="standby">
<h2>Standby</h2>
</td>
<td class="display-box hidden" id="go">
<h2>Go</h2>
</td>
</tr>
<tr>
<td class="display-box hidden" id="fade">
<h2>Fade</h2>
</td>
<td class="display-box hidden" id="off">
<h2>All Off</h2>
</td>
</tr>
</table>
<script src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"></script>
<script type="text/javascript">
(function () {
var lastPeerId = null;
var peer = null; // Own peer object
var peerId = null;
var conn = null;
var recvId = document.getElementById('receiver-id');
var status = document.getElementById('status');
var message = document.getElementById('message');
var standbyBox = document.getElementById('standby');
var goBox = document.getElementById('go');
var fadeBox = document.getElementById('fade');
var offBox = document.getElementById('off');
var sendMessageBox = document.getElementById('sendMessageBox');
var sendButton = document.getElementById('sendButton');
var clearMsgsButton = document.getElementById('clearMsgsButton');
/**
* Create the Peer object for our end of the connection.
*
* Sets up callbacks that handle any events related to our
* peer object.
*/
function initialize() {
// Create own peer object with connection to shared PeerJS server
peer = new Peer(null, {
debug: 2,
});
peer.on('open', function (id) {
// Workaround for peer.reconnect deleting previous id
if (peer.id === null) {
console.log('Received null id from peer open');
peer.id = lastPeerId;
} else {
lastPeerId = peer.id;
}
console.log('ID: ' + peer.id);
recvId.innerHTML = 'ID: ' + peer.id;
status.innerHTML = 'Awaiting connection...';
});
peer.on('connection', function (c) {
// Allow only a single connection
if (conn && conn.open) {
c.on('open', function () {
c.send('Already connected to another client');
setTimeout(function () {
c.close();
}, 500);
});
return;
}
conn = c;
console.log('Connected to: ' + conn.peer);
status.innerHTML = 'Connected';
ready();
});
peer.on('disconnected', function () {
status.innerHTML = 'Connection lost. Please reconnect';
console.log('Connection lost. Please reconnect');
// Workaround for peer.reconnect deleting previous id
peer.id = lastPeerId;
peer._lastServerId = lastPeerId;
peer.reconnect();
});
peer.on('close', function () {
conn = null;
status.innerHTML = 'Connection destroyed. Please refresh';
console.log('Connection destroyed');
});
peer.on('error', function (err) {
console.log(err);
alert('' + err);
});
}
/**
* Triggered once a connection has been achieved.
* Defines callbacks to handle incoming data and connection events.
*/
function ready() {
conn.on('data', function (data) {
console.log('Data recieved');
var cueString = '<span class="cueMsg">Cue: </span>';
switch (data) {
case 'Go':
go();
addMessage(cueString + data);
break;
case 'Fade':
fade();
addMessage(cueString + data);
break;
case 'Off':
off();
addMessage(cueString + data);
break;
case 'Reset':
reset();
addMessage(cueString + data);
break;
default:
addMessage('<span class="peerMsg">Peer: </span>' + data);
break;
}
});
conn.on('close', function () {
status.innerHTML = 'Connection reset<br>Awaiting connection...';
conn = null;
});
}
function go() {
standbyBox.className = 'display-box hidden';
goBox.className = 'display-box go';
fadeBox.className = 'display-box hidden';
offBox.className = 'display-box hidden';
return;
}
function fade() {
standbyBox.className = 'display-box hidden';
goBox.className = 'display-box hidden';
fadeBox.className = 'display-box fade';
offBox.className = 'display-box hidden';
return;
}
function off() {
standbyBox.className = 'display-box hidden';
goBox.className = 'display-box hidden';
fadeBox.className = 'display-box hidden';
offBox.className = 'display-box off';
return;
}
function reset() {
standbyBox.className = 'display-box standby';
goBox.className = 'display-box hidden';
fadeBox.className = 'display-box hidden';
offBox.className = 'display-box hidden';
return;
}
function addMessage(msg) {
var now = new Date();
var h = now.getHours();
var m = addZero(now.getMinutes());
var s = addZero(now.getSeconds());
if (h > 12) h -= 12;
else if (h === 0) h = 12;
function addZero(t) {
if (t < 10) t = '0' + t;
return t;
}
message.innerHTML =
'<br><span class="msg-time">' +
h +
':' +
m +
':' +
s +
'</span> - ' +
msg +
message.innerHTML;
}
function clearMessages() {
message.innerHTML = '';
addMessage('Msgs cleared');
}
// Listen for enter in message box
sendMessageBox.addEventListener('keypress', function (e) {
var event = e || window.event;
var char = event.which || event.keyCode;
if (char == '13') sendButton.click();
});
// Send message
sendButton.addEventListener('click', function () {
if (conn && conn.open) {
var msg = sendMessageBox.value;
sendMessageBox.value = '';
conn.send(msg);
console.log('Sent: ' + msg);
addMessage('<span class="selfMsg">Self: </span>' + msg);
} else {
console.log('Connection is closed');
}
});
// Clear messages box
clearMsgsButton.addEventListener('click', clearMessages);
initialize();
})();
</script>
</body>
</html>
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width" />
<title>Peer-to-Peer Cue System --- Sender</title>
<style>
body {
font-family: 'DejaVu Sans', Arial, Helvetica, sans-serif;
background-color: white;
min-width: 450px;
}
h1 {
font-size: 1.75em;
}
h2 {
text-align: center;
font-size: 4em;
}
td {
width: 50%;
}
input {
margin-bottom: 5px;
}
a:visited {
color: blue;
}
.display {
width: 100%;
min-height: 400px;
padding-bottom: 20px;
}
.control {
width: 100%;
padding-bottom: 20px;
}
.control-button {
width: 100%;
min-height: 50px;
}
.display-box {
border: 2px solid black;
}
.title {
vertical-align: top;
}
.standby {
background-color: red;
}
.go {
background-color: green;
}
.fade {
background-color: yellow;
}
.off {
background-color: gray;
}
.hidden {
visibility: hidden;
}
.no-display {
display: none;
}
.status {
height: 125px;
vertical-align: text-top;
font-weight: bold;
margin-bottom: 10px;
border-bottom: 2px solid black;
}
.message {
height: 125px;
max-height: 125px;
margin-bottom: 10px;
border-bottom: 2px solid black;
overflow: auto;
}
.msg-time {
color: blue;
}
.cueMsg {
color: orange;
}
.selfMsg {
color: green;
}
.peerMsg {
color: red;
}
</style>
</head>
<body>
<h1>Peer-to-Peer Cue System --- Sender</h1>
<table class="control">
<tr>
<td class="title">Status:</td>
<td class="title">Messages:</td>
</tr>
<tr>
<td>
<span style="font-weight: bold">ID: </span>
<input type="text" id="receiver-id" title="Input the ID from receive.html" />
<button id="connect-button">Connect</button>
</td>
<td>
<input type="text" id="sendMessageBox" placeholder="Enter a message..." autofocus="true" />
<button type="button" id="sendButton">Send</button>
<button type="button" id="clearMsgsButton">Clear Msgs (Local)</button>
</td>
</tr>
<tr>
<td>
<div id="status" class="status"></div>
</td>
<td>
<div class="message" id="message"></div>
</td>
</tr>
<tr>
<td>
<button type="button" class="control-button" id="resetButton">
Reset
</button>
</td>
<td>
<button type="button" class="control-button" id="goButton">Go</button>
</td>
</tr>
<tr>
<td>
<button type="button" class="control-button" id="fadeButton">
Fade
</button>
</td>
<td>
<button type="button" class="control-button" id="offButton">
Off
</button>
</td>
</tr>
</table>
<script src="https://unpkg.com/peerjs@1.3.1/dist/peerjs.min.js"></script>
<script type="text/javascript">
(function () {
var lastPeerId = null;
var peer = null; // own peer object
var conn = null;
var recvIdInput = document.getElementById('receiver-id');
var status = document.getElementById('status');
var message = document.getElementById('message');
var goButton = document.getElementById('goButton');
var resetButton = document.getElementById('resetButton');
var fadeButton = document.getElementById('fadeButton');
var offButton = document.getElementById('offButton');
var sendMessageBox = document.getElementById('sendMessageBox');
var sendButton = document.getElementById('sendButton');
var clearMsgsButton = document.getElementById('clearMsgsButton');
var connectButton = document.getElementById('connect-button');
var cueString = '<span class="cueMsg">Cue: </span>';
/**
* Create the Peer object for our end of the connection.
*
* Sets up callbacks that handle any events related to our
* peer object.
*/
function initialize() {
// Create own peer object with connection to shared PeerJS server
peer = new Peer(null, {
debug: 2,
});
peer.on('open', function (id) {
// Workaround for peer.reconnect deleting previous id
if (peer.id === null) {
console.log('Received null id from peer open');
peer.id = lastPeerId;
} else {
lastPeerId = peer.id;
}
console.log('ID: ' + peer.id);
});
peer.on('connection', function (c) {
// Disallow incoming connections
c.on('open', function () {
c.send('Sender does not accept incoming connections');
setTimeout(function () {
c.close();
}, 500);
});
});
peer.on('disconnected', function () {
status.innerHTML = 'Connection lost. Please reconnect';
console.log('Connection lost. Please reconnect');
// Workaround for peer.reconnect deleting previous id
peer.id = lastPeerId;
peer._lastServerId = lastPeerId;
peer.reconnect();
});
peer.on('close', function () {
conn = null;
status.innerHTML = 'Connection destroyed. Please refresh';
console.log('Connection destroyed');
});
peer.on('error', function (err) {
console.log(err);
alert('' + err);
});
}
/**
* Create the connection between the two Peers.
*
* Sets up callbacks that handle any events related to the
* connection and data received on it.
*/
function join() {
// Close old connection
if (conn) {
conn.close();
}
// Create connection to destination peer specified in the input field
conn = peer.connect(recvIdInput.value, {
reliable: true,
});
conn.on('open', function () {
status.innerHTML = 'Connected to: ' + conn.peer;
console.log('Connected to: ' + conn.peer);
// Check URL params for comamnds that should be sent immediately
var command = getUrlParam('command');
if (command) conn.send(command);
});
// Handle incoming data (messages only since this is the signal sender)
conn.on('data', function (data) {
addMessage('<span class="peerMsg">Peer:</span> ' + data);
});
conn.on('close', function () {
status.innerHTML = 'Connection closed';
});
}
/**
* Get first "GET style" parameter from href.
* This enables delivering an initial command upon page load.
*
* Would have been easier to use location.hash.
*/
function getUrlParam(name) {
name = name.replace(/[\[]/, '\\\[').replace(/[\]]/, '\\\]');
var regexS = '[\\?&]' + name + '=([^&#]*)';
var regex = new RegExp(regexS);
var results = regex.exec(window.location.href);
if (results == null) return null;
else return results[1];
}
/**
* Send a signal via the peer connection and add it to the log.
* This will only occur if the connection is still alive.
*/
function signal(sigName) {
if (conn && conn.open) {
conn.send(sigName);
console.log(sigName + ' signal sent');
addMessage(cueString + sigName);
} else {
console.log('Connection is closed');
}
}
goButton.addEventListener('click', function () {
signal('Go');
});
resetButton.addEventListener('click', function () {
signal('Reset');
});
fadeButton.addEventListener('click', function () {
signal('Fade');
});
offButton.addEventListener('click', function () {
signal('Off');
});
function addMessage(msg) {
var now = new Date();
var h = now.getHours();
var m = addZero(now.getMinutes());
var s = addZero(now.getSeconds());
if (h > 12) h -= 12;
else if (h === 0) h = 12;
function addZero(t) {
if (t < 10) t = '0' + t;
return t;
}
message.innerHTML =
'<br><span class="msg-time">' +
h +
':' +
m +
':' +
s +
'</span> - ' +
msg +
message.innerHTML;
}
function clearMessages() {
message.innerHTML = '';
addMessage('Msgs cleared');
}
// Listen for enter in message box
sendMessageBox.addEventListener('keypress', function (e) {
var event = e || window.event;
var char = event.which || event.keyCode;
if (char == '13') sendButton.click();
});
// Send message
sendButton.addEventListener('click', function () {
if (conn && conn.open) {
var msg = sendMessageBox.value;
sendMessageBox.value = '';
conn.send(msg);
console.log('Sent: ' + msg);
addMessage('<span class="selfMsg">Self: </span> ' + msg);
} else {
console.log('Connection is closed');
}
});
// Clear messages box
clearMsgsButton.addEventListener('click', clearMessages);
// Start peer connection on click
connectButton.addEventListener('click', join);
// Since all our callbacks are setup, start the process of obtaining an ID
initialize();
})();
</script>
<div hidden>
# Peer-to-Peer Cue System #
Cue system for simple two-way communication and visual signaling using a WebRTC peer-to-peer connection.
This was initially designed for signaling on-stage actors during a theater performance.
Demo: https://jmcker.github.io/Peer-to-Peer-Cue-System
[PeerJS examples](https://peerjs.com/examples.html)
### Setup ###
1. Open receive.html on the receiving device.
2. Open send.html on the sending device.
3. Copy the ID from the receiving device to the sending device's ID field.
4. Press *Connect*.
4. Both should indicate a successful connection in the *Status* box.
### Features ###
The receiver has access to large indicators for standby, go, fade, and stop signals.
The sender has access to buttons that send the standby, go, fade, and stop signals, triggering the receiver's
indicators.
Both have access to a two-way messenger for additional communication.
</div>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment