| Index: chrome/test/data/webrtc/manual/peerconnection.js
|
| diff --git a/chrome/test/data/webrtc/manual/peerconnection.js b/chrome/test/data/webrtc/manual/peerconnection.js
|
| deleted file mode 100644
|
| index 3d7901f79e16ad2fbebd4a26697681abdb6622b3..0000000000000000000000000000000000000000
|
| --- a/chrome/test/data/webrtc/manual/peerconnection.js
|
| +++ /dev/null
|
| @@ -1,1368 +0,0 @@
|
| -/**
|
| - * Copyright (c) 2012 The Chromium Authors. All rights reserved.
|
| - * Use of this source code is governed by a BSD-style license that can be
|
| - * found in the LICENSE file.
|
| - */
|
| -
|
| - /**
|
| - * See http://dev.w3.org/2011/webrtc/editor/getusermedia.html for more
|
| - * information on getUserMedia. See
|
| - * http://dev.w3.org/2011/webrtc/editor/webrtc.html for more information on
|
| - * peerconnection and webrtc in general.
|
| - */
|
| -
|
| -/** TODO(jansson) give it a better name
|
| - * Global namespace object.
|
| - */
|
| -var global = {};
|
| -
|
| -/**
|
| - * We need a STUN server for some API calls.
|
| - * @private
|
| - */
|
| -var STUN_SERVER = 'stun.l.google.com:19302';
|
| -
|
| -/** @private */
|
| -global.transformOutgoingSdp = function(sdp) { return sdp; };
|
| -
|
| -/** @private */
|
| -global.dataStatusCallback = function(status) {};
|
| -
|
| -/** @private */
|
| -global.dataCallback = function(data) {};
|
| -
|
| -/** @private */
|
| -global.dtmfOnToneChange = function(tone) {};
|
| -
|
| -/**
|
| - * Used as a shortcut for finding DOM elements by ID.
|
| - * @param {string} id is a case-sensitive string representing the unique ID of
|
| - * the element being sought.
|
| - * @return {object} id returns the element object specified as a parameter
|
| - */
|
| -$ = function(id) {
|
| - return document.getElementById(id);
|
| -};
|
| -
|
| -/**
|
| - * Prepopulate constraints from JS to the UI. Enumerate devices available
|
| - * via getUserMedia, register elements to be used for local storage.
|
| - */
|
| -window.onload = function() {
|
| - hookupDataChannelCallbacks_();
|
| - hookupDtmfSenderCallback_();
|
| - updateGetUserMediaConstraints();
|
| - setupLocalStorageFieldValues();
|
| - acceptIncomingCalls();
|
| - if ($('get-devices-onload').checked == true) {
|
| - getDevices();
|
| - }
|
| -};
|
| -
|
| -/**
|
| - * Disconnect before the tab is closed.
|
| - */
|
| -window.onbeforeunload = function() {
|
| - disconnect_();
|
| -};
|
| -
|
| -/** TODO Add element.id as a parameter and call this function instead?
|
| - * A list of element id's to be registered for local storage.
|
| - */
|
| -function setupLocalStorageFieldValues() {
|
| - registerLocalStorage_('pc-server');
|
| - registerLocalStorage_('pc-createanswer-constraints');
|
| - registerLocalStorage_('pc-createoffer-constraints');
|
| - registerLocalStorage_('get-devices-onload');
|
| - registerLocalStorage_('data-channel-type-rtp');
|
| -}
|
| -
|
| -// Public HTML functions
|
| -
|
| -// The *Here functions are called from peerconnection.html and will make calls
|
| -// into our underlying JavaScript library with the values from the page
|
| -// (have to be named differently to avoid name clashes with existing functions).
|
| -
|
| -function getUserMediaFromHere() {
|
| - var constraints = $('getusermedia-constraints').value;
|
| - try {
|
| - doGetUserMedia_(constraints);
|
| - } catch (exception) {
|
| - print_('getUserMedia says: ' + exception);
|
| - }
|
| -}
|
| -
|
| -function connectFromHere() {
|
| - var server = $('pc-server').value;
|
| - if ($('peer-id').value == '') {
|
| - // Generate a random name to distinguish us from other tabs:
|
| - $('peer-id').value = 'peer_' + Math.floor(Math.random() * 10000);
|
| - print_('Our name from now on will be ' + $('peer-id').value);
|
| - }
|
| - connect(server, $('peer-id').value);
|
| -}
|
| -
|
| -function negotiateCallFromHere() {
|
| - // Set the global variables with values from our UI.
|
| - setCreateOfferConstraints(getEvaluatedJavaScript_(
|
| - $('pc-createoffer-constraints').value));
|
| - setCreateAnswerConstraints(getEvaluatedJavaScript_(
|
| - $('pc-createanswer-constraints').value));
|
| -
|
| - ensureHasPeerConnection_();
|
| - negotiateCall_();
|
| -}
|
| -
|
| -function addLocalStreamFromHere() {
|
| - ensureHasPeerConnection_();
|
| - addLocalStream();
|
| -}
|
| -
|
| -function removeLocalStreamFromHere() {
|
| - removeLocalStream();
|
| -}
|
| -
|
| -function hangUpFromHere() {
|
| - hangUp();
|
| - acceptIncomingCalls();
|
| -}
|
| -
|
| -function toggleRemoteVideoFromHere() {
|
| - toggleRemoteStream(function(remoteStream) {
|
| - return remoteStream.getVideoTracks()[0];
|
| - }, 'video');
|
| -}
|
| -
|
| -function toggleRemoteAudioFromHere() {
|
| - toggleRemoteStream(function(remoteStream) {
|
| - return remoteStream.getAudioTracks()[0];
|
| - }, 'audio');
|
| -}
|
| -
|
| -function toggleLocalVideoFromHere() {
|
| - toggleLocalStream(function(localStream) {
|
| - return localStream.getVideoTracks()[0];
|
| - }, 'video');
|
| -}
|
| -
|
| -function toggleLocalAudioFromHere() {
|
| - toggleLocalStream(function(localStream) {
|
| - return localStream.getAudioTracks()[0];
|
| - }, 'audio');
|
| -}
|
| -
|
| -function stopLocalFromHere() {
|
| - stopLocalStream();
|
| -}
|
| -
|
| -function createDataChannelFromHere() {
|
| - ensureHasPeerConnection_();
|
| - createDataChannelOnPeerConnection();
|
| -}
|
| -
|
| -function closeDataChannelFromHere() {
|
| - ensureHasPeerConnection_();
|
| - closeDataChannelOnPeerConnection();
|
| -}
|
| -
|
| -function sendDataFromHere() {
|
| - var data = $('data-channel-send').value;
|
| - sendDataOnChannel(data);
|
| -}
|
| -
|
| -function createDtmfSenderFromHere() {
|
| - ensureHasPeerConnection_();
|
| - createDtmfSenderOnPeerConnection();
|
| -}
|
| -
|
| -function insertDtmfFromHere() {
|
| - var tones = $('dtmf-tones').value;
|
| - var duration = $('dtmf-tones-duration').value;
|
| - var gap = $('dtmf-tones-gap').value;
|
| - insertDtmfOnSender(tones, duration, gap);
|
| -}
|
| -
|
| -function forceIsacChanged() {
|
| - var forceIsac = $('force-isac').checked;
|
| - if (forceIsac) {
|
| - forceIsac_();
|
| - } else {
|
| - dontTouchSdp_();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Updates the constraints in the getusermedia-constraints text box with a
|
| - * MediaStreamConstraints string. This string is created based on the status of
|
| - * the checkboxes for audio and video. If device enumeration is supported and
|
| - * device source id's are not null they will be added to the constraints string.
|
| - * Fetches the screen size using "screen" in Chrome as we need to pass a max
|
| - * resolution else it defaults to 640x480 in the constraints for screen
|
| - * capturing.
|
| - */
|
| -function updateGetUserMediaConstraints() {
|
| - var audioSelected = $('audiosrc');
|
| - var videoSelected = $('videosrc');
|
| - var constraints = {
|
| - audio: $('audio').checked,
|
| - video: $('video').checked
|
| - };
|
| -
|
| - if (audioSelected.disabled == false && videoSelected.disabled == false) {
|
| - var devices = getSourcesFromField_(audioSelected, videoSelected);
|
| - if ($('audio').checked == true) {
|
| - if (devices.audioId != null) {
|
| - constraints.audio = {optional: [{sourceId: devices.audioId}]};
|
| - } else {
|
| - constraints.audio = true;
|
| - }
|
| - }
|
| - if ($('video').checked == true) {
|
| - // Default optional constraints placed here.
|
| - constraints.video = {optional: [{minWidth: $('video-width').value},
|
| - {minHeight: $('video-height').value},
|
| - {googCpuOveruseDetection: true},
|
| - {googLeakyBucket: true}]
|
| - };
|
| - if (devices.videoId != null) {
|
| - constraints.video.optional.push({sourceId: devices.videoId});
|
| - }
|
| - }
|
| - }
|
| -
|
| - if ($('screencapture').checked) {
|
| - var constraints = {
|
| - audio: $('audio').checked,
|
| - video: {mandatory: {chromeMediaSource: 'screen',
|
| - maxWidth: screen.width,
|
| - maxHeight: screen.height}}
|
| - };
|
| - if ($('audio').checked == true)
|
| - print_('Audio for screencapture is not implemented yet, please ' +
|
| - 'try to set audio = false prior requesting screencapture');
|
| - }
|
| - $('getusermedia-constraints').value = JSON.stringify(constraints, null, ' ');
|
| -}
|
| -
|
| -function showServerHelp() {
|
| - alert('You need to build and run a peerconnection_server on some ' +
|
| - 'suitable machine. To build it in chrome, just run make/ninja ' +
|
| - 'peerconnection_server. Otherwise, read in https://code.google' +
|
| - '.com/searchframe#xSWYf0NTG_Q/trunk/peerconnection/README&q=REA' +
|
| - 'DME%20package:webrtc%5C.googlecode%5C.com.');
|
| -}
|
| -
|
| -function clearLog() {
|
| - $('messages').innerHTML = '';
|
| - $('debug').innerHTML = '';
|
| -}
|
| -
|
| -/**
|
| - * Stops the local stream.
|
| - */
|
| -function stopLocalStream() {
|
| - if (global.localStream == null)
|
| - error_('Tried to stop local stream, ' +
|
| - 'but media access is not granted.');
|
| -
|
| - global.localStream.stop();
|
| -}
|
| -
|
| -/**
|
| - * Adds the current local media stream to a peer connection.
|
| - * @param {RTCPeerConnection} peerConnection
|
| - */
|
| -function addLocalStreamToPeerConnection(peerConnection) {
|
| - if (global.localStream == null)
|
| - error_('Tried to add local stream to peer connection, but there is no ' +
|
| - 'stream yet.');
|
| - try {
|
| - peerConnection.addStream(global.localStream, global.addStreamConstraints);
|
| - } catch (exception) {
|
| - error_('Failed to add stream with constraints ' +
|
| - global.addStreamConstraints + ': ' + exception);
|
| - }
|
| - print_('Added local stream.');
|
| -}
|
| -
|
| -/**
|
| - * Removes the local stream from the peer connection.
|
| - * @param {rtcpeerconnection} peerConnection
|
| - */
|
| -function removeLocalStreamFromPeerConnection(peerConnection) {
|
| - if (global.localStream == null)
|
| - error_('Tried to remove local stream from peer connection, but there is ' +
|
| - 'no stream yet.');
|
| - try {
|
| - peerConnection.removeStream(global.localStream);
|
| - } catch (exception) {
|
| - error_('Could not remove stream: ' + exception);
|
| - }
|
| - print_('Removed local stream.');
|
| -}
|
| -
|
| -/**
|
| - * Enumerates the audio and video devices available in Chrome and adds the
|
| - * devices to the HTML elements with Id 'audiosrc' and 'videosrc'.
|
| - * Checks if device enumeration is supported and if the 'audiosrc' + 'videosrc'
|
| - * elements exists, if not a debug printout will be displayed.
|
| - * If the device label is empty, audio/video + sequence number will be used to
|
| - * populate the name. Also makes sure the children has been loaded in order
|
| - * to update the constraints.
|
| - */
|
| -function getDevices() {
|
| - var audio_select = $('audiosrc');
|
| - var video_select = $('videosrc');
|
| - var get_devices = $('get-devices');
|
| - audio_select.innerHTML = '';
|
| - video_select.innerHTML = '';
|
| - try {
|
| - eval(MediaStreamTrack.getSources(function() {}));
|
| - } catch (exception) {
|
| - audio_select.disabled = true;
|
| - video_select.disabled = true;
|
| - refresh_devices.disabled = true;
|
| - updateGetUserMediaConstraints();
|
| - error_('Device enumeration not supported. ' + exception);
|
| - }
|
| - MediaStreamTrack.getSources(function(devices) {
|
| - for (var i = 0; i < devices.length; i++) {
|
| - var option = document.createElement('option');
|
| - option.value = devices[i].id;
|
| - option.text = devices[i].label;
|
| - if (devices[i].kind == 'audio') {
|
| - if (option.text == '') {
|
| - option.text = devices[i].id;
|
| - }
|
| - audio_select.appendChild(option);
|
| - } else if (devices[i].kind == 'video') {
|
| - if (option.text == '') {
|
| - option.text = devices[i].id;
|
| - }
|
| - video_select.appendChild(option);
|
| - } else {
|
| - error_('Device type ' + devices[i].kind + ' not recognized, ' +
|
| - 'cannot enumerate device. Currently only device types' +
|
| - '\'audio\' and \'video\' are supported');
|
| - updateGetUserMediaConstraints();
|
| - return;
|
| - }
|
| - }
|
| - });
|
| - checkIfDeviceDropdownsArePopulated_();
|
| -}
|
| -
|
| -/**
|
| - * Sets the transform to apply just before setting the local description and
|
| - * sending to the peer.
|
| - * @param {function} transformFunction A function which takes one SDP string as
|
| - * argument and returns the modified SDP string.
|
| - */
|
| -function setOutgoingSdpTransform(transformFunction) {
|
| - global.transformOutgoingSdp = transformFunction;
|
| -}
|
| -
|
| -/**
|
| - * Sets the MediaConstraints to be used for PeerConnection createAnswer() calls.
|
| - * @param {string} mediaConstraints The constraints, as defined in the
|
| - * PeerConnection JS API spec.
|
| - */
|
| -function setCreateAnswerConstraints(mediaConstraints) {
|
| - global.createAnswerConstraints = mediaConstraints;
|
| -}
|
| -
|
| -/**
|
| - * Sets the MediaConstraints to be used for PeerConnection createOffer() calls.
|
| - * @param {string} mediaConstraints The constraints, as defined in the
|
| - * PeerConnection JS API spec.
|
| - */
|
| -function setCreateOfferConstraints(mediaConstraints) {
|
| - global.createOfferConstraints = mediaConstraints;
|
| -}
|
| -
|
| -/**
|
| - * Sets the callback functions that will receive DataChannel readyState updates
|
| - * and received data.
|
| - * @param {function} status_callback The function that will receive a string
|
| - * with
|
| - * the current DataChannel readyState.
|
| - * @param {function} data_callback The function that will a string with data
|
| - * received from the remote peer.
|
| - */
|
| -function setDataCallbacks(status_callback, data_callback) {
|
| - global.dataStatusCallback = status_callback;
|
| - global.dataCallback = data_callback;
|
| -}
|
| -
|
| -/**
|
| - * Sends data on an active DataChannel.
|
| - * @param {string} data The string that will be sent to the remote peer.
|
| - */
|
| -function sendDataOnChannel(data) {
|
| - if (global.dataChannel == null)
|
| - error_('Trying to send data, but there is no DataChannel.');
|
| - global.dataChannel.send(data);
|
| -}
|
| -
|
| -/**
|
| - * Sets the callback function that will receive DTMF sender ontonechange events.
|
| - * @param {function} ontonechange The function that will receive a string with
|
| - * the tone that has just begun playout.
|
| - */
|
| -function setOnToneChange(ontonechange) {
|
| - global.dtmfOnToneChange = ontonechange;
|
| -}
|
| -
|
| -/**
|
| - * Inserts DTMF tones on an active DTMF sender.
|
| - * @param {string} tones to be sent.
|
| - * @param {string} duration duration of the tones to be sent.
|
| - * @param {string} interToneGap gap between the tones to be sent.
|
| - */
|
| -function insertDtmf(tones, duration, interToneGap) {
|
| - if (global.dtmfSender == null)
|
| - error_('Trying to send DTMF, but there is no DTMF sender.');
|
| - global.dtmfSender.insertDTMF(tones, duration, interToneGap);
|
| -}
|
| -
|
| -function handleMessage(peerConnection, message) {
|
| - var parsed_msg = JSON.parse(message);
|
| - if (parsed_msg.type) {
|
| - var session_description = new RTCSessionDescription(parsed_msg);
|
| - peerConnection.setRemoteDescription(
|
| - session_description,
|
| - function() { success_('setRemoteDescription'); },
|
| - function() { failure_('setRemoteDescription'); });
|
| - if (session_description.type == 'offer') {
|
| - print_('createAnswer with constraints: ' +
|
| - JSON.stringify(global.createAnswerConstraints, null, ' '));
|
| - peerConnection.createAnswer(
|
| - setLocalAndSendMessage_,
|
| - function() { failure_('createAnswer'); },
|
| - global.createAnswerConstraints);
|
| - }
|
| - return;
|
| - } else if (parsed_msg.candidate) {
|
| - var candidate = new RTCIceCandidate(parsed_msg);
|
| - peerConnection.addIceCandidate(candidate);
|
| - return;
|
| - }
|
| - error_('unknown message received');
|
| -}
|
| -
|
| -function createPeerConnection(stun_server, useRtpDataChannels) {
|
| - servers = {iceServers: [{url: 'stun:' + stun_server}]};
|
| - try {
|
| - var constraints = { optional: [{ RtpDataChannels: useRtpDataChannels }]};
|
| - peerConnection = new webkitRTCPeerConnection(servers, constraints);
|
| - } catch (exception) {
|
| - error_('Failed to create peer connection: ' + exception);
|
| - }
|
| - peerConnection.onaddstream = addStreamCallback_;
|
| - peerConnection.onremovestream = removeStreamCallback_;
|
| - peerConnection.onicecandidate = iceCallback_;
|
| - peerConnection.ondatachannel = onCreateDataChannelCallback_;
|
| - return peerConnection;
|
| -}
|
| -
|
| -function setupCall(peerConnection) {
|
| - print_('createOffer with constraints: ' +
|
| - JSON.stringify(global.createOfferConstraints, null, ' '));
|
| - peerConnection.createOffer(
|
| - setLocalAndSendMessage_,
|
| - function() { failure_('createOffer'); },
|
| - global.createOfferConstraints);
|
| -}
|
| -
|
| -function answerCall(peerConnection, message) {
|
| - handleMessage(peerConnection, message);
|
| -}
|
| -
|
| -function createDataChannel(peerConnection, label) {
|
| - if (global.dataChannel != null && global.dataChannel.readyState != 'closed')
|
| - error_('Creating DataChannel, but we already have one.');
|
| -
|
| - global.dataChannel = peerConnection.createDataChannel(label,
|
| - { reliable: false });
|
| - print_('DataChannel with label ' + global.dataChannel.label + ' initiated ' +
|
| - 'locally.');
|
| - hookupDataChannelEvents();
|
| -}
|
| -
|
| -function closeDataChannel(peerConnection) {
|
| - if (global.dataChannel == null)
|
| - error_('Closing DataChannel, but none exists.');
|
| - print_('DataChannel with label ' + global.dataChannel.label +
|
| - ' is beeing closed.');
|
| - global.dataChannel.close();
|
| -}
|
| -
|
| -function createDtmfSender(peerConnection) {
|
| - if (global.dtmfSender != null)
|
| - error_('Creating DTMF sender, but we already have one.');
|
| -
|
| - var localStream = global.localStream();
|
| - if (localStream == null)
|
| - error_('Creating DTMF sender but local stream is null.');
|
| - local_audio_track = localStream.getAudioTracks()[0];
|
| - global.dtmfSender = peerConnection.createDTMFSender(local_audio_track);
|
| - global.dtmfSender.ontonechange = global.dtmfOnToneChange;
|
| -}
|
| -
|
| -/**
|
| - * Connects to the provided peerconnection_server.
|
| - *
|
| - * @param {string} serverUrl The server URL in string form without an ending
|
| - * slash, something like http://localhost:8888.
|
| - * @param {string} clientName The name to use when connecting to the server.
|
| - */
|
| -function connect(serverUrl, clientName) {
|
| - if (global.ourPeerId != null)
|
| - error_('connecting, but is already connected.');
|
| -
|
| - print_('Connecting to ' + serverUrl + ' as ' + clientName);
|
| - global.serverUrl = serverUrl;
|
| - global.ourClientName = clientName;
|
| -
|
| - request = new XMLHttpRequest();
|
| - request.open('GET', serverUrl + '/sign_in?' + clientName, true);
|
| - print_(serverUrl + '/sign_in?' + clientName);
|
| - request.onreadystatechange = function() {
|
| - connectCallback_(request);
|
| - };
|
| - request.send();
|
| -}
|
| -
|
| -/**
|
| - * Checks if the remote peer has connected. Returns peer-connected if that is
|
| - * the case, otherwise no-peer-connected.
|
| - */
|
| -function remotePeerIsConnected() {
|
| - if (global.remotePeerId == null)
|
| - print_('no-peer-connected');
|
| - else
|
| - print_('peer-connected');
|
| -}
|
| -
|
| -/**
|
| - * Creates a peer connection. Must be called before most other public functions
|
| - * in this file.
|
| - */
|
| -function preparePeerConnection() {
|
| - if (global.peerConnection != null)
|
| - error_('creating peer connection, but we already have one.');
|
| -
|
| - global.peerConnection = createPeerConnection(STUN_SERVER,
|
| - $('data-channel-type-rtp').checked);
|
| - print_('ok-peerconnection-created');
|
| -}
|
| -
|
| -/**
|
| - * Adds the local stream to the peer connection. You will have to re-negotiate
|
| - * the call for this to take effect in the call.
|
| - */
|
| -function addLocalStream() {
|
| - if (global.peerConnection == null)
|
| - error_('adding local stream, but we have no peer connection.');
|
| -
|
| - addLocalStreamToPeerConnection(global.peerConnection);
|
| - print_('ok-added');
|
| -}
|
| -
|
| -/**
|
| - * Removes the local stream from the peer connection. You will have to
|
| - * re-negotiate the call for this to take effect in the call.
|
| - */
|
| -function removeLocalStream() {
|
| - if (global.peerConnection == null)
|
| - error_('attempting to remove local stream, but no call is up');
|
| -
|
| - removeLocalStreamFromPeerConnection(global.peerConnection);
|
| - print_('ok-local-stream-removed');
|
| -}
|
| -
|
| -/**
|
| - * (see getReadyState_)
|
| - */
|
| -function getPeerConnectionReadyState() {
|
| - print_(getReadyState_());
|
| -}
|
| -
|
| -/**
|
| - * Toggles the remote audio stream's enabled state on the peer connection, given
|
| - * that a call is active. Returns ok-[typeToToggle]-toggled-to-[true/false]
|
| - * on success.
|
| - *
|
| - * @param {function} selectAudioOrVideoTrack A function that takes a remote
|
| - * stream as argument and returns a track (e.g. either the video or audio
|
| - * track).
|
| - * @param {function} typeToToggle Either "audio" or "video" depending on what
|
| - * the selector function selects.
|
| - */
|
| -function toggleRemoteStream(selectAudioOrVideoTrack, typeToToggle) {
|
| - if (global.peerConnection == null)
|
| - error_('Tried to toggle remote stream, but have no peer connection.');
|
| - if (global.peerConnection.getRemoteStreams().length == 0)
|
| - error_('Tried to toggle remote stream, but not receiving any stream.');
|
| -
|
| - var track = selectAudioOrVideoTrack(
|
| - global.peerConnection.getRemoteStreams()[0]);
|
| - toggle_(track, 'remote', typeToToggle);
|
| -}
|
| -
|
| -/**
|
| - * See documentation on toggleRemoteStream (this function is the same except
|
| - * we are looking at local streams).
|
| - */
|
| -function toggleLocalStream(selectAudioOrVideoTrack, typeToToggle) {
|
| - if (global.peerConnection == null)
|
| - error_('Tried to toggle local stream, but have no peer connection.');
|
| - if (global.peerConnection.getLocalStreams().length == 0)
|
| - error_('Tried to toggle local stream, but there is no local stream in ' +
|
| - 'the call.');
|
| -
|
| - var track = selectAudioOrVideoTrack(
|
| - global.peerConnection.getLocalStreams()[0]);
|
| - toggle_(track, 'local', typeToToggle);
|
| -}
|
| -
|
| -/**
|
| - * Hangs up a started call. Returns ok-call-hung-up on success. This tab will
|
| - * not accept any incoming calls after this call.
|
| - */
|
| -function hangUp() {
|
| - if (global.peerConnection == null)
|
| - error_('hanging up, but has no peer connection');
|
| - if (getReadyState_() != 'active')
|
| - error_('hanging up, but ready state is not active (no call up).');
|
| - sendToPeer(global.remotePeerId, 'BYE');
|
| - closeCall_();
|
| - global.acceptsIncomingCalls = false;
|
| - print_('ok-call-hung-up');
|
| -}
|
| -
|
| -/**
|
| - * Start accepting incoming calls.
|
| - */
|
| -function acceptIncomingCalls() {
|
| - global.acceptsIncomingCalls = true;
|
| -}
|
| -
|
| -/**
|
| - * Creates a DataChannel on the current PeerConnection. Only one DataChannel can
|
| - * be created on each PeerConnection.
|
| - * Returns ok-datachannel-created on success.
|
| - */
|
| -function createDataChannelOnPeerConnection() {
|
| - if (global.peerConnection == null)
|
| - error_('Tried to create data channel, but have no peer connection.');
|
| -
|
| - createDataChannel(global.peerConnection, global.ourClientName);
|
| - print_('ok-datachannel-created');
|
| -}
|
| -
|
| -/**
|
| - * Close the DataChannel on the current PeerConnection.
|
| - * Returns ok-datachannel-close on success.
|
| - */
|
| -function closeDataChannelOnPeerConnection() {
|
| - if (global.peerConnection == null)
|
| - error_('Tried to close data channel, but have no peer connection.');
|
| -
|
| - closeDataChannel(global.peerConnection);
|
| - print_('ok-datachannel-close');
|
| -}
|
| -
|
| -/**
|
| - * Creates a DTMF sender on the current PeerConnection.
|
| - * Returns ok-dtmfsender-created on success.
|
| - */
|
| -function createDtmfSenderOnPeerConnection() {
|
| - if (global.peerConnection == null)
|
| - error_('Tried to create DTMF sender, but have no peer connection.');
|
| -
|
| - createDtmfSender(global.peerConnection);
|
| - print_('ok-dtmfsender-created');
|
| -}
|
| -
|
| -/**
|
| - * Send DTMF tones on the global.dtmfSender.
|
| - * Returns ok-dtmf-sent on success.
|
| - */
|
| -function insertDtmfOnSender(tones, duration, interToneGap) {
|
| - if (global.dtmfSender == null)
|
| - error_('Tried to insert DTMF tones, but have no DTMF sender.');
|
| -
|
| - insertDtmf(tones, duration, interToneGap);
|
| - print_('ok-dtmf-sent');
|
| -}
|
| -
|
| -/**
|
| - * Sends a message to a peer through the peerconnection_server.
|
| - */
|
| -function sendToPeer(peer, message) {
|
| - var messageToLog = message.sdp ? message.sdp : message;
|
| - print_('Sending message ' + messageToLog + ' to peer ' + peer + '.');
|
| -
|
| - var request = new XMLHttpRequest();
|
| - var url = global.serverUrl + '/message?peer_id=' + global.ourPeerId + '&to=' +
|
| - peer;
|
| - request.open('POST', url, false);
|
| - request.setRequestHeader('Content-Type', 'text/plain');
|
| - request.send(message);
|
| -}
|
| -
|
| -/**
|
| - * @param {!string} videoTagId The ID of the video tag to update.
|
| - * @param {!number} width of the video to update the video tag, if width or
|
| - * height is 0, size will be taken from videoTag.videoWidth.
|
| - * @param {!number} height of the video to update the video tag, if width or
|
| - * height is 0 size will be taken from the videoTag.videoHeight.
|
| - */
|
| -function updateVideoTagSize(videoTagId, width, height) {
|
| - var videoTag = $(videoTagId);
|
| - if (width > 0 || height > 0) {
|
| - videoTag.width = width;
|
| - videoTag.height = height;
|
| - }
|
| - else {
|
| - if (videoTag.videoWidth > 0 || videoTag.videoHeight > 0) {
|
| - videoTag.width = videoTag.videoWidth;
|
| - videoTag.height = videoTag.videoHeight;
|
| - print_('Set video tag "' + videoTagId + '" size to ' + videoTag.width +
|
| - 'x' + videoTag.height);
|
| - }
|
| - else {
|
| - print_('"' + videoTagId + '" video stream size is 0, skipping resize');
|
| - }
|
| - }
|
| - displayVideoSize_(videoTag);
|
| -}
|
| -
|
| -// Internals.
|
| -
|
| -/**
|
| - * Disconnects from the peerconnection server. Returns ok-disconnected on
|
| - * success.
|
| - */
|
| -function disconnect_() {
|
| - if (global.ourPeerId == null)
|
| - return;
|
| -
|
| - request = new XMLHttpRequest();
|
| - request.open('GET', global.serverUrl + '/sign_out?peer_id=' +
|
| - global.ourPeerId, false);
|
| - request.send();
|
| - global.ourPeerId = null;
|
| - print_('ok-disconnected');
|
| -}
|
| -
|
| -/**
|
| -* Returns true if we are disconnected from peerconnection_server.
|
| -*/
|
| -function isDisconnected_() {
|
| - return global.ourPeerId == null;
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @return {!string} The current peer connection's ready state, or
|
| - * 'no-peer-connection' if there is no peer connection up.
|
| - *
|
| - * NOTE: The PeerConnection states are changing and until chromium has
|
| - * implemented the new states we have to use this interim solution of
|
| - * always assuming that the PeerConnection is 'active'.
|
| - */
|
| -function getReadyState_() {
|
| - if (global.peerConnection == null)
|
| - return 'no-peer-connection';
|
| -
|
| - return 'active';
|
| -}
|
| -
|
| -/**
|
| - * This function asks permission to use the webcam and mic from the browser. It
|
| - * will return ok-requested to the test. This does not mean the request was
|
| - * approved though. The test will then have to click past the dialog that
|
| - * appears in Chrome, which will run either the OK or failed callback as a
|
| - * a result. To see which callback was called, use obtainGetUserMediaResult_().
|
| - * @private
|
| - * @param {string} constraints Defines what to be requested, with mandatory
|
| - * and optional constraints defined. The contents of this parameter depends
|
| - * on the WebRTC version. This should be JavaScript code that we eval().
|
| - */
|
| -function doGetUserMedia_(constraints) {
|
| - if (!getUserMedia) {
|
| - print_('Browser does not support WebRTC.');
|
| - return;
|
| - }
|
| - try {
|
| - var evaluatedConstraints;
|
| - eval('evaluatedConstraints = ' + constraints);
|
| - } catch (exception) {
|
| - error_('Not valid JavaScript expression: ' + constraints);
|
| - }
|
| - print_('Requesting doGetUserMedia: constraints: ' + constraints);
|
| - getUserMedia(evaluatedConstraints, getUserMediaOkCallback_,
|
| - getUserMediaFailedCallback_);
|
| -}
|
| -
|
| -/**
|
| - * Must be called after calling doGetUserMedia.
|
| - * @private
|
| - * @return {string} Returns not-called-yet if we have not yet been called back
|
| - * by WebRTC. Otherwise it returns either ok-got-stream or
|
| - * failed-with-error-x (where x is the error code from the error
|
| - * callback) depending on which callback got called by WebRTC.
|
| - */
|
| -function obtainGetUserMediaResult_() {
|
| - if (global.requestWebcamAndMicrophoneResult == null)
|
| - global.requestWebcamAndMicrophoneResult = ' not called yet';
|
| -
|
| - return global.requestWebcamAndMicrophoneResult;
|
| -
|
| -}
|
| -
|
| -/**
|
| - * Negotiates a call with the other side. This will create a peer connection on
|
| - * the other side if there isn't one.
|
| - *
|
| - * To call this method we need to be aware of the other side, e.g. we must be
|
| - * connected to peerconnection_server and we must have exactly one peer on that
|
| - * server.
|
| - *
|
| - * This method may be called any number of times. If you haven't added any
|
| - * streams to the call, an "empty" call will result. The method will return
|
| - * ok-negotiating immediately to the test if the negotiation was successfully
|
| - * sent.
|
| - * @private
|
| - */
|
| -function negotiateCall_() {
|
| - if (global.peerConnection == null)
|
| - error_('Negotiating call, but we have no peer connection.');
|
| - if (global.ourPeerId == null)
|
| - error_('Negotiating call, but not connected.');
|
| - if (global.remotePeerId == null)
|
| - error_('Negotiating call, but missing remote peer.');
|
| -
|
| - setupCall(global.peerConnection);
|
| - print_('ok-negotiating');
|
| -}
|
| -
|
| -/**
|
| - * This provides the selected source id from the objects in the parameters
|
| - * provided to this function. If the audioSelect or video_select objects does
|
| - * not have any HTMLOptions children it will return null in the source object.
|
| - * @param {!object} audioSelect HTML drop down element with audio devices added
|
| - * as HTMLOptionsCollection children.
|
| - * @param {!object} videoSelect HTML drop down element with audio devices added
|
| - * as HTMLOptionsCollection children.
|
| - * @return {!object} source contains audio and video source ID from
|
| - * the selected devices in the drop down menu elements.
|
| - * @private
|
| - */
|
| -function getSourcesFromField_(audioSelect, videoSelect) {
|
| - var source = {
|
| - audioId: null,
|
| - videoId: null
|
| - };
|
| - if (audioSelect.options.length > 0) {
|
| - source.audioId = audioSelect.options[audioSelect.selectedIndex].value;
|
| - }
|
| - if (videoSelect.options.length > 0) {
|
| - source.videoId = videoSelect.options[videoSelect.selectedIndex].value;
|
| - }
|
| - return source;
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {NavigatorUserMediaError} error Error containing details.
|
| - */
|
| -function getUserMediaFailedCallback_(error) {
|
| - print_('GetUserMedia FAILED: Maybe the camera is in use by another process?');
|
| - gRequestWebcamAndMicrophoneResult = 'failed-with-error-' + error.name;
|
| - print_(gRequestWebcamAndMicrophoneResult);
|
| -}
|
| -
|
| -/** @private */
|
| -function success_(method) {
|
| - print_(method + '(): success.');
|
| -}
|
| -
|
| -/** @private */
|
| -function failure_(method, error) {
|
| - error_(method + '() failed: ' + error);
|
| -}
|
| -
|
| -/** @private */
|
| -function iceCallback_(event) {
|
| - if (event.candidate)
|
| - sendToPeer(global.remotePeerId, JSON.stringify(event.candidate));
|
| -}
|
| -
|
| -/** @private */
|
| -function setLocalAndSendMessage_(session_description) {
|
| - session_description.sdp =
|
| - global.transformOutgoingSdp(session_description.sdp);
|
| - global.peerConnection.setLocalDescription(
|
| - session_description,
|
| - function() { success_('setLocalDescription'); },
|
| - function() { failure_('setLocalDescription'); });
|
| - print_('Sending SDP message:\n' + session_description.sdp);
|
| - sendToPeer(global.remotePeerId, JSON.stringify(session_description));
|
| -}
|
| -
|
| -/** @private */
|
| -function addStreamCallback_(event) {
|
| - print_('Receiving remote stream...');
|
| - var videoTag = document.getElementById('remote-view');
|
| - attachMediaStream(videoTag, event.stream);
|
| -
|
| - window.addEventListener('loadedmetadata', function() {
|
| - displayVideoSize_(videoTag);}, true);
|
| -}
|
| -
|
| -/** @private */
|
| -function removeStreamCallback_(event) {
|
| - print_('Call ended.');
|
| - document.getElementById('remote-view').src = '';
|
| -}
|
| -
|
| -/** @private */
|
| -function onCreateDataChannelCallback_(event) {
|
| - if (global.dataChannel != null && global.dataChannel.readyState != 'closed') {
|
| - error_('Received DataChannel, but we already have one.');
|
| - }
|
| -
|
| - global.dataChannel = event.channel;
|
| - print_('DataChannel with label ' + global.dataChannel.label +
|
| - ' initiated by remote peer.');
|
| - hookupDataChannelEvents();
|
| -}
|
| -
|
| -/** @private */
|
| -function hookupDataChannelEvents() {
|
| - global.dataChannel.onmessage = global.dataCallback;
|
| - global.dataChannel.onopen = onDataChannelReadyStateChange_;
|
| - global.dataChannel.onclose = onDataChannelReadyStateChange_;
|
| - // Trigger global.dataStatusCallback so an application is notified
|
| - // about the created data channel.
|
| - onDataChannelReadyStateChange_();
|
| -}
|
| -
|
| -/** @private */
|
| -function onDataChannelReadyStateChange_() {
|
| - var readyState = global.dataChannel.readyState;
|
| - print_('DataChannel state:' + readyState);
|
| - global.dataStatusCallback(readyState);
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {MediaStream} stream Media stream.
|
| - */
|
| -function getUserMediaOkCallback_(stream) {
|
| - global.localStream = stream;
|
| - global.requestWebcamAndMicrophoneResult = 'ok-got-stream';
|
| -
|
| - if (stream.getVideoTracks().length > 0) {
|
| - // Show the video tag if we did request video in the getUserMedia call.
|
| - var videoTag = $('local-view');
|
| - attachMediaStream(videoTag, stream);
|
| -
|
| - window.addEventListener('loadedmetadata', function() {
|
| - displayVideoSize_(videoTag);}, true);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {string} videoTag The ID of the video tag + stream used to
|
| - * write the size to a HTML tag based on id if the div's exists.
|
| - */
|
| -function displayVideoSize_(videoTag) {
|
| - if ($(videoTag.id + '-stream-size') && $(videoTag.id + '-size')) {
|
| - if (videoTag.videoWidth > 0 || videoTag.videoHeight > 0) {
|
| - $(videoTag.id + '-stream-size').innerHTML = '(stream size: ' +
|
| - videoTag.videoWidth + 'x' +
|
| - videoTag.videoHeight + ')';
|
| - $(videoTag.id + '-size').innerHTML = videoTag.width + 'x' +
|
| - videoTag.height;
|
| - }
|
| - } else {
|
| - print_('Skipping updating -stream-size and -size tags due to div\'s ' +
|
| - 'are missing');
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Checks if the 'audiosrc' and 'videosrc' drop down menu elements has had all
|
| - * of its children appended in order to provide device ID's to the function
|
| - * 'updateGetUserMediaConstraints()', used in turn to populate the getUserMedia
|
| - * constraints text box when the page has loaded.
|
| - * @private
|
| - */
|
| -function checkIfDeviceDropdownsArePopulated_() {
|
| - if (document.addEventListener) {
|
| - $('audiosrc').addEventListener('DOMNodeInserted',
|
| - updateGetUserMediaConstraints, false);
|
| - $('videosrc').addEventListener('DOMNodeInserted',
|
| - updateGetUserMediaConstraints, false);
|
| - } else {
|
| - print_('addEventListener is not supported by your browser, cannot update ' +
|
| - 'device source ID\'s automatically. Select a device from the audio' +
|
| - ' or video source drop down menu to update device source id\'s');
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Register an input element to use local storage to remember its state between
|
| - * sessions (using local storage). Only input elements are supported.
|
| - * @private
|
| - * @param {!string} element_id to be used as a key for local storage and the id
|
| - * of the element to store the state for.
|
| - */
|
| -function registerLocalStorage_(element_id) {
|
| - var element = $(element_id);
|
| - if (element.tagName != 'INPUT') {
|
| - error_('You can only use registerLocalStorage_ for input elements. ' +
|
| - 'Element \"' + element.tagName + '\" is not an input element. ');
|
| - }
|
| -
|
| - if (localStorage.getItem(element.id) == 'undefined') {
|
| - storeLocalStorageField_(element);
|
| - } else {
|
| - getLocalStorageField_(element);
|
| - }
|
| - // Registers the appropriate events for input elements.
|
| - if (element.type == 'checkbox') {
|
| - element.onclick = function() { storeLocalStorageField_(this); };
|
| - } else if (element.type == 'text') {
|
| - element.onblur = function() { storeLocalStorageField_(this); };
|
| - } else {
|
| - error_('Unsupportered input type: ' + '\"' + element.type + '\"');
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Fetches the stored values from local storage and updates checkbox status.
|
| - * @private
|
| - * @param {!Object} element of which id is representing the key parameter for
|
| - * local storage.
|
| - */
|
| -function getLocalStorageField_(element) {
|
| - // Makes sure the checkbox status is matching the local storage value.
|
| - if (element.type == 'checkbox') {
|
| - element.checked = (localStorage.getItem(element.id) == 'true');
|
| - } else if (element.type == 'text') {
|
| - element.value = localStorage.getItem(element.id);
|
| - } else {
|
| - error_('Unsupportered input type: ' + '\"' + element.type + '\"');
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Stores the string value of the element object using local storage.
|
| - * @private
|
| - * @param {!Object} element of which id is representing the key parameter for
|
| - * local storage.
|
| - */
|
| -function storeLocalStorageField_(element) {
|
| - if (element.type == 'checkbox') {
|
| - localStorage.setItem(element.id, element.checked);
|
| - } else if (element.type == 'text') {
|
| - localStorage.setItem(element.id, element.value);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Create the peer connection if none is up (this is just convenience to
|
| - * avoid having a separate button for that).
|
| - * @private
|
| - */
|
| -function ensureHasPeerConnection_() {
|
| - if (getReadyState_() == 'no-peer-connection') {
|
| - preparePeerConnection();
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {string} message Text to print.
|
| - */
|
| -function print_(message) {
|
| - console.log(message);
|
| - $('messages').innerHTML += message + '<br>';
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {string} message Text to print.
|
| - */
|
| -function debug_(message) {
|
| - console.log(message);
|
| - $('debug').innerHTML += message + '<br>';
|
| -}
|
| -
|
| -/**
|
| - * Print error message in the debug log + JS console and throw an Error.
|
| - * @private
|
| - * @param {string} message Text to print.
|
| - */
|
| -function error_(message) {
|
| - $('debug').innerHTML += '<span style="color:red;">' + message + '</span><br>';
|
| - throw new Error(message);
|
| -}
|
| -
|
| -/**
|
| - * @private
|
| - * @param {string} stringRepresentation JavaScript as a string.
|
| - * @return {Object} The PeerConnection constraints as a JavaScript dictionary.
|
| - */
|
| -function getEvaluatedJavaScript_(stringRepresentation) {
|
| - try {
|
| - var evaluatedJavaScript;
|
| - eval('evaluatedJavaScript = ' + stringRepresentation);
|
| - return evaluatedJavaScript;
|
| - } catch (exception) {
|
| - error_('Not valid JavaScript expression: ' + stringRepresentation);
|
| - }
|
| -}
|
| -
|
| -/**
|
| - * Swaps lines within a SDP message.
|
| - * @private
|
| - * @param {string} sdp The full SDP message.
|
| - * @param {string} line The line to swap with swapWith.
|
| - * @param {string} swapWith The other line.
|
| - * @return {string} The altered SDP message.
|
| - */
|
| -function swapSdpLines_(sdp, line, swapWith) {
|
| - var lines = sdp.split('\r\n');
|
| - var lineStart = lines.indexOf(line);
|
| - var swapLineStart = lines.indexOf(swapWith);
|
| - if (lineStart == -1 || swapLineStart == -1)
|
| - return sdp; // This generally happens on the first message.
|
| -
|
| - var tmp = lines[lineStart];
|
| - lines[lineStart] = lines[swapLineStart];
|
| - lines[swapLineStart] = tmp;
|
| -
|
| - return lines.join('\r\n');
|
| -}
|
| -
|
| -/** @private */
|
| -function forceIsac_() {
|
| - setOutgoingSdpTransform(function(sdp) {
|
| - // Remove all other codecs (not the video codecs though).
|
| - sdp = sdp.replace(/m=audio (\d+) RTP\/SAVPF.*\r\n/g,
|
| - 'm=audio $1 RTP/SAVPF 104\r\n');
|
| - sdp = sdp.replace('a=fmtp:111 minptime=10', 'a=fmtp:104 minptime=10');
|
| - sdp = sdp.replace(/a=rtpmap:(?!104)\d{1,3} (?!VP8|red|ulpfec).*\r\n/g, '');
|
| - return sdp;
|
| - });
|
| -}
|
| -
|
| -/** @private */
|
| -function dontTouchSdp_() {
|
| - setOutgoingSdpTransform(function(sdp) { return sdp; });
|
| -}
|
| -
|
| -/** @private */
|
| -function hookupDataChannelCallbacks_() {
|
| - setDataCallbacks(function(status) {
|
| - $('data-channel-status').value = status;
|
| - },
|
| - function(data_message) {
|
| - print_('Received ' + data_message.data);
|
| - $('data-channel-receive').value =
|
| - data_message.data + '\n' + $('data-channel-receive').value;
|
| - });
|
| -}
|
| -
|
| -/** @private */
|
| -function hookupDtmfSenderCallback_() {
|
| - setOnToneChange(function(tone) {
|
| - print_('Sent DTMF tone: ' + tone.tone);
|
| - $('dtmf-tones-sent').value =
|
| - tone.tone + '\n' + $('dtmf-tones-sent').value;
|
| - });
|
| -}
|
| -
|
| -/** @private */
|
| -function toggle_(track, localOrRemote, audioOrVideo) {
|
| - if (!track)
|
| - error_('Tried to toggle ' + localOrRemote + ' ' + audioOrVideo +
|
| - ' stream, but has no such stream.');
|
| -
|
| - track.enabled = !track.enabled;
|
| - print_('ok-' + audioOrVideo + '-toggled-to-' + track.enabled);
|
| -}
|
| -
|
| -/** @private */
|
| -function connectCallback_(request) {
|
| - print_('Connect callback: ' + request.status + ', ' + request.readyState);
|
| - if (request.status == 0) {
|
| - print_('peerconnection_server doesn\'t seem to be up.');
|
| - print_('failed-to-connect');
|
| - }
|
| - if (request.readyState == 4 && request.status == 200) {
|
| - global.ourPeerId = parseOurPeerId_(request.responseText);
|
| - global.remotePeerId = parseRemotePeerIdIfConnected_(request.responseText);
|
| - startHangingGet_(global.serverUrl, global.ourPeerId);
|
| - print_('ok-connected');
|
| - }
|
| -}
|
| -
|
| -/** @private */
|
| -function parseOurPeerId_(responseText) {
|
| - // According to peerconnection_server's protocol.
|
| - var peerList = responseText.split('\n');
|
| - return parseInt(peerList[0].split(',')[1]);
|
| -}
|
| -
|
| -/** @private */
|
| -function parseRemotePeerIdIfConnected_(responseText) {
|
| - var peerList = responseText.split('\n');
|
| - if (peerList.length == 1) {
|
| - // No peers have connected yet - we'll get their id later in a notification.
|
| - return null;
|
| - }
|
| - var remotePeerId = null;
|
| - for (var i = 0; i < peerList.length; i++) {
|
| - if (peerList[i].length == 0)
|
| - continue;
|
| -
|
| - var parsed = peerList[i].split(',');
|
| - var name = parsed[0];
|
| - var id = parsed[1];
|
| -
|
| - if (id != global.ourPeerId) {
|
| - print_('Found remote peer with name ' + name + ', id ' +
|
| - id + ' when connecting.');
|
| -
|
| - // There should be at most one remote peer in this test.
|
| - if (remotePeerId != null)
|
| - error_('Expected just one remote peer in this test: ' +
|
| - 'found several.');
|
| -
|
| - // Found a remote peer.
|
| - remotePeerId = id;
|
| - }
|
| - }
|
| - return remotePeerId;
|
| -}
|
| -
|
| -/** @private */
|
| -function startHangingGet_(server, ourId) {
|
| - if (isDisconnected_())
|
| - return;
|
| -
|
| - hangingGetRequest = new XMLHttpRequest();
|
| - hangingGetRequest.onreadystatechange = function() {
|
| - hangingGetCallback_(hangingGetRequest, server, ourId);
|
| - };
|
| - hangingGetRequest.ontimeout = function() {
|
| - hangingGetTimeoutCallback_(hangingGetRequest, server, ourId);
|
| - };
|
| - callUrl = server + '/wait?peer_id=' + ourId;
|
| - print_('Sending ' + callUrl);
|
| - hangingGetRequest.open('GET', callUrl, true);
|
| - hangingGetRequest.send();
|
| -}
|
| -
|
| -/** @private */
|
| -function hangingGetCallback_(hangingGetRequest, server, ourId) {
|
| - if (hangingGetRequest.readyState != 4 || hangingGetRequest.status == 0) {
|
| - // Code 0 is not possible if the server actually responded. Ignore.
|
| - return;
|
| - }
|
| - if (hangingGetRequest.status != 200) {
|
| - error_('Error ' + hangingGetRequest.status + ' from server: ' +
|
| - hangingGetRequest.statusText);
|
| - }
|
| - var targetId = readResponseHeader_(hangingGetRequest, 'Pragma');
|
| - if (targetId == ourId)
|
| - handleServerNotification_(hangingGetRequest.responseText);
|
| - else
|
| - handlePeerMessage_(targetId, hangingGetRequest.responseText);
|
| -
|
| - hangingGetRequest.abort();
|
| - restartHangingGet_(server, ourId);
|
| -}
|
| -
|
| -/** @private */
|
| -function hangingGetTimeoutCallback_(hangingGetRequest, server, ourId) {
|
| - print_('Hanging GET times out, re-issuing...');
|
| - hangingGetRequest.abort();
|
| - restartHangingGet_(server, ourId);
|
| -}
|
| -
|
| -/** @private */
|
| -function handleServerNotification_(message) {
|
| - var parsed = message.split(',');
|
| - if (parseInt(parsed[2]) == 1) {
|
| - // Peer connected - this must be our remote peer, and it must mean we
|
| - // connected before them (except if we happened to connect to the server
|
| - // at precisely the same moment).
|
| - print_('Found remote peer with name ' + parsed[0] + ', id ' + parsed[1] +
|
| - ' when connecting.');
|
| - global.remotePeerId = parseInt(parsed[1]);
|
| - }
|
| -}
|
| -
|
| -/** @private */
|
| -function closeCall_() {
|
| - if (global.peerConnection == null)
|
| - debug_('Closing call, but no call active.');
|
| - global.peerConnection.close();
|
| - global.peerConnection = null;
|
| -}
|
| -
|
| -/** @private */
|
| -function handlePeerMessage_(peerId, message) {
|
| - print_('Received message from peer ' + peerId + ': ' + message);
|
| - if (peerId != global.remotePeerId) {
|
| - error_('Received notification from unknown peer ' + peerId +
|
| - ' (only know about ' + global.remotePeerId + '.');
|
| - }
|
| - if (message.search('BYE') == 0) {
|
| - print_('Received BYE from peer: closing call');
|
| - closeCall_();
|
| - return;
|
| - }
|
| - if (global.peerConnection == null && global.acceptsIncomingCalls) {
|
| - // The other side is calling us.
|
| - print_('We are being called: answer...');
|
| -
|
| - global.peerConnection = createPeerConnection(STUN_SERVER,
|
| - $('data-channel-type-rtp').checked);
|
| -
|
| - if ($('auto-add-stream-oncall') &&
|
| - obtainGetUserMediaResult_() == 'ok-got-stream') {
|
| - print_('We have a local stream, so hook it up automatically.');
|
| - addLocalStreamToPeerConnection(global.peerConnection);
|
| - }
|
| - answerCall(global.peerConnection, message);
|
| - return;
|
| - }
|
| - handleMessage(global.peerConnection, message);
|
| -}
|
| -
|
| -/** @private */
|
| -function restartHangingGet_(server, ourId) {
|
| - window.setTimeout(function() {
|
| - startHangingGet_(server, ourId);
|
| - }, 0);
|
| -}
|
| -
|
| -/** @private */
|
| -function readResponseHeader_(request, key) {
|
| - var value = request.getResponseHeader(key);
|
| - if (value == null || value.length == 0) {
|
| - error_('Received empty value ' + value +
|
| - ' for response header key ' + key + '.');
|
| - }
|
| - return parseInt(value);
|
| -}
|
|
|