| <!DOCTYPE html> |
| <html> |
| <!-- |
| Copyright (c) 2013 The Chromium Authors. All rights reserved. |
| Use of this source code is governed by a BSD-style license that can be |
| found in the LICENSE file. |
| --> |
| <head> |
| <title>Video Effects Demo</title> |
| <style> |
| video { |
| border:5px solid black; |
| width:480px; |
| height:360px; |
| } |
| button { |
| font: 18px sans-serif; |
| padding: 8px; |
| } |
| textarea { |
| font-family: monospace; |
| margin: 2px; |
| width:480px; |
| height:640px; |
| } |
| </style> |
| </head> |
| <body> |
| <table> |
| <tr> |
| <td><video id="vidlocal" autoplay></video></td> |
| <td><video id="vidprocessedlocal" autoplay></video></td> |
| <td><video id="vidremote" autoplay></video></td> |
| </tr> |
| <tr> |
| <td>Local Media Stream</td> |
| <td>Local Media Stream After Effect</td> |
| <td>Remote Media Stream</td> |
| </tr> |
| <tr> |
| </table> |
| <br> |
| <button id="startButton" onclick="start()">Start</button> |
| <button id="toggleEffectButton" onclick="toggleEffect()">Enable Effect</button> |
| <button id="callButton" onclick="call()">Call</button> |
| <button id="hangupButton" onclick="hangup()">Hang Up</button> |
| <br> |
| <embed id="plugin" type="application/x-ppapi-example-video-effects" |
| width="320" height="240"/> |
| |
| <script> |
| var getUserMedia = navigator.webkitGetUserMedia.bind(navigator); |
| var attachMediaStream = function(element, stream) { |
| element.srcObject = stream; |
| }; |
| var startButton = document.getElementById('startButton'); |
| var toggleEffectButton = document.getElementById('toggleEffectButton'); |
| var callButton = document.getElementById('callButton'); |
| var hangupButton = document.getElementById('hangupButton'); |
| |
| callButton.disabled = true; |
| hangupButton.disabled = true; |
| toggleEffectButton.disabled = true; |
| var pc1 = null; |
| var pc2 = null; |
| var localstream = null; |
| var processedLocalstream = null; |
| var effectsPlugin = null; |
| var effectsEnabled = false; |
| |
| function trace(text) { |
| // This function is used for logging. |
| if (text[text.length - 1] == '\n') { |
| text = text.substring(0, text.length - 1); |
| } |
| console.log((performance.now() / 1000).toFixed(3) + ": " + text); |
| } |
| |
| function gotStream(stream){ |
| trace("Received local stream"); |
| // Call the polyfill wrapper to attach the media stream to this element. |
| attachMediaStream(vidlocal, stream); |
| localstream = stream; |
| callButton.disabled = false; |
| initEffect(); |
| } |
| |
| function start() { |
| trace("Requesting local stream"); |
| startButton.disabled = true; |
| // Call into getUserMedia via the polyfill (adapter.js). |
| getUserMedia({audio:false, video:true}, |
| gotStream, function() {}); |
| } |
| |
| function onRegisterStreamDone() { |
| vidprocessedlocal.srcObject = processedLocalstream; |
| toggleEffectButton.disabled = false; |
| } |
| |
| function HandleMessage(message_event) { |
| if (message_event.data) { |
| if (message_event.data == 'DoneRegistering') { |
| onRegisterStreamDone(); |
| } else { |
| trace(message_event.data); |
| } |
| } |
| } |
| |
| function initEffect() { |
| var url = URL.createObjectURL(localstream); |
| processedLocalstream = new MediaStream([]); |
| var processedStreamUrl = URL.createObjectURL(processedLocalstream); |
| effectsPlugin.postMessage( |
| 'registerStream' + ' ' + url + ' ' + processedStreamUrl); |
| } |
| |
| function toggleEffect() { |
| effectsEnabled = !effectsEnabled; |
| if (effectsEnabled) { |
| toggleEffectButton.innerHTML = 'Disable Effect'; |
| effectsPlugin.postMessage('effectOn'); |
| } else { |
| toggleEffectButton.innerHTML = 'Enable Effect'; |
| effectsPlugin.postMessage('effectOff'); |
| } |
| } |
| |
| function call() { |
| callButton.disabled = true; |
| hangupButton.disabled = false; |
| trace("Starting call"); |
| var servers = null; |
| pc1 = new RTCPeerConnection(servers); |
| trace("Created local peer connection object pc1"); |
| pc1.onicecandidate = iceCallback1; |
| pc2 = new RTCPeerConnection(servers); |
| trace("Created remote peer connection object pc2"); |
| pc2.onicecandidate = iceCallback2; |
| pc2.onaddstream = gotRemoteStream; |
| |
| pc1.addStream(processedLocalstream); |
| trace("Adding Local Stream to peer connection"); |
| |
| pc1.createOffer(gotDescription1); |
| } |
| |
| function gotDescription1(desc){ |
| pc1.setLocalDescription(desc); |
| trace("Offer from pc1 \n" + desc.sdp); |
| pc2.setRemoteDescription(desc); |
| // Since the "remote" side has no media stream we need |
| // to pass in the right constraints in order for it to |
| // accept the incoming offer of audio and video. |
| var sdpConstraints = {'mandatory': { |
| 'OfferToReceiveAudio':true, |
| 'OfferToReceiveVideo':true }}; |
| pc2.createAnswer(gotDescription2, null, sdpConstraints); |
| } |
| |
| function gotDescription2(desc){ |
| pc2.setLocalDescription(desc); |
| trace("Answer from pc2 \n" + desc.sdp); |
| pc1.setRemoteDescription(desc); |
| } |
| |
| function hangup() { |
| trace("Ending call"); |
| pc1.close(); |
| pc2.close(); |
| pc1 = null; |
| pc2 = null; |
| hangupButton.disabled = true; |
| callButton.disabled = false; |
| } |
| |
| function gotRemoteStream(e){ |
| vidremote.srcObject = e.stream; |
| trace("Received remote stream"); |
| } |
| |
| function iceCallback1(event){ |
| if (event.candidate) { |
| pc2.addIceCandidate(new RTCIceCandidate(event.candidate)); |
| trace("Local ICE candidate: \n" + event.candidate.candidate); |
| } |
| } |
| |
| function iceCallback2(event){ |
| if (event.candidate) { |
| pc1.addIceCandidate(new RTCIceCandidate(event.candidate)); |
| trace("Remote ICE candidate: \n " + event.candidate.candidate); |
| } |
| } |
| |
| function InitializePlugin() { |
| effectsPlugin = document.getElementById('plugin'); |
| effectsPlugin.addEventListener('message', HandleMessage, false); |
| } |
| |
| document.addEventListener('DOMContentLoaded', InitializePlugin, false); |
| </script> |
| </body> |
| </html> |