Skip to content

Commit 9537f82

Browse files
authored
Merge pull request #1553 from fippo/datachannel-channel
datachannel: add example for two tabs
2 parents d860f48 + fcd937a commit 9537f82

File tree

5 files changed

+409
-0
lines changed

5 files changed

+409
-0
lines changed

index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -189,6 +189,8 @@ <h2 id="datachannel"><a
189189

190190
<li><a href="src/content/datachannel/datatransfer/">Transfer data</a></li>
191191

192+
<li><a href="src/content/datachannel/channel/">Basic datachannel demo between two tabs</a></li>
193+
192194
<li><a href="src/content/datachannel/messaging/">Messaging</a></li>
193195
</ul>
194196

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
/*
2+
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3+
*
4+
* Use of this source code is governed by a BSD-style license
5+
* that can be found in the LICENSE file in the root of the source
6+
* tree.
7+
*/
8+
button {
9+
margin: 0 1em 1em 0;
10+
width: 90px;
11+
}
12+
div#buttons {
13+
margin: 0 0 1em 0;
14+
}
15+
div#send {
16+
margin: 0 20px 1em 0;
17+
}
18+
div#sendReceive {
19+
border-bottom: 1px solid #eee;
20+
margin: 0;
21+
padding: 0 0 10px 0;
22+
}
23+
div#sendReceive > div {
24+
display: inline-block;
25+
width: calc(50% - 20px);
26+
}
27+
form {
28+
margin: 0 0 1em 0;
29+
white-space: nowrap;
30+
}
31+
form span {
32+
font-weight: 300;
33+
margin: 0 1em 0 0;
34+
white-space: normal;
35+
}
36+
textarea {
37+
color: #444;
38+
font-size: 0.9em;
39+
font-weight: 300;
40+
height: 7.0em;
41+
padding: 5px;
42+
width: calc(100% - 10px);
43+
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
<!DOCTYPE html>
2+
<!--
3+
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
4+
*
5+
* Use of this source code is governed by a BSD-style license
6+
* that can be found in the LICENSE file in the root of the source
7+
* tree.
8+
-->
9+
<html>
10+
<head>
11+
12+
<meta charset="utf-8">
13+
<meta name="description" content="WebRTC code samples">
14+
<meta name="viewport" content="width=device-width, user-scalable=yes, initial-scale=1, maximum-scale=1">
15+
<meta itemprop="description" content="Client-side WebRTC code samples">
16+
<meta itemprop="image" content="../../../images/webrtc-icon-192x192.png">
17+
<meta itemprop="name" content="WebRTC code samples">
18+
<meta name="mobile-web-app-capable" content="yes">
19+
<meta id="theme-color" name="theme-color" content="#ffffff">
20+
21+
<base target="_blank">
22+
23+
<title>Transmit text (between two tabs)</title>
24+
25+
<link rel="icon" sizes="192x192" href="../../../images/webrtc-icon-192x192.png">
26+
<link href="//fonts.googleapis.com/css?family=Roboto:300,400,500,700" rel="stylesheet" type="text/css">
27+
<link rel="stylesheet" href="../../../css/main.css">
28+
<link rel="stylesheet" href="css/main.css"/>
29+
30+
</head>
31+
32+
<body>
33+
34+
<div id="container">
35+
36+
<h1><a href="//webrtc.github.io/samples/" title="WebRTC samples homepage">WebRTC samples</a>
37+
<span>Transmit text</span></h1>
38+
39+
<div id="buttons">
40+
<button id="startButton" disabled>Start</button>
41+
<button id="sendButton" disabled>Send</button>
42+
<button id="closeButton" disabled>Stop</button>
43+
</div>
44+
45+
<div id="sendReceive">
46+
<div id="send">
47+
<h2>Send</h2>
48+
<textarea id="dataChannelSend" disabled
49+
placeholder="Press Start, enter some text, then press Send."></textarea>
50+
</div>
51+
<div id="receive">
52+
<h2>Receive</h2>
53+
<textarea id="dataChannelReceive" disabled></textarea>
54+
</div>
55+
</div>
56+
57+
<p>This sample shows how to setup a datachannel connection between two peers in different tabs using
58+
<a href="https://developer.mozilla.org/en-US/docs/Web/API/RTCPeerConnection">RTCPeerConnection</a>
59+
and <a href="https://developer.mozilla.org/en-US/docs/Web/API/Broadcast_Channel_API">Broadcast Channel</a>
60+
</p>
61+
<p>Open the sample in two tabs (of the same browser), then click start in the first tab and
62+
send messages back and forth.</p>
63+
64+
<p>For more information about RTCDataChannel, see <a
65+
href="http://www.html5rocks.com/en/tutorials/webrtc/basics/#toc-rtcdatachannel"
66+
title="RTCDataChannel section of HTML5 Rocks article about WebRTC">Getting Started With WebRTC</a>.</p>
67+
68+
<a href="https://github.com/webrtc/samples/tree/gh-pages/src/content/datachannel/channel"
69+
title="View source for this page on GitHub" id="viewSource">View source on GitHub</a>
70+
</div>
71+
72+
<script src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
73+
<script src="js/main.js" async></script>
74+
75+
<script src="../../../js/lib/ga.js"></script>
76+
77+
</body>
78+
</html>
Lines changed: 196 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,196 @@
1+
/*
2+
* Copyright (c) 2022 The WebRTC project authors. All Rights Reserved.
3+
*
4+
* Use of this source code is governed by a BSD-style license
5+
* that can be found in the LICENSE file in the root of the source
6+
* tree.
7+
*/
8+
9+
'use strict';
10+
11+
const startButton = document.getElementById('startButton');
12+
const closeButton = document.getElementById('closeButton');
13+
const sendButton = document.getElementById('sendButton');
14+
sendButton.onclick = sendData;
15+
16+
const dataChannelSend = document.querySelector('textarea#dataChannelSend');
17+
const dataChannelReceive = document.querySelector('textarea#dataChannelReceive');
18+
19+
let pc;
20+
let sendChannel;
21+
let receiveChannel;
22+
23+
const signaling = new BroadcastChannel('webrtc');
24+
signaling.onmessage = e => {
25+
switch (e.data.type) {
26+
case 'offer':
27+
handleOffer(e.data);
28+
break;
29+
case 'answer':
30+
handleAnswer(e.data);
31+
break;
32+
case 'candidate':
33+
handleCandidate(e.data);
34+
break;
35+
case 'ready':
36+
// A second tab joined. This tab will enable the start button unless in a call already.
37+
if (pc) {
38+
console.log('already in call, ignoring');
39+
return;
40+
}
41+
startButton.disabled = false;
42+
break;
43+
case 'bye':
44+
if (pc) {
45+
hangup();
46+
}
47+
break;
48+
default:
49+
console.log('unhandled', e);
50+
break;
51+
}
52+
};
53+
signaling.postMessage({type: 'ready'});
54+
55+
startButton.onclick = async () => {
56+
startButton.disabled = true;
57+
closeButton.disabled = false;
58+
59+
await createPeerConnection();
60+
sendChannel = pc.createDataChannel('sendDataChannel');
61+
sendChannel.onopen = onSendChannelStateChange;
62+
sendChannel.onmessage = onSendChannelMessageCallback;
63+
sendChannel.onclose = onSendChannelStateChange;
64+
65+
const offer = await pc.createOffer();
66+
signaling.postMessage({type: 'offer', sdp: offer.sdp});
67+
await pc.setLocalDescription(offer);
68+
};
69+
70+
closeButton.onclick = async () => {
71+
hangup();
72+
signaling.postMessage({type: 'bye'});
73+
};
74+
75+
async function hangup() {
76+
if (pc) {
77+
pc.close();
78+
pc = null;
79+
}
80+
sendChannel = null;
81+
receiveChannel = null;
82+
console.log('Closed peer connections');
83+
startButton.disabled = false;
84+
sendButton.disabled = true;
85+
closeButton.disabled = true;
86+
dataChannelSend.value = '';
87+
dataChannelReceive.value = '';
88+
dataChannelSend.disabled = true;
89+
};
90+
91+
function createPeerConnection() {
92+
pc = new RTCPeerConnection();
93+
pc.onicecandidate = e => {
94+
const message = {
95+
type: 'candidate',
96+
candidate: null,
97+
};
98+
if (e.candidate) {
99+
message.candidate = e.candidate.candidate;
100+
message.sdpMid = e.candidate.sdpMid;
101+
message.sdpMLineIndex = e.candidate.sdpMLineIndex;
102+
}
103+
signaling.postMessage(message);
104+
};
105+
}
106+
107+
async function handleOffer(offer) {
108+
if (pc) {
109+
console.error('existing peerconnection');
110+
return;
111+
}
112+
await createPeerConnection();
113+
pc.ondatachannel = receiveChannelCallback;
114+
await pc.setRemoteDescription(offer);
115+
116+
const answer = await pc.createAnswer();
117+
signaling.postMessage({type: 'answer', sdp: answer.sdp});
118+
await pc.setLocalDescription(answer);
119+
}
120+
121+
async function handleAnswer(answer) {
122+
if (!pc) {
123+
console.error('no peerconnection');
124+
return;
125+
}
126+
await pc.setRemoteDescription(answer);
127+
}
128+
129+
async function handleCandidate(candidate) {
130+
if (!pc) {
131+
console.error('no peerconnection');
132+
return;
133+
}
134+
if (!candidate.candidate) {
135+
await pc.addIceCandidate(null);
136+
} else {
137+
await pc.addIceCandidate(candidate);
138+
}
139+
}
140+
141+
function sendData() {
142+
const data = dataChannelSend.value;
143+
if (sendChannel) {
144+
sendChannel.send(data);
145+
} else {
146+
receiveChannel.send(data);
147+
}
148+
console.log('Sent Data: ' + data);
149+
}
150+
151+
function receiveChannelCallback(event) {
152+
console.log('Receive Channel Callback');
153+
receiveChannel = event.channel;
154+
receiveChannel.onmessage = onReceiveChannelMessageCallback;
155+
receiveChannel.onopen = onReceiveChannelStateChange;
156+
receiveChannel.onclose = onReceiveChannelStateChange;
157+
}
158+
159+
function onReceiveChannelMessageCallback(event) {
160+
console.log('Received Message');
161+
dataChannelReceive.value = event.data;
162+
}
163+
164+
function onSendChannelMessageCallback(event) {
165+
console.log('Received Message');
166+
dataChannelReceive.value = event.data;
167+
}
168+
169+
function onSendChannelStateChange() {
170+
const readyState = sendChannel.readyState;
171+
console.log('Send channel state is: ' + readyState);
172+
if (readyState === 'open') {
173+
dataChannelSend.disabled = false;
174+
dataChannelSend.focus();
175+
sendButton.disabled = false;
176+
closeButton.disabled = false;
177+
} else {
178+
dataChannelSend.disabled = true;
179+
sendButton.disabled = true;
180+
closeButton.disabled = true;
181+
}
182+
}
183+
184+
function onReceiveChannelStateChange() {
185+
const readyState = receiveChannel.readyState;
186+
console.log(`Receive channel state is: ${readyState}`);
187+
if (readyState === 'open') {
188+
dataChannelSend.disabled = false;
189+
sendButton.disabled = false;
190+
closeButton.disabled = false;
191+
} else {
192+
dataChannelSend.disabled = true;
193+
sendButton.disabled = true;
194+
closeButton.disabled = true;
195+
}
196+
}

0 commit comments

Comments
 (0)