Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(149)

Side by Side Diff: content/test/data/media/peerconnection-call.html

Issue 11785041: Add content browser tests for PeerConnection DataChannels. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Created 7 years, 11 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
1 <html> 1 <html>
2 <head> 2 <head>
3 <script type="text/javascript"> 3 <script type="text/javascript">
4 $ = function(id) { 4 $ = function(id) {
5 return document.getElementById(id); 5 return document.getElementById(id);
6 }; 6 };
7 7
8 var gFirstConnection = null; 8 var gFirstConnection = null;
9 var gSecondConnection = null; 9 var gSecondConnection = null;
10 var gTestWithoutMsidAndBundle = false; 10 var gTestWithoutMsidAndBundle = false;
11 11
12 // Number of conditions to meet before the test pass. When the test pass, the
13 // document title change to OK.
phoglund_chromium 2013/01/09 12:40:36 I think a better name here is gNumberOfEvents and
perkj_chrome 2013/01/09 13:56:21 Done.
14 var gNumberOfExitConditions = 0;
15
16 // Number of conditions that currently have been met.
17 var gNumberOfExitConditionsMet = 0;
18
19 // Test that we can setup call with an audio and video track.
12 function call(constraints) { 20 function call(constraints) {
21 createConnections(null);
13 navigator.webkitGetUserMedia(constraints, okCallback, failedCallback); 22 navigator.webkitGetUserMedia(constraints, okCallback, failedCallback);
23 waitForVideo($('remote-view'), 320, 240);
14 } 24 }
15 25
26 // Test that we can setup call with an audio and video track and
27 // simulate that the remote peer don't support MSID.
16 function callWithoutMsidAndBundle() { 28 function callWithoutMsidAndBundle() {
29 createConnections(null);
17 gTestWithoutMsidAndBundle = true; 30 gTestWithoutMsidAndBundle = true;
18 navigator.webkitGetUserMedia({audio:true, video:true}, okCallback, 31 navigator.webkitGetUserMedia({audio:true, video:true}, okCallback,
19 failedCallback); 32 failedCallback);
33 waitForVideo($('remote-view'), 320, 240);
20 } 34 }
35
36 // Test only a data channel.
37 function callWithDataOnly() {
38 createConnections({optional:[{RtpDataChannels: true}]});
39 setupDataChannel();
40 gFirstConnection.createOffer(onOfferCreated);
41 }
42
43 // Test call with audio, video and a data channel.
44 function callWithDataAndMedia() {
45 createConnections({optional:[{RtpDataChannels: true}]});
46 setupDataChannel();
47 navigator.webkitGetUserMedia({audio:true, video:true}, okCallback,
48 failedCallback);
49 waitForVideo($('remote-view'), 320, 240);
50 }
51
52 // Test call with a data channel and later add audio and video.
53 function callWithDataAndLaterAddMedia() {
54 // TODO(perkj): This is needed for now until
55 // https://code.google.com/p/webrtc/issues/detail?id=1203 is fixed.
56 gTestWithoutMsidAndBundle = true;
57
58 createConnections({optional:[{RtpDataChannels: true}]});
59 setupDataChannel();
60 gFirstConnection.createOffer(onOfferCreated);
61
62 navigator.webkitGetUserMedia({audio:true, video:true}, okCallback,
63 failedCallback);
64 waitForVideo($('remote-view'), 320, 240);
65 }
66
phoglund_chromium 2013/01/09 12:40:36 Perhaps it would be nice to number the events, lik
perkj_chrome 2013/01/09 13:56:21 Done.
67 // Create a data channel on |gFirstConnection| and sends data to
phoglund_chromium 2013/01/09 12:40:36 Nit: line length
perkj_chrome 2013/01/09 13:56:21 Done.
68 // |gSecondConnection|. When data is received on |gSecondConnection| a message
69 // is sent to |gFirstConnection|.
70 // When data is received on |gFirstConnection|, the data
71 // channel is closed again. The test pass when |dataChannel.readyState| has
72 // transitioned to closed after an offer/answer exchange.
73 function setupDataChannel() {
74 var sendDataString = "send some text on a data channel."
75 dataChannel = gFirstConnection.createDataChannel(
76 "sendDataChannel", {reliable : false});
77 expectEquals('connecting', dataChannel.readyState);
78
79 dataChannel.onmessage = function(event) {
80 expectEquals(event.data, sendDataString);
81 dataChannel.close();
82 gFirstConnection.createOffer(onOfferCreated);
83 }
84
85 dataChannel.onopen = function() {
86 expectEquals('open', dataChannel.readyState);
87 dataChannel.send(sendDataString);
88 }
89
90 gSecondConnection.ondatachannel = function (event) {
phoglund_chromium 2013/01/09 12:40:36 This shadows a variable in the outer scope, which
perkj_chrome 2013/01/09 13:56:21 renamed. I would prefer to not break out anyting s
phoglund_chromium 2013/01/09 16:36:45 Ok, fair enough.
91 var dataChannel = event.channel;
92 var messageReceived = false;
93 dataChannel.onmessage = function(event) {
94 expectEquals(event.data, sendDataString);
95 // TODO(perkj): Currently we sometimes can't send a message here since
96 // the the |dataChannel.readyState| has not transitioned to open yet.
97 // http://code.google.com/p/webrtc/issues/detail?id=1262
98 messageReceived = true;
phoglund_chromium 2013/01/09 12:40:36 Hm. Ok, so this whole messageReceived thing is use
perkj_chrome 2013/01/09 13:56:21 Done.
99 if (dataChannel.readyState == "open") {
100 dataChannel.send(sendDataString);
101 }
102 }
103 dataChannel.onopen = function(event) {
104 expectEquals('open', dataChannel.readyState);
105 if (messageReceived) {
106 dataChannel.send(sendDataString);
107 }
108 }
109 }
110
111 addExitCondition();
112 dataChannel.onclose = function() {
113 expectEquals('closed', dataChannel.readyState);
114 testSuccessful();
115 }
116 }
21 117
22 function failedCallback(error) { 118 function failedCallback(error) {
23 document.title = 'getUserMedia request failed with code ' + error.code; 119 document.title = 'getUserMedia request failed with code ' + error.code;
24 } 120 }
25 121
26 function okCallback(localStream) { 122 function okCallback(localStream) {
27 var localStreamUrl = webkitURL.createObjectURL(localStream); 123 var localStreamUrl = webkitURL.createObjectURL(localStream);
28 $('local-view').src = localStreamUrl; 124 $('local-view').src = localStreamUrl;
29 125
30 callUsingStream(localStream); 126 callUsingStream(localStream);
31 } 127 }
32 128
33 function callUsingStream(localStream) { 129 function createConnections(constraints) {
34 gFirstConnection = new webkitRTCPeerConnection(null, null); 130 gFirstConnection = new webkitRTCPeerConnection(null, constraints);
35 gFirstConnection.onicecandidate = onIceCandidateToFirst; 131 gFirstConnection.onicecandidate = onIceCandidateToFirst;
132
133 gSecondConnection = new webkitRTCPeerConnection(null, constraints);
134 gSecondConnection.onicecandidate = onIceCandidateToSecond;
135 gSecondConnection.onaddstream = onRemoteStream;
136 }
137
138 function callUsingStream(localStream) {
36 gFirstConnection.addStream(localStream); 139 gFirstConnection.addStream(localStream);
37 gFirstConnection.createOffer(onOfferCreated); 140 gFirstConnection.createOffer(onOfferCreated);
38 } 141 }
39 142
40 function onOfferCreated(offer) { 143 function onOfferCreated(offer) {
41 gFirstConnection.setLocalDescription(offer); 144 gFirstConnection.setLocalDescription(offer);
42 145 receiveOffer(offer.sdp);
43 receiveCall(offer.sdp);
44 } 146 }
45 147
46 function receiveCall(offerSdp) { 148 function receiveOffer(offerSdp) {
47 if (gTestWithoutMsidAndBundle) { 149 if (gTestWithoutMsidAndBundle) {
48 offerSdp = removeMsidAndBundle(offerSdp); 150 offerSdp = removeMsidAndBundle(offerSdp);
49 } 151 }
50 gSecondConnection = new webkitRTCPeerConnection(null, null);
51 gSecondConnection.onicecandidate = onIceCandidateToSecond;
52 gSecondConnection.onaddstream = onRemoteStream;
53 152
54 var parsedOffer = new RTCSessionDescription({ type: 'offer', 153 var parsedOffer = new RTCSessionDescription({ type: 'offer',
55 sdp: offerSdp }); 154 sdp: offerSdp });
56 gSecondConnection.setRemoteDescription(parsedOffer); 155 gSecondConnection.setRemoteDescription(parsedOffer);
57
58 gSecondConnection.createAnswer(onAnswerCreated); 156 gSecondConnection.createAnswer(onAnswerCreated);
59 } 157 }
60 158
61 function removeMsidAndBundle(offerSdp) { 159 function removeMsidAndBundle(offerSdp) {
62 offerSdp = offerSdp.replace(/a=msid-semantics.*\r\n/g, ''); 160 offerSdp = offerSdp.replace(/a=msid-semantics.*\r\n/g, '');
63 offerSdp = offerSdp.replace('a=group:BUNDLE audio video\r\n', ''); 161 offerSdp = offerSdp.replace('a=group:BUNDLE audio video\r\n', '');
64 offerSdp = offerSdp.replace('a=mid:audio\r\n', ''); 162 offerSdp = offerSdp.replace('a=mid:audio\r\n', '');
65 offerSdp = offerSdp.replace('a=mid:video\r\n', ''); 163 offerSdp = offerSdp.replace('a=mid:video\r\n', '');
66 offerSdp = offerSdp.replace(/a=ssrc.*\r\n/g, ''); 164 offerSdp = offerSdp.replace(/a=ssrc.*\r\n/g, '');
67 return offerSdp; 165 return offerSdp;
(...skipping 18 matching lines...) Expand all
86 } 184 }
87 185
88 function onIceCandidateToSecond(event) { 186 function onIceCandidateToSecond(event) {
89 if (event.candidate) { 187 if (event.candidate) {
90 var candidate = new RTCIceCandidate(event.candidate); 188 var candidate = new RTCIceCandidate(event.candidate);
91 gFirstConnection.addIceCandidate(candidate); 189 gFirstConnection.addIceCandidate(candidate);
92 } 190 }
93 } 191 }
94 192
95 function onRemoteStream(e) { 193 function onRemoteStream(e) {
96 var remoteStreamUrl = webkitURL.createObjectURL(e.stream);
97 var remoteVideo = $('remote-view');
98 remoteVideo.src = remoteStreamUrl;
99
100 if (gTestWithoutMsidAndBundle && e.stream.label != "default") { 194 if (gTestWithoutMsidAndBundle && e.stream.label != "default") {
101 document.title = 'a default remote stream was expected but instead ' + 195 document.title = 'a default remote stream was expected but instead ' +
102 e.stream.label + ' was received.'; 196 e.stream.label + ' was received.';
103 return; 197 return;
104 } 198 }
105 199 var remoteStreamUrl = webkitURL.createObjectURL(e.stream);
106 waitForVideo(remoteVideo, 320, 240); 200 var remoteVideo = $('remote-view');
201 remoteVideo.src = remoteStreamUrl;
107 } 202 }
108 203
109 // TODO(phoglund): perhaps use the video detector in chrome/test/data/webrtc/? 204 // TODO(phoglund): perhaps use the video detector in chrome/test/data/webrtc/?
110 function waitForVideo(videoElement, width, height) { 205 function waitForVideo(videoElement, width, height) {
111 document.title = 'Waiting for video...'; 206 document.title = 'Waiting for video...';
phoglund_chromium 2013/01/09 12:40:36 Use addExitConditions.
perkj_chrome 2013/01/09 13:56:21 Done.
207 ++gNumberOfExitConditions;
112 var canvas = $('canvas'); 208 var canvas = $('canvas');
113 setInterval(function() { 209 setInterval(function() {
114 var context = canvas.getContext('2d'); 210 var context = canvas.getContext('2d');
115 context.drawImage(videoElement, 0, 0, width, height); 211 context.drawImage(videoElement, 0, 0, width, height);
116 var pixels = context.getImageData(0, 0, width, height).data; 212 var pixels = context.getImageData(0, 0, width, height).data;
117 213
118 if (isVideoPlaying(pixels, width, height)) 214 if (isVideoPlaying(pixels, width, height))
119 testSuccessful(); 215 testSuccessful();
120 }, 100); 216 }, 100);
121 } 217 }
122 218
123 // This very basic video verification algorithm will be satisfied if any 219 // This very basic video verification algorithm will be satisfied if any
124 // pixels are nonzero in a small sample area in the middle. It relies on the 220 // pixels are nonzero in a small sample area in the middle. It relies on the
125 // assumption that a video element with null source just presents zeroes. 221 // assumption that a video element with null source just presents zeroes.
126 function isVideoPlaying(pixels, width, height) { 222 function isVideoPlaying(pixels, width, height) {
127 // Sample somewhere near the middle of the image. 223 // Sample somewhere near the middle of the image.
128 var middle = width * height / 2; 224 var middle = width * height / 2;
129 for (var i = 0; i < 20; i++) { 225 for (var i = 0; i < 20; i++) {
130 if (pixels[middle + i] > 0) { 226 if (pixels[middle + i] > 0) {
131 return true; 227 return true;
132 } 228 }
133 } 229 }
134 return false; 230 return false;
135 } 231 }
232
233
234 // This function matches |left| and |right| and throws an exception if the
235 // values don't match.
236 function expectEquals(left, right) {
237 if (left != right) {
238 var s = "expectEquals failed left: " + left + " right: " + right;
239 document.title = s;
240 throw s;
241 }
242 }
136 243
244 function addExitCondition() {
245 ++gNumberOfExitConditions;
246 }
247
137 function testSuccessful() { 248 function testSuccessful() {
phoglund_chromium 2013/01/09 12:40:36 Why is testSuccessful an exit condition?...
perkj_chrome 2013/01/09 13:56:21 Renamed to exitConditionMet. This is called when a
138 document.title = 'OK'; 249 ++gNumberOfExitConditionsMet;
250 if (gNumberOfExitConditionsMet == gNumberOfExitConditions) {
251 document.title = 'OK';
252 }
139 } 253 }
140 </script> 254 </script>
141 </head> 255 </head>
142 <body> 256 <body>
143 <table border="0"> 257 <table border="0">
144 <tr> 258 <tr>
145 <td>Local Preview</td> 259 <td>Local Preview</td>
146 <td>Remote Stream</td> 260 <td>Remote Stream</td>
147 <td>Capturing Canvas</td> 261 <td>Capturing Canvas</td>
148 </tr> 262 </tr>
149 <tr> 263 <tr>
150 <td><video width="320" height="240" id="local-view" 264 <td><video width="320" height="240" id="local-view"
151 autoplay="autoplay"></video></td> 265 autoplay="autoplay"></video></td>
152 <td><video width="320" height="240" id="remote-view" 266 <td><video width="320" height="240" id="remote-view"
153 autoplay="autoplay"></video></td> 267 autoplay="autoplay"></video></td>
154 <td><canvas width="320" height="240" id="canvas"></canvas></td> 268 <td><canvas width="320" height="240" id="canvas"></canvas></td>
155 </tr> 269 </tr>
156 <tr> 270 <tr>
157 <td colspan="3">You should see the same animated feed in all three 271 <td colspan="3">You should see the same animated feed in all three
158 displays (the canvas will lag a bit). 272 displays (the canvas will lag a bit).
159 </td> 273 </td>
160 </table> 274 </table>
161 </body> 275 </body>
162 </html> 276 </html>
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698