1d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org/** 2d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. 3d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * 4d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * Use of this source code is governed by a BSD-style license 5d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * that can be found in the LICENSE file in the root of the source 6d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * tree. An additional intellectual property rights grant can be found 7d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * in the file PATENTS. All contributing project authors may 8d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org * be found in the AUTHORS file in the root of the source tree. 9d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org */ 10d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 11d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// LoopbackTest establish a one way loopback call between 2 peer connections 12d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// while continuously monitoring bandwidth stats. The idea is to use this as 13d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// a base for other future tests and to keep track of more than just bandwidth 14d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// stats. 15d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// 16d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// Usage: 17d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// var test = new LoopbackTest(stream, callDurationMs, 18ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org// forceTurn, pcConstraints, 19ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org// maxVideoBitrateKbps); 20d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// test.run(onDone); 21d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// function onDone() { 22d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// test.getResults(); // return stats recorded during the loopback test. 23d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// } 24d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org// 25ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.orgfunction LoopbackTest( 26ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org stream, 27ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org callDurationMs, 28ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org forceTurn, 29ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org pcConstraints, 30ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org maxVideoBitrateKbps) { 31ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org 32d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var pc1StatTracker; 33d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var pc2StatTracker; 34d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 35d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // In order to study effect of network (e.g. wifi) on peer connection one can 36d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // establish a loopback call and force it to go via a turn server. This way 37d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // the call won't switch to local addresses. That is achieved by filtering out 38d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // all non-relay ice candidades on both peers. 39d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function constrainTurnCandidates(pc) { 40d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var origAddIceCandidate = pc.addIceCandidate; 41d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc.addIceCandidate = function (candidate, successCallback, 42d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org failureCallback) { 43d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (forceTurn && candidate.candidate.indexOf("typ relay ") == -1) { 44d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace("Dropping non-turn candidate: " + candidate.candidate); 45d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org successCallback(); 46d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org return; 47d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } else { 48d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org origAddIceCandidate.call(this, candidate, successCallback, 49d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org failureCallback); 50d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 51d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 52d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 53d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 54d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // FEC makes it hard to study bwe estimation since there seems to be a spike 55d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // when it is enabled and disabled. Disable it for now. FEC issue tracked on: 56d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // https://code.google.com/p/webrtc/issues/detail?id=3050 57d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function constrainOfferToRemoveFec(pc) { 58d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var origCreateOffer = pc.createOffer; 59d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc.createOffer = function (successCallback, failureCallback, options) { 60d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function filteredSuccessCallback(desc) { 61d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org desc.sdp = desc.sdp.replace(/(m=video 1 [^\r]+)(116 117)(\r\n)/g, 62d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org '$1\r\n'); 63d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org desc.sdp = desc.sdp.replace(/a=rtpmap:116 red\/90000\r\n/g, ''); 64d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org desc.sdp = desc.sdp.replace(/a=rtpmap:117 ulpfec\/90000\r\n/g, ''); 65d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org successCallback(desc); 66d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 67d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org origCreateOffer.call(this, filteredSuccessCallback, failureCallback, 68d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org options); 69d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 70d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 71d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 72d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Constraint max video bitrate by modifying the SDP when creating an answer. 73d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function constrainBitrateAnswer(pc) { 74d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var origCreateAnswer = pc.createAnswer; 75d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc.createAnswer = function (successCallback, failureCallback, options) { 76d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function filteredSuccessCallback(desc) { 77d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (maxVideoBitrateKbps) { 78d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org desc.sdp = desc.sdp.replace( 79d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org /a=mid:video\r\n/g, 80d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 'a=mid:video\r\nb=AS:' + maxVideoBitrateKbps + '\r\n'); 81d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 82d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org successCallback(desc); 83d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 84d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org origCreateAnswer.call(this, filteredSuccessCallback, failureCallback, 85d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org options); 86d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 87d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 88d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 89d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Run the actual LoopbackTest. 90d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org this.run = function(doneCallback) { 91d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (forceTurn) requestTurn(start, fail); 92d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org else start(); 93d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 94d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function start(turnServer) { 95d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var pcConfig = forceTurn ? { iceServers: [turnServer] } : null; 96d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org console.log(pcConfig); 97ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org var pc1 = new RTCPeerConnection(pcConfig, pcConstraints); 98d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org constrainTurnCandidates(pc1); 99d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org constrainOfferToRemoveFec(pc1); 100d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker = new StatTracker(pc1, 50); 101d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker.recordStat("EstimatedSendBitrate", 102d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org "bweforvideo", "googAvailableSendBandwidth"); 103d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker.recordStat("TransmitBitrate", 104d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org "bweforvideo", "googTransmitBitrate"); 105d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker.recordStat("TargetEncodeBitrate", 106d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org "bweforvideo", "googTargetEncBitrate"); 107d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker.recordStat("ActualEncodedBitrate", 108d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org "bweforvideo", "googActualEncBitrate"); 109d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 110ccef356aceb30b18b8cc50d0e55d2caa2a16b00candresp@webrtc.org var pc2 = new RTCPeerConnection(pcConfig, pcConstraints); 111d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org constrainTurnCandidates(pc2); 112d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org constrainBitrateAnswer(pc2); 113d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2StatTracker = new StatTracker(pc2, 50); 114d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2StatTracker.recordStat("REMB", 115d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org "bweforvideo", "googAvailableReceiveBandwidth"); 116d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 117d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.addStream(stream); 118d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var call = new Call(pc1, pc2); 119d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 120d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org call.start(); 121d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org setTimeout(function () { 122d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org call.stop(); 123d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1StatTracker.stop(); 124d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2StatTracker.stop(); 125d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org success(); 126d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org }, callDurationMs); 127d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 128d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 129d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function success() { 130d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace("Success"); 131d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org doneCallback(); 132d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 133d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 1341fb05fcdfaccd145e6433aa1dbbbf6fd9adc5639andresp@webrtc.org function fail(msg) { 1351fb05fcdfaccd145e6433aa1dbbbf6fd9adc5639andresp@webrtc.org trace("Fail: " + msg); 136d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org doneCallback(); 137d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 138d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 139d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 140d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Returns a google visualization datatable with the recorded samples during 141d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // the loopback test. 142d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org this.getResults = function () { 143d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org return mergeDataTable(pc1StatTracker.dataTable(), 144d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2StatTracker.dataTable()); 145d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 146d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 147d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Helper class to establish and manage a call between 2 peer connections. 148d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Usage: 149d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // var c = new Call(pc1, pc2); 150d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // c.start(); 151d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // c.stop(); 152d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // 153d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function Call(pc1, pc2) { 154d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.onicecandidate = applyIceCandidate.bind(pc2); 155d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2.onicecandidate = applyIceCandidate.bind(pc1); 156d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 157d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function applyIceCandidate(e) { 158d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (e.candidate) { 159d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org this.addIceCandidate(new RTCIceCandidate(e.candidate), 160d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org onAddIceCandidateSuccess, 161d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org onAddIceCandidateError); 162d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 163d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 164d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 165d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function onAddIceCandidateSuccess() {} 166d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function onAddIceCandidateError(error) { 167d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace("Failed to add Ice Candidate: " + error.toString()); 168d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 169d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 170d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org this.start = function() { 171d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.createOffer(gotDescription1, onCreateSessionDescriptionError); 172d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 173d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function onCreateSessionDescriptionError(error) { 174d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace('Failed to create session description: ' + error.toString()); 175d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 176d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 177d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function gotDescription1(desc){ 178d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace("Offer: " + desc.sdp); 179d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.setLocalDescription(desc); 180d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2.setRemoteDescription(desc); 181d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Since the "remote" side has no media stream we need 182d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // to pass in the right constraints in order for it to 183d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // accept the incoming offer of audio and video. 184d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2.createAnswer(gotDescription2, onCreateSessionDescriptionError); 185d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 186d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 187d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function gotDescription2(desc){ 188d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org trace("Answer: " + desc.sdp); 189d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2.setLocalDescription(desc); 190d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.setRemoteDescription(desc); 191d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 192d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 193d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 194d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org this.stop = function() { 195d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc1.close(); 196d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org pc2.close(); 197d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 198d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 199d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 200d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Request a turn server. This uses the same servers as apprtc. 201d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function requestTurn(successCallback, failureCallback) { 202d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var currentDomain = document.domain; 203d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (currentDomain.search('localhost') === -1 && 2041fb05fcdfaccd145e6433aa1dbbbf6fd9adc5639andresp@webrtc.org currentDomain.search('webrtc.googlecode.com') === -1) { 2051fb05fcdfaccd145e6433aa1dbbbf6fd9adc5639andresp@webrtc.org failureCallback("Domain not authorized for turn server: " + 2061fb05fcdfaccd145e6433aa1dbbbf6fd9adc5639andresp@webrtc.org currentDomain); 207d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org return; 208d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 209d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 210d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Get a turn server from computeengineondemand.appspot.com. 211d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var turnUrl = 'https://computeengineondemand.appspot.com/' + 212d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 'turn?username=156547625762562&key=4080218913'; 213d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var xmlhttp = new XMLHttpRequest(); 214d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org xmlhttp.onreadystatechange = onTurnResult; 215d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org xmlhttp.open('GET', turnUrl, true); 216d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org xmlhttp.send(); 217d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 218d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function onTurnResult() { 219d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (this.readyState !== 4) { 220d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org return; 221d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 222d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org 223d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (this.status === 200) { 224d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var turnServer = JSON.parse(xmlhttp.responseText); 225d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org // Create turnUris using the polyfill (adapter.js). 226d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org turnServer.uris = turnServer.uris.filter( 227d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org function (e) { return e.search('transport=udp') != -1; } 228d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org ); 229d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org var iceServers = createIceServers(turnServer.uris, 230d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org turnServer.username, 231d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org turnServer.password); 232d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org if (iceServers !== null) { 233d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org successCallback(iceServers); 234d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org return; 235d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 236d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 237d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org failureCallback("Failed to get a turn server."); 238d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 239d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org } 240d07336255a3f273d8a14d4485dd73c0398491bc3andresp@webrtc.org} 241