|  | <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd"> | 
|  |  | 
|  | <!-- | 
|  | To quickly iterate when developing this test, make sure you select | 
|  | 'Always allow this site to use this webcam' option in the dropdown menu of | 
|  | Chrome when it's requesting access to your webcam. | 
|  | Notice that this requires the site you're browsing to use HTTPS. | 
|  |  | 
|  | Without that, the test might timeout before you have had the chance to accept | 
|  | access to the webcam. | 
|  | --> | 
|  |  | 
|  | <html> | 
|  | <head> | 
|  | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> | 
|  | <title>PeerConnection Connection Test</title> | 
|  |  | 
|  | <script src="https://w3c-test.org/resources/testharness.js"></script> | 
|  |  | 
|  | <script type="text/javascript"> | 
|  | var test = async_test('Can set up a basic WebRTC call.', {timeout: 5000}); | 
|  | var gFirstConnection = null; | 
|  | var gSecondConnection = null; | 
|  |  | 
|  | function getUserMediaOkCallback(localStream) { | 
|  | gFirstConnection = new webkitRTCPeerConnection(null, null); | 
|  | gFirstConnection.onicecandidate = onIceCandidateToFirst; | 
|  | gFirstConnection.addStream(localStream); | 
|  | gFirstConnection.createOffer(onOfferCreated); | 
|  |  | 
|  | var videoTag = document.getElementById('local-view'); | 
|  | videoTag.src = webkitURL.createObjectURL(localStream); | 
|  | }; | 
|  |  | 
|  | var onOfferCreated = test.step_func(function(offer) { | 
|  | gFirstConnection.setLocalDescription(offer); | 
|  |  | 
|  | // This would normally go across the application's signaling solution. | 
|  | // In our case, the "signaling" is to call this function. | 
|  | receiveCall(offer.sdp); | 
|  | }); | 
|  |  | 
|  | function receiveCall(offerSdp) { | 
|  | gSecondConnection = new webkitRTCPeerConnection(null, null); | 
|  | gSecondConnection.onicecandidate = onIceCandidateToSecond; | 
|  | gSecondConnection.onaddstream = onRemoteStream; | 
|  |  | 
|  | var parsedOffer = new RTCSessionDescription({ type: 'offer', | 
|  | sdp: offerSdp }); | 
|  | gSecondConnection.setRemoteDescription(parsedOffer); | 
|  |  | 
|  | gSecondConnection.createAnswer(onAnswerCreated, | 
|  | failed('createAnswer')); | 
|  | }; | 
|  |  | 
|  | var onAnswerCreated = test.step_func(function(answer) { | 
|  | gSecondConnection.setLocalDescription(answer); | 
|  |  | 
|  | // Similarly, this would go over the application's signaling solution. | 
|  | handleAnswer(answer.sdp); | 
|  | }); | 
|  |  | 
|  | function handleAnswer(answerSdp) { | 
|  | var parsedAnswer = new RTCSessionDescription({ type: 'answer', | 
|  | sdp: answerSdp }); | 
|  | gFirstConnection.setRemoteDescription(parsedAnswer); | 
|  |  | 
|  | // Call negotiated: done. | 
|  | test.done(); | 
|  | }; | 
|  |  | 
|  | // Note: the ice candidate handlers are special. We can not wrap them in test | 
|  | // steps since that seems to cause some kind of starvation that prevents the | 
|  | // call of being set up. Unfortunately we cannot report errors in here. | 
|  | var onIceCandidateToFirst = function(event) { | 
|  | // If event.candidate is null = no more candidates. | 
|  | if (event.candidate) { | 
|  | var candidate = new RTCIceCandidate(event.candidate); | 
|  | gSecondConnection.addIceCandidate(candidate); | 
|  | } | 
|  | }; | 
|  |  | 
|  | var onIceCandidateToSecond = function(event) { | 
|  | if (event.candidate) { | 
|  | var candidate = new RTCIceCandidate(event.candidate); | 
|  | gFirstConnection.addIceCandidate(candidate); | 
|  | } | 
|  | }; | 
|  |  | 
|  | var onRemoteStream = test.step_func(function(event) { | 
|  | var videoTag = document.getElementById('remote-view'); | 
|  | videoTag.src = webkitURL.createObjectURL(event.stream); | 
|  | }); | 
|  |  | 
|  | // Returns a suitable error callback. | 
|  | function failed(function_name) { | 
|  | return test.step_func(function() { | 
|  | assert_unreached('WebRTC called error callback for ' + function_name); | 
|  | }); | 
|  | } | 
|  |  | 
|  | // This function starts the test. | 
|  | test.step(function() { | 
|  | navigator.webkitGetUserMedia({ video: true, audio: true }, | 
|  | getUserMediaOkCallback, | 
|  | failed('getUserMedia')); | 
|  | }); | 
|  | </script> | 
|  | </head> | 
|  |  | 
|  | <body> | 
|  |  | 
|  | <div> | 
|  | <video width="320" height="240" id="remote-view" autoplay="autoplay"></video> | 
|  | <video width="320" height="240" id="local-view" autoplay="autoplay"></video> | 
|  | </div> | 
|  | <div id="log"></div> | 
|  | </body> | 
|  | </html> |