1<!DOCTYPE html> 2<html> 3 <!-- 4 Copyright (c) 2013 The Chromium Authors. All rights reserved. 5 Use of this source code is governed by a BSD-style license that can be 6 found in the LICENSE file. 7 --> 8<head> 9<title>Video Effects Demo</title> 10<style> 11video { 12 border:5px solid black; 13 width:480px; 14 height:360px; 15} 16button { 17 font: 18px sans-serif; 18 padding: 8px; 19} 20textarea { 21 font-family: monospace; 22 margin: 2px; 23 width:480px; 24 height:640px; 25} 26</style> 27</head> 28<body> 29<table> 30<tr> 31<td><video id="vidlocal" autoplay></video></td> 32<td><video id="vidprocessedlocal" autoplay></video></td> 33<td><video id="vidremote" autoplay></video></td> 34</tr> 35<tr> 36<td>Local Media Stream</td> 37<td>Local Media Stream After Effect</td> 38<td>Remote Media Stream</td> 39</tr> 40<tr> 41</table> 42<br> 43<button id="startButton" onclick="start()">Start</button> 44<button id="toggleEffectButton" onclick="toggleEffect()">Enable Effect</button> 45<button id="callButton" onclick="call()">Call</button> 46<button id="hangupButton" onclick="hangup()">Hang Up</button> 47<br> 48<embed id="plugin" type="application/x-ppapi-example-video-effects" 49 width="320" height="240"/> 50 51<script> 52var RTCPeerConnection = webkitRTCPeerConnection; 53var getUserMedia = navigator.webkitGetUserMedia.bind(navigator); 54var attachMediaStream = function(element, stream) { 55 element.src = URL.createObjectURL(stream); 56}; 57var startButton = document.getElementById('startButton'); 58var toggleEffectButton = document.getElementById('toggleEffectButton'); 59var callButton = document.getElementById('callButton'); 60var hangupButton = document.getElementById('hangupButton'); 61 62callButton.disabled = true; 63hangupButton.disabled = true; 64toggleEffectButton.disabled = true; 65var pc1 = null; 66var pc2 = null; 67var localstream = null; 68var processedLocalstream = null; 69var effectsPlugin = null; 70var effectsEnabled = false; 71 72function trace(text) { 73 // This function is used for logging. 74 if (text[text.length - 1] == '\n') { 75 text = text.substring(0, text.length - 1); 76 } 77 console.log((performance.now() / 1000).toFixed(3) + ": " + text); 78} 79 80function gotStream(stream){ 81 trace("Received local stream"); 82 // Call the polyfill wrapper to attach the media stream to this element. 83 attachMediaStream(vidlocal, stream); 84 localstream = stream; 85 callButton.disabled = false; 86 initEffect(); 87} 88 89function start() { 90 trace("Requesting local stream"); 91 startButton.disabled = true; 92 // Call into getUserMedia via the polyfill (adapter.js). 93 getUserMedia({audio:false, video:true}, 94 gotStream, function() {}); 95} 96 97function onRegisterStreamDone() { 98 vidprocessedlocal.src = URL.createObjectURL(processedLocalstream); 99 toggleEffectButton.disabled = false; 100} 101 102function HandleMessage(message_event) { 103 if (message_event.data) { 104 if (message_event.data == 'DoneRegistering') { 105 onRegisterStreamDone(); 106 } else { 107 trace(message_event.data); 108 } 109 } 110} 111 112function initEffect() { 113 var url = URL.createObjectURL(localstream); 114 processedLocalstream = new webkitMediaStream([]); 115 var processedStreamUrl = URL.createObjectURL(processedLocalstream); 116 effectsPlugin.postMessage( 117 'registerStream' + ' ' + url + ' ' + processedStreamUrl); 118} 119 120function toggleEffect() { 121 effectsEnabled = !effectsEnabled; 122 if (effectsEnabled) { 123 toggleEffectButton.innerHTML = 'Disable Effect'; 124 effectsPlugin.postMessage('effectOn'); 125 } else { 126 toggleEffectButton.innerHTML = 'Enable Effect'; 127 effectsPlugin.postMessage('effectOff'); 128 } 129} 130 131function call() { 132 callButton.disabled = true; 133 hangupButton.disabled = false; 134 trace("Starting call"); 135 var servers = null; 136 pc1 = new RTCPeerConnection(servers); 137 trace("Created local peer connection object pc1"); 138 pc1.onicecandidate = iceCallback1; 139 pc2 = new RTCPeerConnection(servers); 140 trace("Created remote peer connection object pc2"); 141 pc2.onicecandidate = iceCallback2; 142 pc2.onaddstream = gotRemoteStream; 143 144 pc1.addStream(processedLocalstream); 145 trace("Adding Local Stream to peer connection"); 146 147 pc1.createOffer(gotDescription1); 148} 149 150function gotDescription1(desc){ 151 pc1.setLocalDescription(desc); 152 trace("Offer from pc1 \n" + desc.sdp); 153 pc2.setRemoteDescription(desc); 154 // Since the "remote" side has no media stream we need 155 // to pass in the right constraints in order for it to 156 // accept the incoming offer of audio and video. 157 var sdpConstraints = {'mandatory': { 158 'OfferToReceiveAudio':true, 159 'OfferToReceiveVideo':true }}; 160 pc2.createAnswer(gotDescription2, null, sdpConstraints); 161} 162 163function gotDescription2(desc){ 164 pc2.setLocalDescription(desc); 165 trace("Answer from pc2 \n" + desc.sdp); 166 pc1.setRemoteDescription(desc); 167} 168 169function hangup() { 170 trace("Ending call"); 171 pc1.close(); 172 pc2.close(); 173 pc1 = null; 174 pc2 = null; 175 hangupButton.disabled = true; 176 callButton.disabled = false; 177} 178 179function gotRemoteStream(e){ 180 vidremote.src = URL.createObjectURL(e.stream); 181 trace("Received remote stream"); 182} 183 184function iceCallback1(event){ 185 if (event.candidate) { 186 pc2.addIceCandidate(new RTCIceCandidate(event.candidate)); 187 trace("Local ICE candidate: \n" + event.candidate.candidate); 188 } 189} 190 191function iceCallback2(event){ 192 if (event.candidate) { 193 pc1.addIceCandidate(new RTCIceCandidate(event.candidate)); 194 trace("Remote ICE candidate: \n " + event.candidate.candidate); 195 } 196} 197 198function InitializePlugin() { 199 effectsPlugin = document.getElementById('plugin'); 200 effectsPlugin.addEventListener('message', HandleMessage, false); 201} 202 203document.addEventListener('DOMContentLoaded', InitializePlugin, false); 204</script> 205</body> 206</html> 207 208 209