Roll src/third_party/WebKit d9c6159:8139f33 (svn 201974:201975)
[chromium-blink-merge.git] / chrome / test / data / webrtc / peerconnection.js
blob00c0306535b757f5f7c578267ea18e382940bd78
1 /**
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
4  * found in the LICENSE file.
5  */
7 /**
8  * We need a STUN server for some API calls.
9  * @private
10  */
11 var STUN_SERVER = 'stun.l.google.com:19302';
13 /**
14  * The one and only peer connection in this page.
15  * @private
16  */
17 var gPeerConnection = null;
19 /**
20  * This stores ICE candidates generated on this side.
21  * @private
22  */
23 var gIceCandidates = [];
25 /**
26  * Keeps track of whether we have seen crypto information in the SDP.
27  * @private
28  */
29 var gHasSeenCryptoInSdp = 'no-crypto-seen';
31 // Public interface to tests. These are expected to be called with
32 // ExecuteJavascript invocations from the browser tests and will return answers
33 // through the DOM automation controller.
35 /**
36  * Creates a peer connection. Must be called before most other public functions
37  * in this file.
38  */
39 function preparePeerConnection() {
40   if (gPeerConnection != null)
41     throw failTest('creating peer connection, but we already have one.');
43   gPeerConnection = createPeerConnection_(STUN_SERVER);
44   returnToTest('ok-peerconnection-created');
47 /**
48  * Asks this page to create a local offer.
49  *
50  * Returns a string on the format ok-(JSON encoded session description).
51  *
52  * @param {!Object} constraints Any createOffer constraints.
53  */
54 function createLocalOffer(constraints) {
55   peerConnection_().createOffer(
56       function(localOffer) {
57         success_('createOffer');
58         setLocalDescription(peerConnection, localOffer);
60         returnToTest('ok-' + JSON.stringify(localOffer));
61       },
62       function(error) { failure_('createOffer', error); },
63       constraints);
66 /**
67  * Asks this page to accept an offer and generate an answer.
68  *
69  * Returns a string on the format ok-(JSON encoded session description).
70  *
71  * @param {!string} sessionDescJson A JSON-encoded session description of type
72  *     'offer'.
73  * @param {!Object} constraints Any createAnswer constraints.
74  */
75 function receiveOfferFromPeer(sessionDescJson, constraints) {
76   offer = parseJson_(sessionDescJson);
77   if (!offer.type)
78     failTest('Got invalid session description from peer: ' + sessionDescJson);
79   if (offer.type != 'offer')
80     failTest('Expected to receive offer from peer, got ' + offer.type);
82   var sessionDescription = new RTCSessionDescription(offer);
83   peerConnection_().setRemoteDescription(
84       sessionDescription,
85       function() { success_('setRemoteDescription'); },
86       function(error) { failure_('setRemoteDescription', error); });
88   peerConnection_().createAnswer(
89       function(answer) {
90         success_('createAnswer');
91         setLocalDescription(peerConnection, answer);
92         returnToTest('ok-' + JSON.stringify(answer));
93       },
94       function(error) { failure_('createAnswer', error); },
95       constraints);
98 /**
99  * Asks this page to accept an answer generated by the peer in response to a
100  * previous offer by this page
102  * Returns a string ok-accepted-answer on success.
104  * @param {!string} sessionDescJson A JSON-encoded session description of type
105  *     'answer'.
106  */
107 function receiveAnswerFromPeer(sessionDescJson) {
108   answer = parseJson_(sessionDescJson);
109   if (!answer.type)
110     failTest('Got invalid session description from peer: ' + sessionDescJson);
111   if (answer.type != 'answer')
112     failTest('Expected to receive answer from peer, got ' + answer.type);
114   var sessionDescription = new RTCSessionDescription(answer);
115   peerConnection_().setRemoteDescription(
116       sessionDescription,
117       function() {
118         success_('setRemoteDescription');
119         returnToTest('ok-accepted-answer');
120       },
121       function(error) { failure_('setRemoteDescription', error); });
125  * Adds the local stream to the peer connection. You will have to re-negotiate
126  * the call for this to take effect in the call.
127  */
128 function addLocalStream() {
129   addLocalStreamToPeerConnection(peerConnection_());
130   returnToTest('ok-added');
134  * Loads a file with WebAudio and connects it to the peer connection.
136  * The loadAudioAndAddToPeerConnection will return ok-added to the test when
137  * the sound is loaded and added to the peer connection. The sound will start
138  * playing when you call playAudioFile.
140  * @param url URL pointing to the file to play. You can assume that you can
141  *     serve files from the repository's file system. For instance, to serve a
142  *     file from chrome/test/data/pyauto_private/webrtc/file.wav, pass in a path
143  *     relative to this directory (e.g. ../pyauto_private/webrtc/file.wav).
144  */
145 function addAudioFile(url) {
146   loadAudioAndAddToPeerConnection(url, peerConnection_());
150  * Must be called after addAudioFile.
151  */
152 function playAudioFile() {
153   playPreviouslyLoadedAudioFile(peerConnection_());
154   returnToTest('ok-playing');
158  * Hangs up a started call. Returns ok-call-hung-up on success.
159  */
160 function hangUp() {
161   peerConnection_().close();
162   gPeerConnection = null;
163   returnToTest('ok-call-hung-up');
167  * Retrieves all ICE candidates generated on this side. Must be called after
168  * ICE candidate generation is triggered (for instance by running a call
169  * negotiation). This function will wait if necessary if we're not done
170  * generating ICE candidates on this side.
172  * Returns a JSON-encoded array of RTCIceCandidate instances to the test.
173  */
174 function getAllIceCandidates() {
175   if (peerConnection_().iceGatheringState != 'complete') {
176     console.log('Still ICE gathering - waiting...');
177     setTimeout(getAllIceCandidates, 100);
178     return;
179   }
181   returnToTest(JSON.stringify(gIceCandidates));
185  * Receives ICE candidates from the peer.
187  * Returns ok-received-candidates to the test on success.
189  * @param iceCandidatesJson a JSON-encoded array of RTCIceCandidate instances.
190  */
191 function receiveIceCandidates(iceCandidatesJson) {
192   var iceCandidates = parseJson_(iceCandidatesJson);
193   if (!iceCandidates.length)
194     throw failTest('Received invalid ICE candidate list from peer: ' +
195         iceCandidatesJson);
197   iceCandidates.forEach(function(iceCandidate) {
198     if (!iceCandidate.candidate)
199       failTest('Received invalid ICE candidate from peer: ' +
200           iceCandidatesJson);
202     peerConnection_().addIceCandidate(new RTCIceCandidate(iceCandidate,
203         function() { success_('addIceCandidate'); },
204         function(error) { failure_('addIceCandidate', error); }
205     ));
206   });
208   returnToTest('ok-received-candidates');
212  * Sets the mute state of the selected media element.
214  * Returns ok-muted on success.
216  * @param elementId The id of the element to mute.
217  * @param muted The mute state to set.
218  */
219 function setMediaElementMuted(elementId, muted) {
220   var element = document.getElementById(elementId);
221   if (!element)
222     throw failTest('Cannot mute ' + elementId + '; does not exist.');
223   element.muted = muted;
224   returnToTest('ok-muted');
228  * Returns
229  */
230 function hasSeenCryptoInSdp() {
231   returnToTest(gHasSeenCryptoInSdp);
234 // Internals.
236 /** @private */
237 function createPeerConnection_(stun_server) {
238   servers = {iceServers: [{url: 'stun:' + stun_server}]};
239   try {
240     peerConnection = new RTCPeerConnection(servers, {});
241   } catch (exception) {
242     throw failTest('Failed to create peer connection: ' + exception);
243   }
244   peerConnection.onaddstream = addStreamCallback_;
245   peerConnection.onremovestream = removeStreamCallback_;
246   peerConnection.onicecandidate = iceCallback_;
247   return peerConnection;
250 /** @private */
251 function peerConnection_() {
252   if (gPeerConnection == null)
253     throw failTest('Trying to use peer connection, but none was created.');
254   return gPeerConnection;
257 /** @private */
258 function success_(method) {
259   debug(method + '(): success.');
262 /** @private */
263 function failure_(method, error) {
264   throw failTest(method + '() failed: ' + JSON.stringify(error));
267 /** @private */
268 function iceCallback_(event) {
269   if (event.candidate)
270     gIceCandidates.push(event.candidate);
273 /** @private */
274 function setLocalDescription(peerConnection, sessionDescription) {
275   if (sessionDescription.sdp.search('a=crypto') != -1 ||
276       sessionDescription.sdp.search('a=fingerprint') != -1)
277     gHasSeenCryptoInSdp = 'crypto-seen';
279   peerConnection.setLocalDescription(
280     sessionDescription,
281     function() { success_('setLocalDescription'); },
282     function(error) { failure_('setLocalDescription', error); });
285 /** @private */
286 function addStreamCallback_(event) {
287   debug('Receiving remote stream...');
288   var videoTag = document.getElementById('remote-view');
289   attachMediaStream(videoTag, event.stream);
292 /** @private */
293 function removeStreamCallback_(event) {
294   debug('Call ended.');
295   document.getElementById('remote-view').src = '';
299  * Parses JSON-encoded session descriptions and ICE candidates.
300  * @private
301  */
302 function parseJson_(json) {
303   // Escape since the \r\n in the SDP tend to get unescaped.
304   jsonWithEscapedLineBreaks = json.replace(/\r\n/g, '\\r\\n');
305   try {
306     return JSON.parse(jsonWithEscapedLineBreaks);
307   } catch (exception) {
308     failTest('Failed to parse JSON: ' + jsonWithEscapedLineBreaks + ', got ' +
309              exception);
310   }