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