Unregister from GCM when the only GCM app is removed
[chromium-blink-merge.git] / chrome / test / data / webrtc / peerconnection.js
blob78d63cff84cbcdc54b7d7b667c6abdc3d8040abb
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-' + stringifyDOMObject_(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-' + stringifyDOMObject_(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(stringifyDOMObject_(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  * Returns
213  */
214 function hasSeenCryptoInSdp() {
215   returnToTest(gHasSeenCryptoInSdp);
218 // Internals.
220 /** @private */
221 function createPeerConnection_(stun_server) {
222   servers = {iceServers: [{url: 'stun:' + stun_server}]};
223   try {
224     peerConnection = new RTCPeerConnection(servers, {});
225   } catch (exception) {
226     throw failTest('Failed to create peer connection: ' + exception);
227   }
228   peerConnection.onaddstream = addStreamCallback_;
229   peerConnection.onremovestream = removeStreamCallback_;
230   peerConnection.onicecandidate = iceCallback_;
231   return peerConnection;
234 /** @private */
235 function peerConnection_() {
236   if (gPeerConnection == null)
237     throw failTest('Trying to use peer connection, but none was created.');
238   return gPeerConnection;
241 /** @private */
242 function success_(method) {
243   debug(method + '(): success.');
246 /** @private */
247 function failure_(method, error) {
248   throw failTest(method + '() failed: ' + stringifyDOMObject_(error));
251 /** @private */
252 function iceCallback_(event) {
253   if (event.candidate)
254     gIceCandidates.push(event.candidate);
257 /** @private */
258 function setLocalDescription(peerConnection, sessionDescription) {
259   if (sessionDescription.sdp.search('a=crypto') != -1 ||
260       sessionDescription.sdp.search('a=fingerprint') != -1)
261     gHasSeenCryptoInSdp = 'crypto-seen';
263   peerConnection.setLocalDescription(
264     sessionDescription,
265     function() { success_('setLocalDescription'); },
266     function(error) { failure_('setLocalDescription', error); });
269 /** @private */
270 function addStreamCallback_(event) {
271   debug('Receiving remote stream...');
272   var videoTag = document.getElementById('remote-view');
273   attachMediaStream(videoTag, event.stream);
276 /** @private */
277 function removeStreamCallback_(event) {
278   debug('Call ended.');
279   document.getElementById('remote-view').src = '';
283  * Stringifies a DOM object.
285  * This function stringifies not only own properties but also DOM attributes
286  * which are on a prototype chain.  Note that JSON.stringify only stringifies
287  * own properties.
288  * @private
289  */
290 function stringifyDOMObject_(object)
292   function deepCopy(src) {
293     if (typeof src != "object")
294       return src;
295     var dst = Array.isArray(src) ? [] : {};
296     for (var property in src) {
297       dst[property] = deepCopy(src[property]);
298     }
299     return dst;
300   }
301   return JSON.stringify(deepCopy(object));
305  * Parses JSON-encoded session descriptions and ICE candidates.
306  * @private
307  */
308 function parseJson_(json) {
309   // Escape since the \r\n in the SDP tend to get unescaped.
310   jsonWithEscapedLineBreaks = json.replace(/\r\n/g, '\\r\\n');
311   try {
312     return JSON.parse(jsonWithEscapedLineBreaks);
313   } catch (exception) {
314     failTest('Failed to parse JSON: ' + jsonWithEscapedLineBreaks + ', got ' +
315              exception);
316   }