OLD | NEW |
1 /** | 1 /** |
2 * Copyright 2014 The Chromium Authors. All rights reserved. | 2 * Copyright 2014 The Chromium Authors. All rights reserved. |
3 * Use of this source code is governed by a BSD-style license that can be | 3 * Use of this source code is governed by a BSD-style license that can be |
4 * found in the LICENSE file. | 4 * found in the LICENSE file. |
5 */ | 5 */ |
6 | 6 |
7 /** | 7 /** |
8 * The one and only peer connection in this page. | 8 * The one and only peer connection in this page. |
9 * @private | 9 * @private |
10 */ | 10 */ |
(...skipping 26 matching lines...) Expand all Loading... |
37 gPeerConnection = createPeerConnection_(); | 37 gPeerConnection = createPeerConnection_(); |
38 returnToTest('ok-peerconnection-created'); | 38 returnToTest('ok-peerconnection-created'); |
39 } | 39 } |
40 | 40 |
41 /** | 41 /** |
42 * Asks this page to create a local offer. | 42 * Asks this page to create a local offer. |
43 * | 43 * |
44 * Returns a string on the format ok-(JSON encoded session description). | 44 * Returns a string on the format ok-(JSON encoded session description). |
45 * | 45 * |
46 * @param {!Object} constraints Any createOffer constraints. | 46 * @param {!Object} constraints Any createOffer constraints. |
| 47 * @param {string} videoCodec If not null, promotes the specified codec to be |
| 48 * the default video codec, e.g. the first one in the list on the 'm=video' |
| 49 * SDP offer line. |videoCodec| is the case-sensitive codec name, e.g. |
| 50 * 'VP8' or 'H264'. |
47 */ | 51 */ |
48 function createLocalOffer(constraints) { | 52 function createLocalOffer(constraints, videoCodec = null) { |
49 peerConnection_().createOffer( | 53 peerConnection_().createOffer( |
50 function(localOffer) { | 54 function(localOffer) { |
51 success_('createOffer'); | 55 success('createOffer'); |
| 56 |
52 setLocalDescription(peerConnection, localOffer); | 57 setLocalDescription(peerConnection, localOffer); |
| 58 if (videoCodec !== null) |
| 59 localOffer.sdp = setSdpDefaultVideoCodec(localOffer.sdp, videoCodec); |
53 | 60 |
54 returnToTest('ok-' + JSON.stringify(localOffer)); | 61 returnToTest('ok-' + JSON.stringify(localOffer)); |
55 }, | 62 }, |
56 function(error) { failure_('createOffer', error); }, | 63 function(error) { failure('createOffer', error); }, |
57 constraints); | 64 constraints); |
58 } | 65 } |
59 | 66 |
60 /** | 67 /** |
61 * Asks this page to accept an offer and generate an answer. | 68 * Asks this page to accept an offer and generate an answer. |
62 * | 69 * |
63 * Returns a string on the format ok-(JSON encoded session description). | 70 * Returns a string on the format ok-(JSON encoded session description). |
64 * | 71 * |
65 * @param {!string} sessionDescJson A JSON-encoded session description of type | 72 * @param {!string} sessionDescJson A JSON-encoded session description of type |
66 * 'offer'. | 73 * 'offer'. |
67 * @param {!Object} constraints Any createAnswer constraints. | 74 * @param {!Object} constraints Any createAnswer constraints. |
68 */ | 75 */ |
69 function receiveOfferFromPeer(sessionDescJson, constraints) { | 76 function receiveOfferFromPeer(sessionDescJson, constraints) { |
70 offer = parseJson_(sessionDescJson); | 77 offer = parseJson_(sessionDescJson); |
71 if (!offer.type) | 78 if (!offer.type) |
72 failTest('Got invalid session description from peer: ' + sessionDescJson); | 79 failTest('Got invalid session description from peer: ' + sessionDescJson); |
73 if (offer.type != 'offer') | 80 if (offer.type != 'offer') |
74 failTest('Expected to receive offer from peer, got ' + offer.type); | 81 failTest('Expected to receive offer from peer, got ' + offer.type); |
75 | 82 |
76 var sessionDescription = new RTCSessionDescription(offer); | 83 var sessionDescription = new RTCSessionDescription(offer); |
77 peerConnection_().setRemoteDescription( | 84 peerConnection_().setRemoteDescription( |
78 sessionDescription, | 85 sessionDescription, |
79 function() { success_('setRemoteDescription'); }, | 86 function() { success('setRemoteDescription'); }, |
80 function(error) { failure_('setRemoteDescription', error); }); | 87 function(error) { failure('setRemoteDescription', error); }); |
81 | 88 |
82 peerConnection_().createAnswer( | 89 peerConnection_().createAnswer( |
83 function(answer) { | 90 function(answer) { |
84 success_('createAnswer'); | 91 success('createAnswer'); |
85 setLocalDescription(peerConnection, answer); | 92 setLocalDescription(peerConnection, answer); |
86 returnToTest('ok-' + JSON.stringify(answer)); | 93 returnToTest('ok-' + JSON.stringify(answer)); |
87 }, | 94 }, |
88 function(error) { failure_('createAnswer', error); }, | 95 function(error) { failure('createAnswer', error); }, |
89 constraints); | 96 constraints); |
90 } | 97 } |
91 | 98 |
92 /** | 99 /** |
| 100 * Verifies that the specified codec is the default video codec, e.g. the first |
| 101 * one in the list on the 'm=video' SDP answer line. If this is not the case, |
| 102 * |failure| occurs. |
| 103 * |
| 104 * @param {!string} sessionDescJson A JSON-encoded session description. |
| 105 * @param {!string} expectedVideoCodec The case-sensitive codec name, e.g. |
| 106 * 'VP8' or 'H264'. |
| 107 */ |
| 108 function verifyDefaultVideoCodec(sessionDescJson, expectedVideoCodec) { |
| 109 var sessionDesc = parseJson_(sessionDescJson); |
| 110 if (!sessionDesc.type) { |
| 111 failure('verifyDefaultVideoCodec', |
| 112 'Invalid session description: ' + sessionDescJson); |
| 113 } |
| 114 var defaultVideoCodec = getSdpDefaultVideoCodec(sessionDesc.sdp); |
| 115 if (defaultVideoCodec === null) { |
| 116 failure('verifyDefaultVideoCodec', |
| 117 'Could not determine default video codec.'); |
| 118 } |
| 119 if (expectedVideoCodec !== defaultVideoCodec) { |
| 120 failure('verifyDefaultVideoCodec', |
| 121 'Expected default video codec ' + expectedVideoCodec + |
| 122 ', got ' + defaultVideoCodec + '.'); |
| 123 } |
| 124 returnToTest('ok-verified'); |
| 125 } |
| 126 |
| 127 /** |
93 * Asks this page to accept an answer generated by the peer in response to a | 128 * Asks this page to accept an answer generated by the peer in response to a |
94 * previous offer by this page | 129 * previous offer by this page |
95 * | 130 * |
96 * Returns a string ok-accepted-answer on success. | 131 * Returns a string ok-accepted-answer on success. |
97 * | 132 * |
98 * @param {!string} sessionDescJson A JSON-encoded session description of type | 133 * @param {!string} sessionDescJson A JSON-encoded session description of type |
99 * 'answer'. | 134 * 'answer'. |
100 */ | 135 */ |
101 function receiveAnswerFromPeer(sessionDescJson) { | 136 function receiveAnswerFromPeer(sessionDescJson) { |
102 answer = parseJson_(sessionDescJson); | 137 answer = parseJson_(sessionDescJson); |
103 if (!answer.type) | 138 if (!answer.type) |
104 failTest('Got invalid session description from peer: ' + sessionDescJson); | 139 failTest('Got invalid session description from peer: ' + sessionDescJson); |
105 if (answer.type != 'answer') | 140 if (answer.type != 'answer') |
106 failTest('Expected to receive answer from peer, got ' + answer.type); | 141 failTest('Expected to receive answer from peer, got ' + answer.type); |
107 | 142 |
108 var sessionDescription = new RTCSessionDescription(answer); | 143 var sessionDescription = new RTCSessionDescription(answer); |
109 peerConnection_().setRemoteDescription( | 144 peerConnection_().setRemoteDescription( |
110 sessionDescription, | 145 sessionDescription, |
111 function() { | 146 function() { |
112 success_('setRemoteDescription'); | 147 success('setRemoteDescription'); |
113 returnToTest('ok-accepted-answer'); | 148 returnToTest('ok-accepted-answer'); |
114 }, | 149 }, |
115 function(error) { failure_('setRemoteDescription', error); }); | 150 function(error) { failure('setRemoteDescription', error); }); |
116 } | 151 } |
117 | 152 |
118 /** | 153 /** |
119 * Adds the local stream to the peer connection. You will have to re-negotiate | 154 * Adds the local stream to the peer connection. You will have to re-negotiate |
120 * the call for this to take effect in the call. | 155 * the call for this to take effect in the call. |
121 */ | 156 */ |
122 function addLocalStream() { | 157 function addLocalStream() { |
123 addLocalStreamToPeerConnection(peerConnection_()); | 158 addLocalStreamToPeerConnection(peerConnection_()); |
124 returnToTest('ok-added'); | 159 returnToTest('ok-added'); |
125 } | 160 } |
(...skipping 61 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
187 if (!iceCandidates.length) | 222 if (!iceCandidates.length) |
188 throw failTest('Received invalid ICE candidate list from peer: ' + | 223 throw failTest('Received invalid ICE candidate list from peer: ' + |
189 iceCandidatesJson); | 224 iceCandidatesJson); |
190 | 225 |
191 iceCandidates.forEach(function(iceCandidate) { | 226 iceCandidates.forEach(function(iceCandidate) { |
192 if (!iceCandidate.candidate) | 227 if (!iceCandidate.candidate) |
193 failTest('Received invalid ICE candidate from peer: ' + | 228 failTest('Received invalid ICE candidate from peer: ' + |
194 iceCandidatesJson); | 229 iceCandidatesJson); |
195 | 230 |
196 peerConnection_().addIceCandidate(new RTCIceCandidate(iceCandidate, | 231 peerConnection_().addIceCandidate(new RTCIceCandidate(iceCandidate, |
197 function() { success_('addIceCandidate'); }, | 232 function() { success('addIceCandidate'); }, |
198 function(error) { failure_('addIceCandidate', error); } | 233 function(error) { failure('addIceCandidate', error); } |
199 )); | 234 )); |
200 }); | 235 }); |
201 | 236 |
202 returnToTest('ok-received-candidates'); | 237 returnToTest('ok-received-candidates'); |
203 } | 238 } |
204 | 239 |
205 /** | 240 /** |
206 * Sets the mute state of the selected media element. | 241 * Sets the mute state of the selected media element. |
207 * | 242 * |
208 * Returns ok-muted on success. | 243 * Returns ok-muted on success. |
(...skipping 32 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
241 } | 276 } |
242 | 277 |
243 /** @private */ | 278 /** @private */ |
244 function peerConnection_() { | 279 function peerConnection_() { |
245 if (gPeerConnection == null) | 280 if (gPeerConnection == null) |
246 throw failTest('Trying to use peer connection, but none was created.'); | 281 throw failTest('Trying to use peer connection, but none was created.'); |
247 return gPeerConnection; | 282 return gPeerConnection; |
248 } | 283 } |
249 | 284 |
250 /** @private */ | 285 /** @private */ |
251 function success_(method) { | |
252 debug(method + '(): success.'); | |
253 } | |
254 | |
255 /** @private */ | |
256 function failure_(method, error) { | |
257 throw failTest(method + '() failed: ' + JSON.stringify(error)); | |
258 } | |
259 | |
260 /** @private */ | |
261 function iceCallback_(event) { | 286 function iceCallback_(event) { |
262 if (event.candidate) | 287 if (event.candidate) |
263 gIceCandidates.push(event.candidate); | 288 gIceCandidates.push(event.candidate); |
264 } | 289 } |
265 | 290 |
266 /** @private */ | 291 /** @private */ |
267 function setLocalDescription(peerConnection, sessionDescription) { | 292 function setLocalDescription(peerConnection, sessionDescription) { |
268 if (sessionDescription.sdp.search('a=crypto') != -1 || | 293 if (sessionDescription.sdp.search('a=crypto') != -1 || |
269 sessionDescription.sdp.search('a=fingerprint') != -1) | 294 sessionDescription.sdp.search('a=fingerprint') != -1) |
270 gHasSeenCryptoInSdp = 'crypto-seen'; | 295 gHasSeenCryptoInSdp = 'crypto-seen'; |
271 | 296 |
272 peerConnection.setLocalDescription( | 297 peerConnection.setLocalDescription( |
273 sessionDescription, | 298 sessionDescription, |
274 function() { success_('setLocalDescription'); }, | 299 function() { success('setLocalDescription'); }, |
275 function(error) { failure_('setLocalDescription', error); }); | 300 function(error) { failure('setLocalDescription', error); }); |
276 } | 301 } |
277 | 302 |
278 /** @private */ | 303 /** @private */ |
279 function addStreamCallback_(event) { | 304 function addStreamCallback_(event) { |
280 debug('Receiving remote stream...'); | 305 debug('Receiving remote stream...'); |
281 var videoTag = document.getElementById('remote-view'); | 306 var videoTag = document.getElementById('remote-view'); |
282 attachMediaStream(videoTag, event.stream); | 307 attachMediaStream(videoTag, event.stream); |
283 } | 308 } |
284 | 309 |
285 /** @private */ | 310 /** @private */ |
286 function removeStreamCallback_(event) { | 311 function removeStreamCallback_(event) { |
287 debug('Call ended.'); | 312 debug('Call ended.'); |
288 document.getElementById('remote-view').src = ''; | 313 document.getElementById('remote-view').src = ''; |
289 } | 314 } |
290 | 315 |
291 /** | 316 /** |
292 * Parses JSON-encoded session descriptions and ICE candidates. | 317 * Parses JSON-encoded session descriptions and ICE candidates. |
293 * @private | 318 * @private |
294 */ | 319 */ |
295 function parseJson_(json) { | 320 function parseJson_(json) { |
296 // Escape since the \r\n in the SDP tend to get unescaped. | 321 // Escape since the \r\n in the SDP tend to get unescaped. |
297 jsonWithEscapedLineBreaks = json.replace(/\r\n/g, '\\r\\n'); | 322 jsonWithEscapedLineBreaks = json.replace(/\r\n/g, '\\r\\n'); |
298 try { | 323 try { |
299 return JSON.parse(jsonWithEscapedLineBreaks); | 324 return JSON.parse(jsonWithEscapedLineBreaks); |
300 } catch (exception) { | 325 } catch (exception) { |
301 failTest('Failed to parse JSON: ' + jsonWithEscapedLineBreaks + ', got ' + | 326 failTest('Failed to parse JSON: ' + jsonWithEscapedLineBreaks + ', got ' + |
302 exception); | 327 exception); |
303 } | 328 } |
304 } | 329 } |
OLD | NEW |