blob: 7f7fc5d79281195fa85b59eba86dea0b52326b7f [file] [log] [blame]
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +00001<html>
2<head>
3<title>Constraints and Statistics</title>
hta@webrtc.orgdb3f4272013-03-05 15:23:40 +00004<!-- Load the polyfill to switch-hit between Chrome and Firefox -->
5<script src="../../base/adapter.js"></script>
6
hta@webrtc.org37bf5842013-04-06 10:05:55 +00007<style type="text/css">
8td { vertical-align: top; }
9</style>
10
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +000011<script>
12var mystream;
13var pc1;
14var pc2;
hta@webrtc.org3ed599a2013-03-22 08:48:16 +000015var bytesPrev = 0;
16var timestampPrev = 0;
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +000017
18$ = function(id) {
19 return document.getElementById(id);
20}
21
22function log(txt) {
23 console.log(txt);
24}
25
26function openCamera() {
27 if (mystream) {
28 mystream.stop();
29 }
30 navigator.webkitGetUserMedia(cameraConstraints(), gotStream, function() {
31 log("GetUserMedia failed");
32 });
33}
34
35function gotStream(stream) {
36 log("GetUserMedia succeeded");
37 mystream = stream;
38 $("local-video").src = webkitURL.createObjectURL(stream);
39}
40
41function cameraConstraints() {
42 var constraints = {};
43 constraints.audio = true;
44 constraints.video = { mandatory: {}, optional: [] };
45 if ($("minwidth").value != "0") {
46 constraints.video.mandatory.minWidth = $("minwidth").value;
47 }
48 if ($("maxwidth").value != "0") {
49 constraints.video.mandatory.maxWidth = $("maxwidth").value;
50 }
51 if ($("minheight").value != "0") {
52 constraints.video.mandatory.minHeight = $("minheight").value;
53 }
54 if ($("maxheight").value != "0") {
55 constraints.video.mandatory.maxHeight = $("maxheight").value;
56 }
57 if ($("frameRate").value != "0") {
58 constraints.video.mandatory.minFrameRate = $("frameRate").value;
59 }
60 log('Camera constraints are ' + JSON.stringify(constraints));
61 $("cameraConstraints").innerHTML = JSON.stringify(constraints, null, ' ');
62 return constraints;
63}
64
65function streamConstraints() {
66 var constraints = { mandatory: {}, optional: [] };
67 if ($("bandwidth").value != "0") {
68 constraints.optional[0] = { 'bandwidth' : $('bandwidth').value };
69 }
70 log('Constraints are ' + JSON.stringify(constraints));
71 $("addStreamConstraints").innerHTML = JSON.stringify(constraints, null, ' ');
72 return constraints;
73}
74
75
76
77function connect() {
78 pc1 = new webkitRTCPeerConnection(null);
79 pc2 = new webkitRTCPeerConnection(null);
80 pc1.addStream(mystream, streamConstraints());
81 log('PC1 creating offer');
82 pc1.onnegotiationeeded = function() {
83 log('Negotiation needed - PC1');
84 }
85 pc2.onnegotiationeeded = function() {
86 log('Negotiation needed - PC2');
87 }
88 pc1.onicecandidate = function(e) {
89 log('Candidate PC1');
90 if (e.candidate) {
91 pc2.addIceCandidate(new RTCIceCandidate(e.candidate));
92 }
93 }
94 pc2.onicecandidate = function(e) {
95 log('Candidate PC2');
96 if (e.candidate) {
97 pc1.addIceCandidate(new RTCIceCandidate(e.candidate));
98 }
99 }
100 pc2.onaddstream = function(e) {
101 log('PC2 got stream');
102 $('remote-video').src = webkitURL.createObjectURL(e.stream);
103 log('Remote video is ' + $('remote-video').src);
104 }
105 pc1.createOffer(function(desc) {
106 log('PC1 offering');
107 pc1.setLocalDescription(desc);
108 pc2.setRemoteDescription(desc);
109 pc2.createAnswer(function(desc2) {
110 log('PC2 answering');
111 pc2.setLocalDescription(desc2);
112 pc1.setRemoteDescription(desc2);
113 });
114 });
115}
116
117// Display statistics
118var statCollector = setInterval(function() {
119 var display = function(str) {
120 $('bitrate').innerHTML = str;
121 }
122
123 display("No stream");
hta@webrtc.orgdb3f4272013-03-05 15:23:40 +0000124 if (pc2 && pc2.getRemoteStreams()[0]) {
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000125 if (pc2.getStats) {
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000126 pc2.getStats(function(stats) {
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000127 var statsString = '';
128 var results = stats.result();
hta@webrtc.org3ed599a2013-03-22 08:48:16 +0000129 var bitrateText = 'No bitrate stats';
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000130 for (var i = 0; i < results.length; ++i) {
131 var res = results[i];
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000132 statsString += '<h3>Report ';
133 statsString += i;
134 statsString += '</h3>';
hta@webrtc.orgecfd3282013-03-19 08:45:47 +0000135 if (!res.local || res.local === res) {
136 statsString += dumpStats(res);
hta@webrtc.org3ed599a2013-03-22 08:48:16 +0000137 // The bandwidth info for video is in a type ssrc stats record
138 // with googFrameHeightReceived defined.
139 // Should check for mediatype = video, but this is not
140 // implemented yet.
141 if (res.type == 'ssrc' && res.stat('googFrameHeightReceived')) {
142 var bytesNow = res.stat('bytesReceived');
143 if (timestampPrev > 0) {
144 var bitRate = Math.round((bytesNow - bytesPrev) * 8 /
145 (res.timestamp - timestampPrev));
146 bitrateText = bitRate + ' kbits/sec';
147 }
148 timestampPrev = res.timestamp;
149 bytesPrev = bytesNow;
150 }
hta@webrtc.orgecfd3282013-03-19 08:45:47 +0000151 } else {
152 // Pre-227.0.1445 (188719) browser
153 if (res.local) {
154 statsString += "<p>Local ";
155 statsString += dumpStats(res.local);
156 }
157 if (res.remote) {
158 statsString += "<p>Remote ";
159 statsString += dumpStats(res.remote);
160 }
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000161 }
162 }
hta@webrtc.org37bf5842013-04-06 10:05:55 +0000163 $('receiverstats').innerHTML = statsString;
hta@webrtc.org3ed599a2013-03-22 08:48:16 +0000164 display(bitrateText);
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000165 });
hta@webrtc.org37bf5842013-04-06 10:05:55 +0000166 pc1.getStats(function(stats) {
167 var statsString = '';
168 var results = stats.result();
169 for (var i = 0; i < results.length; ++i) {
170 var res = results[i];
171 statsString += '<h3>Report ';
172 statsString += i;
173 statsString += '</h3>';
174 if (!res.local || res.local === res) {
175 statsString += dumpStats(res);
176 }
177 }
178 $('senderstats').innerHTML = statsString;
179 });
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000180 } else {
181 display('No stats function. Use at least Chrome 24.0.1285');
182 }
183 } else {
184 log('Not connected yet');
185 }
186 // Collect some stats from the video tags.
187 local_video = $('local-video');
188 if (local_video) {
189 $('local-video-stats').innerHTML = local_video.videoWidth +
190 'x' + local_video.videoHeight;
191 }
192 remote_video = $('remote-video');
193 if (remote_video) {
194 $('remote-video-stats').innerHTML = remote_video.videoWidth +
195 'x' + remote_video.videoHeight;
196 }
197}, 1000);
198
199// Dumping a stats variable as a string.
200// might be named toString?
201function dumpStats(obj) {
202 var statsString = 'Timestamp:';
203 statsString += obj.timestamp;
hta@webrtc.org3ed599a2013-03-22 08:48:16 +0000204 if (obj.id) {
hta@webrtc.org37bf5842013-04-06 10:05:55 +0000205 statsString += "<br>id ";
hta@webrtc.org3ed599a2013-03-22 08:48:16 +0000206 statsString += obj.id;
207 }
208 if (obj.type) {
209 statsString += " type ";
210 statsString += obj.type;
211 }
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000212 if (obj.names) {
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000213 names = obj.names();
214 for (var i = 0; i < names.length; ++i) {
215 statsString += '<br>';
216 statsString += names[i];
217 statsString += ':';
218 statsString += obj.stat(names[i]);
219 }
220 } else {
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000221 if (obj.stat('audioOutputLevel')) {
222 statsString += "audioOutputLevel: ";
223 statsString += obj.stat('audioOutputLevel');
224 statsString += "<br>";
225 }
226 }
227 return statsString;
228}
229
230
231// Utility to show the value of a field in a span called name+Display
232function showValue(name, value) {
233 $(name + 'Display').innerHTML = value;
234}
235</script>
236</head>
237<body>
238<h1>Constraints and Statistics</h1>
239This page is meant to give some hints on how one can use constraints and statistics in WebRTC applications.
240<p>
241The form to the left gives constraints you can set on the getUserMedia call.
242When you hit "open", it will (re)open the camera with these constraints.
243<p>
244The left picture is the local preview. The right picture is the picture
245after being passed through the PeerConnection (locally).
246<p>
247Underneath the picture you will see a running display of how many Kbits/sec
248the video feed uses for transmission.
249<hr>
250<table>
251<tr>
252<td align="top">
253<h2>getUserMedia constraints</h2>
254<table>
255<tr><td><td>Min<td>Max
256<tr><td>Horizontal
257<td><input type="range" id="minwidth" min="0" max="1280" value="300"
258 onchange="showValue(this.id, this.value)">
259<td><input type="range" id="maxwidth" min="0" max="1280" value="640"
260 onchange="showValue(this.id, this.value)">
261<td><span id="minwidthDisplay">300</span>-<span id="maxwidthDisplay">640</span>
262<tr><td>Vertical
263<td><input type="range" id="minheight" min="0" max="1280" value="200"
264 onchange="showValue(this.id, this.value)">
265<td><input type="range" id="maxheight" min="0" max="1280" value="480"
266 onchange="showValue(this.id, this.value)">
267<td><span id="minheightDisplay">200</span>-<span id="maxheightDisplay">480</span>
268<tr><td>
269FrameRate
270<td colspan=2><input type="range" id="frameRate" min="0" max="60" value="30"
271 onchange="showValue(this.id, this.value)">
272<td><span id="frameRateDisplay">30</span>
273</table>
274<input type="submit" name="capture" value="Capture!" onclick="openCamera()">
275</td>
276<td align="top">
277<h2>addStream constraints</h2>
278Maximum bitrate
279<input type="range" id="bandwidth" min="0" max="2000" value="1000"
280 onchange="showValue(this.id, this.value)">
281<span id="bandwidthDisplay">1000</span>
282<br>
283<input type="submit" name="connect" value="Connect!" onclick="connect()">
284</td>
285</tr>
286<tr>
287<td>
vikasmarwaha@webrtc.orgda0f7082013-03-11 16:58:07 +0000288<video id="local-video" autoplay width=400 muted="true"></video>
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000289</td>
290<td>
291<video id="remote-video" autoplay width=400></video>
292</td>
293<tr>
294<td><span id="local-video-stats"></span>
295<td><span id="remote-video-stats"></span>
296<br>
297<span id="bitrate">Bitrate unknown</span>
298</td>
299</tr>
300<tr>
301<td><pre><span id="cameraConstraints"></span></pre>
302<td><pre><span id="addStreamConstraints"></span></pre>
303</table>
304<h2>Statistics report display</h2>
hta@webrtc.org37bf5842013-04-06 10:05:55 +0000305<table>
306<tr>
307<th>Sender side<th>Receiver side
308<tr>
309<td align="top"><div id="senderstats">Stats will appear here.</div>
310<td align="top"><div id="receiverstats">Stats will appear here.</div>
311</table>
vikasmarwaha@webrtc.org98fce152013-02-27 23:22:10 +0000312</body>
313</html>