Disable view source for Developer Tools.
[chromium-blink-merge.git] / chrome / test / data / webrtc / manual / peerconnection-multi.html
blobe90f7a6d89db546ffe4f95270958e0ec8027976e
1 <!DOCTYPE HTML PUBLIC "-//IETF//DTD HTML//EN">
2 <!--
3 Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
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. An additional intellectual property rights grant can be found
8 in the file PATENTS. All contributing project authors may
9 be found in the AUTHORS file in the root of the source tree.
10 -->
11 <html>
12 <head>
13 <title>WebRTC Multi-PeerConnection Test</title>
14 <script type="text/javascript">
15 // This file can create an arbitrary number of peer connection calls, each
16 // with an arbitrary number of auto-echoing data channels. It can run with
17 // two separate cameras.
19 // Our two local video / audio streams.
20 var gLocalStream1 = null;
21 var gLocalStream2 = null;
23 // The number of remote view windows (2x number of calls).
24 var gNumRemoteViews = 0;
26 // Maps connection id -> { connection1, connection2 }.
27 var gAllConnections = [];
28 var gNumConnections = 0;
30 // Maps data channel id -> sending channel.
31 // Note: there can be many data channels per connection id.
32 var gSendingDataChannels = [];
33 var gTotalNumSendChannels = 0;
35 function startTest() {
36 navigator.webkitGetUserMedia(
37 {video: true, audio: true},
38 function(localStream) {
39 gLocalStream1 = localStream;
40 play(localStream, 'local-view-1');
42 getUserMediaFailedCallback);
43 navigator.webkitGetUserMedia(
44 {video: true, audio: true},
45 function(localStream) {
46 gLocalStream2 = localStream;
47 play(localStream, 'local-view-2');
49 getUserMediaFailedCallback);
52 function playStreamInNewRemoteView(stream, peerNumber) {
53 console.log('Remote stream to connection ' + peerNumber +
54 ': ' + stream.label);
55 gNumRemoteViews++;
56 var viewName = 'remote-view-' + gNumRemoteViews;
57 addRemoteView(viewName, peerNumber);
58 play(stream, viewName);
61 function addRemoteView(elementName, peerNumber) {
62 var remoteViews = $('remote-views-' + peerNumber);
63 remoteViews.innerHTML +=
64 '<tr><td><video width="320" height="240" id="' + elementName + '" ' +
65 'autoplay="autoplay"></video></td></tr>';
68 function play(stream, videoElement) {
69 var streamUrl = URL.createObjectURL(stream);
70 $(videoElement).src = streamUrl;
73 function getUserMediaFailedCallback(error) {
74 console.log('getUserMedia request failed with code ' + error.code);
77 function call() {
78 connection1 = new webkitRTCPeerConnection(null,
79 {optional:[{RtpDataChannels: true}]});
80 connection1.addStream(gLocalStream1);
82 connection2 = new webkitRTCPeerConnection(
83 null, {optional:[{RtpDataChannels: true}]});
84 connection2.addStream(gLocalStream2);
85 connection2.onicecandidate = function(event) {
86 if (event.candidate) {
87 var candidate = new RTCIceCandidate(event.candidate);
88 connection1.addIceCandidate(candidate);
91 connection1.onicecandidate = function(event) {
92 if (event.candidate) {
93 console.log('Ice candidate: ' + event.candidate);
94 var candidate = new RTCIceCandidate(event.candidate);
95 connection2.addIceCandidate(candidate);
98 connection1.onaddstream = function(event) {
99 playStreamInNewRemoteView(event.stream, 1);
100 //addDataChannelAnchor(connection1, connection2);
102 connection2.onaddstream = function(event) {
103 playStreamInNewRemoteView(event.stream, 2);
105 // TODO(phoglund): hack to work around
106 // https://code.google.com/p/webrtc/issues/detail?id=1203. When it is fixed,
107 // uncomment the negotiate call, remove addDataChannel and uncomment in
108 // connection1.onaddstream. Also remove the notice at the top of the HTML!
109 // negotiate(connection1, connection2);
110 addDataChannelAnchor(connection1, connection2);
113 function negotiate(connection1, connection2) {
114 connection1.createOffer(function(offer) {
115 connection1.setLocalDescription(offer);
116 connection2.setRemoteDescription(offer);
117 connection2.createAnswer(function(answer) {
118 console.log('Created answer ' + answer);
119 connection2.setLocalDescription(answer);
120 connection1.setRemoteDescription(answer);
125 function addDataChannelAnchor(connection1, connection2) {
126 var connectionId = gNumConnections++;
127 gAllConnections[connectionId] = { connection1: connection1,
128 connection2: connection2 };
129 addOneAnchor(1, connectionId);
130 addOneAnchor(2, connectionId);
133 function makeDataChannelAnchorName(peerId, connectionId) {
134 return 'data-channels-peer' + peerId + '-' + connectionId;
137 // This adds a target table we'll add our input fields to later.
138 function addOneAnchor(peerId, connectionId) {
139 var newButtonId = 'add-data-channel-' + connectionId;
140 var remoteViewContainer = 'remote-views-' + peerId;
141 $(remoteViewContainer).innerHTML +=
142 '<tr><td><button id="' + newButtonId + '" ' +
143 'onclick="addDataChannel(' + connectionId + ')">' +
144 ' Add Echoing Data Channel</button></td></tr>';
146 var anchorName = makeDataChannelAnchorName(peerId, connectionId);
147 $(remoteViewContainer).innerHTML +=
148 '<tr><td><table id="' + anchorName + '"></table></td></tr>';
151 // Called by clicking Add Echoing Data Channel.
152 function addDataChannel(connectionId) {
153 var dataChannelId = gTotalNumSendChannels++;
155 var peer1SinkId = addDataChannelSink(1, connectionId, dataChannelId);
156 var peer2SinkId = addDataChannelSink(2, connectionId, dataChannelId);
157 var connections = gAllConnections[connectionId];
159 configureChannels(connections.connection1, connections.connection2,
160 peer1SinkId, peer2SinkId, dataChannelId);
162 // Add the field the user types in, and a
163 // dummy field so everything lines up nicely.
164 addDataChannelSource(1, connectionId, dataChannelId);
165 addDisabledInputField(2, connectionId, '(the above is echoed)');
167 negotiate(connections.connection1, connections.connection2);
170 function configureChannels(connection1, connection2, targetFor1, targetFor2,
171 dataChannelId) {
172 // Label the channel so we know where to send the data later in dispatch.
173 sendChannel = connection1.createDataChannel(
174 targetFor2, { reliable : false });
175 sendChannel.onmessage = function(messageEvent) {
176 $(targetFor1).value = messageEvent.data;
179 gSendingDataChannels[dataChannelId] = sendChannel;
181 connection2.ondatachannel = function(event) {
182 // The channel got created by a message from a sending channel: hook this
183 // new receiver channel up to dispatch and then echo any messages.
184 event.channel.onmessage = dispatchAndEchoDataMessage;
188 function addDataChannelSink(peerNumber, connectionId, dataChannelId) {
189 var sinkId = 'data-sink-peer' + peerNumber + '-' + dataChannelId;
190 var anchor = $(makeDataChannelAnchorName(peerNumber, connectionId));
191 anchor.innerHTML +=
192 '<tr><td><input type="text" id="' + sinkId + '" disabled/></td></tr>';
193 return sinkId;
196 function addDataChannelSource(peerNumber, connectionId, dataChannelId) {
197 var sourceId = 'data-source-peer' + peerNumber + '-' + dataChannelId;
198 var anchor = $(makeDataChannelAnchorName(peerNumber, connectionId));
199 anchor.innerHTML +=
200 '<tr><td><input type="text" id="' + sourceId + '"' +
201 ' onchange="userWroteSomethingIn(\'' + sourceId + '\', ' +
202 dataChannelId + ');"/></td></tr>';
205 function userWroteSomethingIn(sourceId, dataChannelId) {
206 var source = $(sourceId);
207 var dataChannel = gSendingDataChannels[dataChannelId];
208 dataChannel.send(source.value);
211 function addDisabledInputField(peerNumber, connectionId, text) {
212 var anchor = $(makeDataChannelAnchorName(peerNumber, connectionId));
213 anchor.innerHTML +=
214 '<tr><td><input type="text" value="' + text + '" disabled/></td></tr>';
217 function dispatchAndEchoDataMessage(messageEvent) {
218 // Since we labeled the channel earlier, we know to which input element
219 // we should send the data.
220 var dataChannel = messageEvent.currentTarget;
221 var targetInput = $(dataChannel.label);
222 targetInput.value = messageEvent.data;
223 dataChannel.send('echo: ' + messageEvent.data);
226 window.onload = function() {
227 startTest();
230 $ = function(id) {
231 return document.getElementById(id);
233 </script>
234 </head>
235 <body>
236 <table border="0">
237 <tr>
238 <td colspan="2">
239 Notes:
240 <ul>
241 <li>Due to https://code.google.com/p/webrtc/issues/detail?id=1203,
242 you must create a data channel to actually get a call negotiated. Add
243 one call at a time and click "add echoing data channel" for each and
244 you'll be fine.</li>
245 <li>For unknown reasons, adding a new data channel will clear the
246 input field contents for all other channels on the same call. This is
247 not the data channel's fault though.</li>
248 </ul>
249 </td>
250 </tr>
251 <tr>
252 <td>Local Preview for Peer 1</td>
253 <td>Local Preview for Peer 2</td>
254 </tr>
255 <tr>
256 <td><video width="320" height="240" id="local-view-1"
257 autoplay="autoplay"></video></td>
258 <td><video width="320" height="240" id="local-view-2"
259 autoplay="autoplay"></video></td>
260 </tr>
261 <tr>
262 <td><button id="add-call" onclick="call();">Add Call</button></td>
263 </tr>
264 <tr>
265 <td>
266 <table id="remote-views-1">
267 <tr>
268 <td>Remote (Incoming to Peer 1)</td>
269 </tr>
270 </table>
271 </td>
272 <td>
273 <table id="remote-views-2">
274 <tr>
275 <td>Remote (Incoming to Peer 2)</td>
276 </tr>
277 </table>
278 </td>
279 </tr>
280 </table>
281 </body>
282 </html>