Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(430)

Unified Diff: chrome/test/data/webrtc/message_handling.js

Issue 271653002: Rewrote WebRTC browser tests to not use peerconnection_server. (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Nit fixes Created 6 years, 7 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « chrome/test/data/webrtc/jsep01_call.js ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: chrome/test/data/webrtc/message_handling.js
diff --git a/chrome/test/data/webrtc/message_handling.js b/chrome/test/data/webrtc/message_handling.js
index 377f95f1aa63298f77b5e8e95334f55ba27f5a14..6329ed303480e5863dcfbecbe23664f2becfa87b 100644
--- a/chrome/test/data/webrtc/message_handling.js
+++ b/chrome/test/data/webrtc/message_handling.js
@@ -5,162 +5,117 @@
*/
// This file requires these functions to be defined globally by someone else:
-// function handleMessage(peerConnection, message)
// function createPeerConnection(stun_server, useRtpDataChannel)
-// function setupCall(peerConnection)
-// function answerCall(peerConnection, message)
+// function createOffer(peerConnection, constraints, callback)
+// function receiveOffer(peerConnection, offer, constraints, callback)
+// function receiveAnswer(peerConnection, answer, callback)
// Currently these functions are supplied by jsep01_call.js.
/**
- * This object represents the call.
- * @private
- */
-var gPeerConnection = null;
-
-/**
- * True if we are accepting incoming calls.
- * @private
- */
-var gAcceptsIncomingCalls = true;
-
-/**
- * Our peer id as assigned by the peerconnection_server.
- * @private
- */
-var gOurPeerId = null;
-
-/**
- * The client id we use to identify to peerconnection_server.
- * @private
- */
-var gOurClientName = null;
-
-/**
- * The URL to the peerconnection_server.
- * @private
- */
-var gServerUrl = null;
-
-/**
- * The remote peer's id. We receive this one either when we connect (in the case
- * our peer connects before us) or in a notification later.
+ * We need a STUN server for some API calls.
* @private
*/
-var gRemotePeerId = null;
+var STUN_SERVER = 'stun.l.google.com:19302';
/**
- * Whether or not to auto-respond by adding our local stream when we are called.
+ * This object represents the call.
* @private
*/
-var gAutoAddLocalToPeerConnectionStreamWhenCalled = true;
+var gPeerConnection = null;
/**
- * The one and only data channel.
- * @private
+ * If true, any created peer connection will use RTP data
+ * channels. Otherwise it will use SCTP data channels.
*/
-var gDataChannel = null;
+var gUseRtpDataChannels = true;
/**
- * The DTMF sender.
+ * This stores ICE candidates generated on this side.
* @private
*/
-var gDtmfSender = null;
+var gIceCandidates = [];
-/**
- * We need a STUN server for some API calls.
- * @private
- */
-var STUN_SERVER = 'stun.l.google.com:19302';
+// Public interface to tests. These are expected to be called with
+// ExecuteJavascript invocations from the browser tests and will return answers
+// through the DOM automation controller.
/**
- * If true, any created peer connection will use RTP data
- * channels. Otherwise it will use SCTP data channels.
+ * Creates a peer connection. Must be called before most other public functions
+ * in this file.
*/
-var gUseRtpDataChannels = true;
-
-// Public interface to tests.
+function preparePeerConnection() {
+ if (gPeerConnection != null)
+ throw failTest('creating peer connection, but we already have one.');
+ gPeerConnection = createPeerConnection(STUN_SERVER, gUseRtpDataChannels);
+ returnToTest('ok-peerconnection-created');
+}
/**
- * Connects to the provided peerconnection_server.
+ * Asks this page to create a local offer.
*
- * @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.
+ * Returns a string on the format ok-(JSON encoded session description).
+ *
+ * @param {!object} constraints Any createOffer constraints.
*/
-function connect(serverUrl, clientName) {
- if (gOurPeerId != null)
- throw failTest('connecting, but is already connected.');
-
- debug('Connecting to ' + serverUrl + ' as ' + clientName);
- gServerUrl = serverUrl;
- gOurClientName = clientName;
-
- request = new XMLHttpRequest();
- request.open('GET', serverUrl + '/sign_in?' + clientName, true);
- debug(serverUrl + '/sign_in?' + clientName);
- request.onreadystatechange = function() {
- connectCallback_(request);
- }
- request.send();
-}
+function createLocalOffer(constraints) {
+ if (gPeerConnection == null)
+ throw failTest('Negotiating call, but we have no peer connection.');
-/**
- * Checks if the remote peer has connected. Returns peer-connected if that is
- * the case, otherwise no-peer-connected.
- */
-function remotePeerIsConnected() {
- if (gRemotePeerId == null)
- returnToTest('no-peer-connected');
- else
- returnToTest('peer-connected');
+ // TODO(phoglund): move jsep01.call stuff into this file and remove need
+ // of the createOffer method, etc.
+ createOffer(gPeerConnection, constraints, function(localOffer) {
+ returnToTest('ok-' + JSON.stringify(localOffer));
+ });
}
/**
- * Set if RTP data channels should be used for peerconnections.
- * @param{boolean} useRtpDataChannel
+ * Asks this page to accept an offer and generate an answer.
+ *
+ * Returns a string on the format ok-(JSON encoded session description).
+ *
+ * @param {!string} sessionDescJson A JSON-encoded session description of type
+ * 'offer'.
+ * @param {!object} constraints Any createAnswer constraints.
*/
-function useRtpDataChannelsForNewPeerConnections(useRtpDataChannels) {
- gUseRtpDataChannels = useRtpDataChannels;
-}
+function receiveOfferFromPeer(sessionDescJson, constraints) {
+ if (gPeerConnection == null)
+ throw failTest('Receiving offer, but we have no peer connection.');
-/**
- * Creates a peer connection. Must be called before most other public functions
- * in this file.
- */
-function preparePeerConnection() {
- if (gPeerConnection != null)
- throw failTest('creating peer connection, but we already have one.');
+ offer = parseJson_(sessionDescJson);
+ if (!offer.type)
+ failTest('Got invalid session description from peer: ' + sessionDescJson);
+ if (offer.type != 'offer')
+ failTest('Expected to receive offer from peer, got ' + offer.type);
- gPeerConnection = createPeerConnection(STUN_SERVER, gUseRtpDataChannels);
- returnToTest('ok-peerconnection-created');
+ receiveOffer(gPeerConnection, offer , constraints, function(answer) {
+ returnToTest('ok-' + JSON.stringify(answer));
+ });
}
/**
- * Negotiates a call with the other side. This will create a peer connection on
- * the other side if there isn't one. The other side will automatically add any
- * stream it has unless doNotAutoAddLocalStreamWhenCalled() has been called.
+ * Asks this page to accept an answer generated by the peer in response to a
+ * previous offer by this page
*
- * 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.
+ * Returns a string ok-accepted-answer on success.
*
- * 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.
+ * @param {!string} sessionDescJson A JSON-encoded session description of type
+ * 'answer'.
*/
-function negotiateCall() {
+function receiveAnswerFromPeer(sessionDescJson) {
if (gPeerConnection == null)
- throw failTest('negotiating call, but we have no peer connection.');
- if (gOurPeerId == null)
- throw failTest('negotiating call, but not connected.');
- if (gRemotePeerId == null)
- throw failTest('negotiating call, but missing remote peer.');
-
- setupCall(gPeerConnection);
- returnToTest('ok-negotiating');
+ throw failTest('Receiving offer, but we have no peer connection.');
+
+ answer = parseJson_(sessionDescJson);
+ if (!answer.type)
+ failTest('Got invalid session description from peer: ' + sessionDescJson);
+ if (answer.type != 'answer')
+ failTest('Expected to receive answer from peer, got ' + answer.type);
+
+ receiveAnswer(gPeerConnection, answer, function() {
+ returnToTest('ok-accepted-answer');
+ });
}
/**
@@ -226,374 +181,86 @@ function playAudioFile() {
}
/**
- * 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 (gPeerConnection == null)
- throw failTest('attempting to remove local stream, but no call is up');
-
- removeLocalStreamFromPeerConnection(gPeerConnection);
- returnToTest('ok-local-stream-removed');
-}
-
-/**
- * (see getReadyState)
- */
-function getPeerConnectionReadyState() {
- returnToTest(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 selectAudioOrVideoTrack: A function that takes a remote stream as
- * argument and returns a track (e.g. either the video or audio track).
- * @param typeToToggle: Either "audio" or "video" depending on what the selector
- * function selects.
- */
-function toggleRemoteStream(selectAudioOrVideoTrack, typeToToggle) {
- if (gPeerConnection == null)
- throw failTest('Tried to toggle remote stream, ' +
- 'but have no peer connection.');
- if (gPeerConnection.getRemoteStreams().length == 0)
- throw failTest('Tried to toggle remote stream, ' +
- 'but not receiving any stream.');
-
- var track = selectAudioOrVideoTrack(gPeerConnection.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 (gPeerConnection == null)
- throw failTest('Tried to toggle local stream, ' +
- 'but have no peer connection.');
- if (gPeerConnection.getLocalStreams().length == 0)
- throw failTest('Tried to toggle local stream, but there is no local ' +
- 'stream in the call.');
-
- var track = selectAudioOrVideoTrack(gPeerConnection.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.
+ * Hangs up a started call. Returns ok-call-hung-up on success.
*/
function hangUp() {
if (gPeerConnection == null)
throw failTest('hanging up, but has no peer connection');
- if (getReadyState() != 'active')
- throw failTest('hanging up, but ready state is not active (no call up).');
- sendToPeer(gRemotePeerId, 'BYE');
- closeCall_();
- gAcceptsIncomingCalls = false;
+ gPeerConnection.close();
+ gPeerConnection = null;
returnToTest('ok-call-hung-up');
}
/**
- * Start accepting incoming calls again after a hangup.
- */
-function acceptIncomingCallsAgain() {
- gAcceptsIncomingCalls = true;
-}
-
-/**
- * Do not auto-add the local stream when called.
- */
-function doNotAutoAddLocalStreamWhenCalled() {
- gAutoAddLocalToPeerConnectionStreamWhenCalled = false;
-}
-
-/**
- * Disconnects from the peerconnection server. Returns ok-disconnected on
- * success.
- */
-function disconnect() {
- if (gOurPeerId == null)
- throw failTest('Disconnecting, but we are not connected.');
-
- request = new XMLHttpRequest();
- request.open('GET', gServerUrl + '/sign_out?peer_id=' + gOurPeerId, false);
- request.send();
- gOurPeerId = null;
- returnToTest('ok-disconnected');
-}
-
-/**
- * Creates a DataChannel on the current PeerConnection. Only one DataChannel can
- * be created on each PeerConnection.
- * Returns ok-datachannel-created on success.
+ * Retrieves all ICE candidates generated on this side. Must be called after
+ * ICE candidate generation is triggered (for instance by running a call
+ * negotiation). This function will wait if necessary if we're not done
+ * generating ICE candidates on this side.
+ *
+ * Returns a JSON-encoded array of RTCIceCandidate instances to the test.
*/
-function createDataChannelOnPeerConnection() {
+function getAllIceCandidates() {
if (gPeerConnection == null)
- throw failTest('Tried to create data channel, ' +
- 'but have no peer connection.');
+ throw failTest('Trying to get ICE candidates, but has no peer connection.');
- createDataChannel(gPeerConnection, gOurClientName);
- returnToTest('ok-datachannel-created');
-}
-
-/**
- * Close the DataChannel on the current PeerConnection.
- * Returns ok-datachannel-close on success.
- */
-function closeDataChannelOnPeerConnection() {
- if (gPeerConnection == null)
- throw failTest('Tried to close data channel, ' +
- 'but have no peer connection.');
+ if (gPeerConnection.iceGatheringState != 'complete') {
+ console.log('Still ICE gathering - waiting...');
+ setTimeout(getAllIceCandidates, 100);
+ return;
+ }
- closeDataChannel(gPeerConnection);
- returnToTest('ok-datachannel-close');
+ returnToTest(JSON.stringify(gIceCandidates));
}
/**
- * Creates a DTMF sender on the current PeerConnection.
- * Returns ok-dtmfsender-created on success.
+ * Receives ICE candidates from the peer.
+ *
+ * Returns ok-received-candidates to the test on success.
+ *
+ * @param iceCandidatesJson a JSON-encoded array of RTCIceCandidate instances.
*/
-function createDtmfSenderOnPeerConnection() {
+function receiveIceCandidates(iceCandidatesJson) {
if (gPeerConnection == null)
- throw failTest('Tried to create DTMF sender, ' +
- 'but have no peer connection.');
+ throw failTest('Received ICE candidate, but has no peer connection');
- createDtmfSender(gPeerConnection);
- returnToTest('ok-dtmfsender-created');
-}
+ var iceCandidates = parseJson_(iceCandidatesJson);
+ if (!iceCandidates.length)
+ throw failTest('Received invalid ICE candidate list from peer: ' +
+ iceCandidatesJson);
-/**
- * Send DTMF tones on the gDtmfSender.
- * Returns ok-dtmf-sent on success.
- */
-function insertDtmfOnSender(tones, duration, interToneGap) {
- if (gDtmfSender == null)
- throw failTest('Tried to insert DTMF tones, ' +
- 'but have no DTMF sender.');
+ iceCandidates.forEach(function(iceCandidate) {
+ if (!iceCandidate.candidate)
+ failTest('Received invalid ICE candidate from peer: ' +
+ iceCandidatesJson);
+
+ gPeerConnection.addIceCandidate(new RTCIceCandidate(iceCandidate));
+ });
- insertDtmf(tones, duration, interToneGap);
- returnToTest('ok-dtmf-sent');
+ returnToTest('ok-received-candidates');
}
// Public interface to signaling implementations, such as JSEP.
/**
- * Sends a message to a peer through the peerconnection_server.
- */
-function sendToPeer(peer, message) {
- var messageToLog = message.sdp ? message.sdp : message;
- debug('Sending message ' + messageToLog + ' to peer ' + peer + '.');
-
- var request = new XMLHttpRequest();
- var url = gServerUrl + '/message?peer_id=' + gOurPeerId + '&to=' + peer;
- request.open('POST', url, false);
- request.setRequestHeader('Content-Type', 'text/plain');
- request.send(message);
-}
-
-/**
- * Returns true if we are disconnected from peerconnection_server.
+ * Enqueues an ICE candidate for sending to the peer.
+ *
+ * @param {!RTCIceCandidate} The ICE candidate to send.
*/
-function isDisconnected() {
- return gOurPeerId == null;
+function sendIceCandidate(message) {
+ gIceCandidates.push(message);
}
/**
- * @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'.
+ * Parses JSON-encoded session descriptions and ICE candidates.
+ * @private
*/
-function getReadyState() {
- if (gPeerConnection == null)
- return 'no-peer-connection';
-
- return 'active';
-}
-
-// Internals.
-
-/** @private */
-function toggle_(track, localOrRemote, audioOrVideo) {
- if (!track)
- throw failTest('Tried to toggle ' + localOrRemote + ' ' + audioOrVideo +
- ' stream, but has no such stream.');
-
- track.enabled = !track.enabled;
- returnToTest('ok-' + audioOrVideo + '-toggled-to-' + track.enabled);
-}
-
-/** @private */
-function connectCallback_(request) {
- debug('Connect callback: ' + request.status + ', ' + request.readyState);
- if (request.status == 0) {
- debug('peerconnection_server doesn\'t seem to be up.');
- returnToTest('failed-to-connect');
- }
- if (request.readyState == 4 && request.status == 200) {
- gOurPeerId = parseOurPeerId_(request.responseText);
- gRemotePeerId = parseRemotePeerIdIfConnected_(request.responseText);
- startHangingGet_(gServerUrl, gOurPeerId);
- returnToTest('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 != gOurPeerId) {
- debug('Found remote peer with name ' + name + ', id ' +
- id + ' when connecting.');
-
- // There should be at most one remote peer in this test.
- if (remotePeerId != null)
- throw failTest('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;
- debug('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) {
- throw failTest('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) {
- debug('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).
- debug('Found remote peer with name ' + parsed[0] + ', id ' +
- parsed[1] + ' when connecting.');
- gRemotePeerId = parseInt(parsed[1]);
- }
-}
-
-/** @private */
-function closeCall_() {
- if (gPeerConnection == null)
- throw failTest('Closing call, but no call active.');
- gPeerConnection.close();
- gPeerConnection = null;
-}
-
-/** @private */
-function handlePeerMessage_(peerId, message) {
- debug('Received message from peer ' + peerId + ': ' + message);
- if (peerId != gRemotePeerId) {
- throw failTest('Received notification from unknown peer ' + peerId +
- ' (only know about ' + gRemotePeerId + '.');
- }
- if (message.search('BYE') == 0) {
- debug('Received BYE from peer: closing call');
- closeCall_();
- return;
- }
- if (gPeerConnection == null && gAcceptsIncomingCalls) {
- // The other side is calling us.
- debug('We are being called: answer...');
-
- gPeerConnection = createPeerConnection(STUN_SERVER, gUseRtpDataChannels);
- if (gAutoAddLocalToPeerConnectionStreamWhenCalled &&
- obtainGetUserMediaResult() == 'ok-got-stream') {
- debug('We have a local stream, so hook it up automatically.');
- addLocalStreamToPeerConnection(gPeerConnection);
- }
- answerCall(gPeerConnection, message);
- return;
- }
- if (gPeerConnection == null) {
- debug('Discarding message ' + message + '; already disconnected.');
- return;
- }
-
- handleMessage(gPeerConnection, 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) {
- throw failTest('Received empty value ' + value +
- ' for response header key ' + key + '.');
+function parseJson_(json) {
+ // Escape since the \r\n in the SDP tend to get unescaped.
+ jsonWithEscapedLineBreaks = json.replace(/\r\n/g, '\\r\\n');
+ try {
+ return JSON.parse(jsonWithEscapedLineBreaks);
+ } catch (exception) {
+ failTest('Failed to parse JSON: ' + jsonWithEscapedLineBreaks + ', got ' +
+ exception);
}
- return parseInt(value);
}
« no previous file with comments | « chrome/test/data/webrtc/jsep01_call.js ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698