diff --git a/webrtc/tools/rtcbot/bot/browser/bot.js b/webrtc/tools/rtcbot/bot/browser/bot.js index 130d006e22..8839802134 100644 --- a/webrtc/tools/rtcbot/bot/browser/bot.js +++ b/webrtc/tools/rtcbot/bot/browser/bot.js @@ -5,23 +5,80 @@ // tree. An additional intellectual property rights grant can be found // in the file PATENTS. All contributing project authors may // be found in the AUTHORS file in the root of the source tree. +// +var localStreams = []; +var remoteStreams = []; -var botExposedApi = { - ping: function (callback) { - callback("pong"); - }, +function ping(callback) { + callback("pong"); +} - createPeerConnection: function (doneCallback) { - console.log("Creating peer connection"); - var pc = new webkitRTCPeerConnection(null); - var obj = {}; - expose(obj, pc, "close"); - expose(obj, pc, "createOffer"); - expose(obj, pc, "createAnswer"); - expose(obj, pc, "setRemoteDescription", { 0: RTCSessionDescription }); - expose(obj, pc, "setLocalDescription", { 0: RTCSessionDescription }); - doneCallback(obj); - }, +function getUserMedia(constraints, onSuccessCallback, onFailCallback){ + console.log("Getting user media."); + navigator.webkitGetUserMedia(constraints, + onSuccessCallbackWraper, onFailCallback); + + function onSuccessCallbackWraper(stream) { + console.log("GetUserMedia success."); + localStreams[stream.id] = stream; + onSuccessCallback(stream); + } +} + +function createPeerConnection(doneCallback, failCallback) { + console.log("Creating peer connection"); + var obj = {}; + var pc = new webkitRTCPeerConnection(null); + + expose(obj, pc, "close"); + expose(obj, pc, "createOffer"); + expose(obj, pc, "createAnswer"); + expose(obj, pc, "addEventListener"); + expose(obj, pc, "addIceCandidate", { 0: RTCIceCandidate}); + expose(obj, pc, "setRemoteDescription", { 0: RTCSessionDescription }); + expose(obj, pc, "setLocalDescription", { 0: RTCSessionDescription }); + + obj.addStream = function(stream) { + console.log("Adding local stream."); + var tempStream = localStreams[stream.id]; + if (!tempStream) { + console.log("Undefined stream!"); + return; + } + pc.addStream(tempStream); + }; + + pc.addEventListener('addstream', function(event) { + remoteStreams[event.stream.id] = event.stream; + }); + + doneCallback(obj); +} + +function showStream(streamId, autoplay, muted) { + var stream = getStreamFromIdentifier_(streamId); + var video = document.createElement('video'); + video.autoplay = autoplay; + video.muted = muted; + document.body.appendChild(video); + video.src = URL.createObjectURL(stream); + console.log("Stream " + stream.id + " attached to video element"); }; -connectToServer(botExposedApi); +function getStreamFromIdentifier_(id) { + var tempStream = localStreams[id]; + if (tempStream) + return tempStream; + tempStream = remoteStreams[id]; + if (tempStream) + return tempStream; + console.log(id + " is not id for stream."); + return null; +} + +connectToServer({ + ping: ping, + getUserMedia: getUserMedia, + createPeerConnection: createPeerConnection, + showStream: showStream, +}); diff --git a/webrtc/tools/rtcbot/test.js b/webrtc/tools/rtcbot/test.js index c1db4fc0eb..f731773979 100644 --- a/webrtc/tools/rtcbot/test.js +++ b/webrtc/tools/rtcbot/test.js @@ -17,10 +17,10 @@ var vm = require('vm'); var BotManager = require('./botmanager.js'); function Test(botType) { - // Make the test fail if not completed in 3 seconds. + // TODO(houssainy) set the time out. this.timeout_ = setTimeout( this.fail.bind(this, "Test timeout!"), - 5000); + 10000); this.botType_ = botType; } @@ -82,4 +82,4 @@ function runTest(testfile) { script.runInNewContext({ test: new Test(process.argv[2]) }); } -runTest("./test/simple_offer_answer.js"); +runTest("./test/webrtc_video_streaming.js"); diff --git a/webrtc/tools/rtcbot/test/webrtc_video_streaming.js b/webrtc/tools/rtcbot/test/webrtc_video_streaming.js new file mode 100644 index 0000000000..a907976384 --- /dev/null +++ b/webrtc/tools/rtcbot/test/webrtc_video_streaming.js @@ -0,0 +1,94 @@ +// Copyright (c) 2014 The WebRTC project authors. All Rights Reserved. +// +// Use of this source code is governed by a BSD-style license +// that can be found in the LICENSE file in the root of the source +// tree. An additional intellectual property rights grant can be found +// in the file PATENTS. All contributing project authors may +// be found in the AUTHORS file in the root of the source tree. +// +// A unidirectional video and audio flowing test from bot 1 to bot 2. +// +// Note: the source of the video and audio stream is getUserMedia(). +// +// TODO(houssainy): get a condition to terminate the test. +// +function testVideoStreaming(bot1, bot2) { + var pc1 = null; + var pc2 = null; + + test.wait([ + createPeerConnection.bind(bot1), + createPeerConnection.bind(bot2) ], + onPeerConnectionCreated); + + function createPeerConnection(done) { + this.createPeerConnection(done, test.fail); + } + + function onPeerConnectionCreated(peer1, peer2) { + test.log("RTC Peers created."); + pc1 = peer1; + pc2 = peer2; + pc1.addEventListener('addstream', test.fail); + pc2.addEventListener('addstream', onAddStream); + pc1.addEventListener('icecandidate', onIceCandidate.bind(pc2)); + pc2.addEventListener('icecandidate', onIceCandidate.bind(pc1)); + + bot1.getUserMedia({video:true, audio:true}, onUserMediaSuccess, test.fail); + + function onUserMediaSuccess(stream) { + test.log("User has granted access to local media."); + pc1.addStream(stream); + bot1.showStream(stream.id, true, true); + + createOfferAndAnswer(); + } + } + + function onAddStream(event) { + test.log("On Add stream."); + bot2.showStream(event.stream.id, true, false); + } + + function onIceCandidate(event) { + if(event.candidate){ + test.log(event.candidate.candidate); + this.addIceCandidate(event.candidate, + onAddIceCandidateSuccess, test.fail); + }; + + function onAddIceCandidateSuccess() { + test.log("Candidate added successfully"); + }; + } + + function createOfferAndAnswer() { + test.log("Creating offer."); + pc1.createOffer(gotOffer, test.fail); + + function gotOffer(offer) { + test.log("Got offer"); + pc1.setLocalDescription(offer, onSetSessionDescriptionSuccess, test.fail); + pc2.setRemoteDescription(offer, onSetSessionDescriptionSuccess, + test.fail); + test.log("Creating answer"); + pc2.createAnswer(gotAnswer, test.fail); + } + + function gotAnswer(answer) { + test.log("Got answer"); + pc2.setLocalDescription(answer, onSetSessionDescriptionSuccess, + test.fail); + pc1.setRemoteDescription(answer, onSetSessionDescriptionSuccess, + test.fail); + } + + function onSetSessionDescriptionSuccess() { + test.log("Set session description success."); + } + } +} + +test.wait( [ test.spawnBot.bind(test, "alice"), + test.spawnBot.bind(test, "bob") ], + testVideoStreaming);