peerconnection-call.html revision 2a99a7e74a7f215066514fe81d2bfa6639d9eddd
1b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org<html>
2b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org<head>
3b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  <script type="text/javascript">
4b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  $ = function(id) {
5b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return document.getElementById(id);
6b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  };
7b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
8b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // These must match with how the video and canvas tags are declared in html.
9b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const VIDEO_TAG_WIDTH = 320;
10b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  const VIDEO_TAG_HEIGHT = 240;
11b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
12b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  var gFirstConnection = null;
13cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org  var gSecondConnection = null;
14b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  var gTestWithoutMsidAndBundle = false;
15cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org
16b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Number of test events to occur before the test pass. When the test pass,
17cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org  // the document title change to OK.
18cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org  var gNumberOfExpectedEvents = 0;
19cbd78ae09f44b003a9969536b78f08cd1ff513e8pbos@webrtc.org
207fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // Number of events that currently have occured.
21b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  var gNumberOfEvents = 0;
22b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
23b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  var gLocalStream = null;
24b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  var gSentTones = '';
25b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
267fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // Test that we can setup call with an audio and video track.
27b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function call(constraints) {
28b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    createConnections(null);
29b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    navigator.webkitGetUserMedia(constraints,
30b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org      addStreamToBothConnectionsAndNegotiate, printGetUserMediaError);
31b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-1');
32b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-2');
33b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
34b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
35b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // First calls without streams on any connections, and then adds a stream
36b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // to peer connection 1 which gets sent to peer connection 2.
37b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function makeEmptyCallThenAddOneStreamAndRenegotiate(constraints) {
38b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections(null);
39b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    negotiate();
40b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    navigator.webkitGetUserMedia(constraints,
41b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      addStreamToTheFirstConnectionAndNegotiate, printGetUserMediaError);
42b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Only the first connection is sending here.
43b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-2');
44b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
45b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
46b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Test that we can setup call with an audio and video track and
47b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // simulate that the remote peer don't support MSID.
48b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function callWithoutMsidAndBundle() {
49b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections(null);
50b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gTestWithoutMsidAndBundle = true;
51b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    navigator.webkitGetUserMedia({audio:true, video:true},
52b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      addStreamToBothConnectionsAndNegotiate, printGetUserMediaError);
53b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // TODO(phoglund): this should work but it doesn't! http://crbug.com/177443.
54b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // waitForVideo('remote-view-1');
55b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-2');
56b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
57b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
58b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Test only a data channel.
59b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function callWithDataOnly() {
60b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections({optional:[{RtpDataChannels: true}]});
61b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    setupDataChannel();
627fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.createOffer(onOfferCreated);
63b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
64b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org
65b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  // Test call with audio, video and a data channel.
66b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  function callWithDataAndMedia() {
67b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections({optional:[{RtpDataChannels: true}]});
68b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    setupDataChannel();
69b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    navigator.webkitGetUserMedia({audio:true, video:true},
70b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org      addStreamToBothConnectionsAndNegotiate,
71b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      printGetUserMediaError);
72b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-1');
73b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-2');
74b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
75b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
76b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Test call with a data channel and later add audio and video.
77b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function callWithDataAndLaterAddMedia() {
78b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // TODO(perkj): This is needed for now until
797fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    // https://code.google.com/p/webrtc/issues/detail?id=1203 is fixed.
80b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    gTestWithoutMsidAndBundle = true;
81b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org
82b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections({optional:[{RtpDataChannels: true}]});
83b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    setupDataChannel();
84b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gFirstConnection.createOffer(onOfferCreated);
85b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
86b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    navigator.webkitGetUserMedia({audio:true, video:true},
87b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      addStreamToBothConnectionsAndNegotiate, printGetUserMediaError);
88b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-1');
89b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    waitForVideo('remote-view-2');
90b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
91b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
92b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Test that we can setup call and send DTMF.
93b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function callAndSendDtmf(tones) {
94b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    createConnections(null);
95b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    navigator.webkitGetUserMedia({audio:true, video:true},
96b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      addStreamToBothConnectionsAndNegotiate, printGetUserMediaError);
97b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    var onCallEstablished = function() {
98b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // Send DTMF tones.
99b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      var localAudioTrack = gLocalStream.getAudioTracks()[0];
100b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      var dtmfSender = gFirstConnection.createDTMFSender(localAudioTrack);
101b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      dtmfSender.ontonechange = onToneChange;
102b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      dtmfSender.insertDTMF(tones);
1031bb2146351979b6610107419b2a9c86cca2692a3stefan@webrtc.org      // Wait for the DTMF tones callback.
104b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      document.title = 'Waiting for dtmf...';
105b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      addExpectedEvent();
106b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      var waitDtmf = setInterval(function() {
107b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        if (gSentTones == tones) {
108b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          clearInterval(waitDtmf);
109b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          eventOccured();
110b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        }
111b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }, 100);
112b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
113b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
114b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Do the DTMF test after we have received video.
115b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    detectVideoIn('remote-view-2', onCallEstablished);
116b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
117b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
118b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // This function is used for setting up a test that:
119b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // 1. Creates a data channel on |gFirstConnection| and sends data to
120b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  //    |gSecondConnection|.
1217fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // 2. When data is received on |gSecondConnection| a message
1227fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  //    is sent to |gFirstConnection|.
1237fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // 3. When data is received on |gFirstConnection|, the data
1247fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  //    channel is closed. The test passes when the state transition completes.
12599681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org  function setupDataChannel() {
1267fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var sendDataString = "send some text on a data channel."
12799681317b0a9dc29c1682a17908f382eac16bd2aandresp@webrtc.org    firstDataChannel = gFirstConnection.createDataChannel(
1287fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org        "sendDataChannel", {reliable : false});
129b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    expectEquals('connecting', firstDataChannel.readyState);
130b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
131b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // When |firstDataChannel| transition to open state, send a text string.
132b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    firstDataChannel.onopen = function() {
1337fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      expectEquals('open', firstDataChannel.readyState);
134b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      firstDataChannel.send(sendDataString);
135b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
136b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
137b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // When |firstDataChannel| receive a message, close the channel and
1387fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    // initiate a new offer/answer exchange to complete the closure.
1397fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    firstDataChannel.onmessage = function(event) {
1407fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      expectEquals(event.data, sendDataString);
141b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      firstDataChannel.close();
142b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      gFirstConnection.createOffer(onOfferCreated);
1437fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
144b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
145b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // When |firstDataChannel| transition to closed state, the test pass.
146b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    addExpectedEvent();
147b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    firstDataChannel.onclose = function() {
1487fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      expectEquals('closed', firstDataChannel.readyState);
1497fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      eventOccured();
1507fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
1517fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
1527fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    // Event handler for when |gSecondConnection| receive a new dataChannel.
1537fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gSecondConnection.ondatachannel = function (event) {
1547fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      var secondDataChannel = event.channel;
1557fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
156b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      // When |secondDataChannel| receive a message, send a message back.
157b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      secondDataChannel.onmessage = function(event) {
158b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        expectEquals(event.data, sendDataString);
159b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        expectEquals('open', secondDataChannel.readyState);
160b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        secondDataChannel.send(sendDataString);
161b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
162b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
163b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
164b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
165b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function onToneChange(tone) {
166b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSentTones += tone.tone;
167b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    document.title = gSentTones;
168b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
169b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
170b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function createConnections(constraints) {
171b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gFirstConnection = new webkitRTCPeerConnection(null, constraints);
1727fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.onicecandidate = onIceCandidateToFirst;
1737fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.onaddstream = function(event) {
1747fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      onRemoteStream(event, 'remote-view-1');
1757fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
1767fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    expectEquals('stable', gFirstConnection.signalingState);
1777fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
178b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSecondConnection = new webkitRTCPeerConnection(null, constraints);
179b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSecondConnection.onicecandidate = onIceCandidateToSecond;
180b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSecondConnection.onaddstream = function(event) {
181b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      onRemoteStream(event, 'remote-view-2');
182b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
183b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
184b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org
185b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  function displayAndRemember(localStream) {
186b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    var localStreamUrl = webkitURL.createObjectURL(localStream);
187b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    $('local-view').src = localStreamUrl;
1881bb2146351979b6610107419b2a9c86cca2692a3stefan@webrtc.org
189b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gLocalStream = localStream;
190b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
191b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
192903e746cc9a73da17bfa3f6110293582fa6ee3bestefan@webrtc.org  // Called if getUserMedia fails.
193b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function printGetUserMediaError(error) {
194b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    document.title = 'getUserMedia request failed with code ' + error.code;
195b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
1967fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
197b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Called if getUserMedia succeeds and we want to send from both connections.
198b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function addStreamToBothConnectionsAndNegotiate(localStream) {
199b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    displayAndRemember(localStream);
200b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gFirstConnection.addStream(localStream);
201b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSecondConnection.addStream(localStream);
202b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    negotiate();
2037fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
204b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
205b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // Called if getUserMedia succeeds when we want to send from one connection.
206b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function addStreamToTheFirstConnectionAndNegotiate(localStream) {
2077fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    displayAndRemember(localStream);
20864b5c6141a124816290795f80d555eb994edec32pbos@webrtc.org    gFirstConnection.addStream(localStream);
2097fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    negotiate();
2107fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2117fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2127fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function negotiate() {
2137fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.createOffer(onOfferCreated);
2147fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2157fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2167fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function onOfferCreated(offer) {
2177fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.setLocalDescription(offer);
2187fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    expectEquals('have-local-offer', gFirstConnection.signalingState);
2197fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    receiveOffer(offer.sdp);
2207fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2217fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2227fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function receiveOffer(offerSdp) {
2237fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    if (gTestWithoutMsidAndBundle) {
2247fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      offerSdp = removeMsidAndBundle(offerSdp);
2257fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
2267fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2277fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var parsedOffer = new RTCSessionDescription({ type: 'offer',
228b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org                                                  sdp: offerSdp });
229b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    gSecondConnection.setRemoteDescription(parsedOffer);
230b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    gSecondConnection.createAnswer(onAnswerCreated);
231b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    expectEquals('have-remote-offer', gSecondConnection.signalingState);
232b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
233b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
2347fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function removeMsidAndBundle(offerSdp) {
2357e97e4c84dc21b2853f5158a03dcceb569e493adstefan@webrtc.org    offerSdp = offerSdp.replace(/a=msid-semantic.*\r\n/g, '');
2367e97e4c84dc21b2853f5158a03dcceb569e493adstefan@webrtc.org    offerSdp = offerSdp.replace('a=group:BUNDLE audio video\r\n', '');
2377e97e4c84dc21b2853f5158a03dcceb569e493adstefan@webrtc.org    offerSdp = offerSdp.replace('a=mid:audio\r\n', '');
238b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    offerSdp = offerSdp.replace('a=mid:video\r\n', '');
239b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    offerSdp = offerSdp.replace(/a=ssrc.*\r\n/g, '');
240b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    return offerSdp;
2417fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
24264b5c6141a124816290795f80d555eb994edec32pbos@webrtc.org
2437fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function onAnswerCreated(answer) {
2447fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gSecondConnection.setLocalDescription(answer);
2457fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    expectEquals('stable', gSecondConnection.signalingState);
2467fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    handleAnswer(answer.sdp);
2477fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2487fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2497fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function handleAnswer(answerSdp) {
2507fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var parsedAnswer = new RTCSessionDescription({ type: 'answer',
2517fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org                                                   sdp: answerSdp });
2527fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    gFirstConnection.setRemoteDescription(parsedAnswer);
2537fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    expectEquals('stable', gFirstConnection.signalingState);
2547fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2557fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2567fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function onIceCandidateToFirst(event) {
2577fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    if (event.candidate) {
2587fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      var candidate = new RTCIceCandidate(event.candidate);
2597fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      gSecondConnection.addIceCandidate(candidate);
2607fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
2617fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
262b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
263903e746cc9a73da17bfa3f6110293582fa6ee3bestefan@webrtc.org  function onIceCandidateToSecond(event) {
264b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    if (event.candidate) {
265b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      var candidate = new RTCIceCandidate(event.candidate);
266b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      gFirstConnection.addIceCandidate(candidate);
2677fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
2687fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2697fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
270b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function onRemoteStream(e, target) {
2717fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    if (gTestWithoutMsidAndBundle && e.stream.label != "default") {
272b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org      document.title = 'a default remote stream was expected but instead ' +
273b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          e.stream.label + ' was received.';
2747fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      return;
2757fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
2767fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var remoteStreamUrl = webkitURL.createObjectURL(e.stream);
2777fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var remoteVideo = $(target);
2787fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    remoteVideo.src = remoteStreamUrl;
2797fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
2807fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
2817fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // TODO(phoglund): perhaps use the video detector in chrome/test/data/webrtc/?
2827fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function detectVideoIn(videoElementName, callback) {
2837fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var width = VIDEO_TAG_WIDTH;
2847fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var height = VIDEO_TAG_HEIGHT;
2857fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var videoElement = $(videoElementName);
2867fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    var canvas = $(videoElementName + '-canvas');
287b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    var waitVideo = setInterval(function() {
288b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      var context = canvas.getContext('2d');
289b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      context.drawImage(videoElement, 0, 0, width, height);
290b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org      var pixels = context.getImageData(0, 0, width, height).data;
291b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
292b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (isVideoPlaying(pixels, width, height)) {
293b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org        clearInterval(waitVideo);
294b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        callback();
295b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      }
296b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org    }, 100);
297b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
298b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
299b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  function waitForVideo(videoElement) {
300b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    document.title = 'Waiting for video...';
301b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    addExpectedEvent();
302b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    detectVideoIn(videoElement, function () { eventOccured(); });
303b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  }
304b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org
305b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // This very basic video verification algorithm will be satisfied if any
306b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // pixels are nonzero in a small sample area in the middle. It relies on the
307b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  // assumption that a video element with null source just presents zeroes.
308b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  function isVideoPlaying(pixels, width, height) {
309b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    // Sample somewhere near the middle of the image.
310b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    var middle = width * height / 2;
311b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    for (var i = 0; i < 20; i++) {
312b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      if (pixels[middle + i] > 0) {
313b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org        return true;
3147fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      }
31564b5c6141a124816290795f80d555eb994edec32pbos@webrtc.org    }
3167fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    return false;
3177fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
3187fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
3197fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
3207fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // This function matches |left| and |right| and throws an exception if the
3217fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  // values don't match.
3227fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function expectEquals(left, right) {
3237fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    if (left != right) {
3247fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      var s = "expectEquals failed left: " + left + " right: " + right;
3257fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      document.title = s;
3267fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      throw s;
3277fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    }
3287fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
3297fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
3307fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function addExpectedEvent() {
3317fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    ++gNumberOfExpectedEvents;
3327fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  }
3337fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org
3347fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  function eventOccured() {
335b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    ++gNumberOfEvents;
336903e746cc9a73da17bfa3f6110293582fa6ee3bestefan@webrtc.org    if (gNumberOfEvents == gNumberOfExpectedEvents) {
337b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      document.title = 'OK';
338b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    }
339b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  }
340b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org  </script>
3417fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org</head>
3427fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org<body>
3437fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org  <table border="0">
3447fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    <tr>
3457fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      <td>Local Preview</td>
3467fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      <td>Remote Stream for Connection 1</td>
3477fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      <td>Remote Stream for Connection 2</td>
3487fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    </tr>
3497fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org    <tr>
3507fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org      <td><video width="320" height="240" id="local-view"
3517fc75bbb65cc1cd99fdf45d9fce44bcce1396dfawu@webrtc.org          autoplay="autoplay"></video></td>
352b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      <td><video width="320" height="240" id="remote-view-1"
353b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          autoplay="autoplay"></video></td>
354b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org      <td><video width="320" height="240" id="remote-view-2"
355b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          autoplay="autoplay"></video></td>
356b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      <!-- Canvases are named after their corresponding video elements. -->
357b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      <td><canvas width="320" height="240" id="remote-view-1-canvas"
358b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          style="display:none"></canvas></td>
359b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org      <td><canvas width="320" height="240" id="remote-view-2-canvas">
360b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org          style="display:none"></canvas></td>
361b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org    </tr>
362b57da6501f9db93536f51f7a64abf27306a7af04pbos@webrtc.org  </table>
363b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org</body>
364b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org</html>
365b015cbede88899f67a53fbbe581b02ce8e32794andrew@webrtc.org