Browse Source

Added seek and volume support, check origins in postMessage receivers.

pull/195/head
Joachim Bauch 10 years ago
parent
commit
c8ad76005b
  1. 89
      static/js/directives/youtubevideo.js
  2. 82
      static/partials/youtubevideo_sandbox.html

89
static/js/directives/youtubevideo.js

@ -26,9 +26,13 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
var YOUTUBE_IFRAME_API_URL = "//www.youtube.com/iframe_api"; var YOUTUBE_IFRAME_API_URL = "//www.youtube.com/iframe_api";
var origin = $window.location.protocol + "//" + $window.location.host;
var Sandbox = function(iframe) { var Sandbox = function(iframe) {
this.iframe = iframe; this.iframe = iframe;
this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(sandboxTemplate); var template = sandboxTemplate;
template = template.replace(/__PARENT__ORIGIN__/g, origin);
this.iframe.src = "data:text/html;charset=utf-8," + encodeURI(template);
this.target = this.iframe.contentWindow; this.target = this.iframe.contentWindow;
}; };
@ -75,21 +79,28 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
this.sandbox.postMessage("seekTo", msg); this.sandbox.postMessage("seekTo", msg);
}; };
SandboxPlayer.prototype.setVolume = function(volume) {
this.sandbox.postMessage("setVolume", {"volume": volume});
};
SandboxPlayer.prototype.getCurrentTime = function() { SandboxPlayer.prototype.getCurrentTime = function() {
// TODO(fancycode): implement me // TODO(fancycode): implement me
return 0; return 0;
}; };
SandboxPlayer.prototype.getPlayerState = function() {
// TODO(fancycode): implement me
return null;
}
var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) { var controller = ['$scope', '$element', '$attrs', function($scope, $element, $attrs) {
var addedIframeScript = false; var addedIframeScript = false;
var player = null; var player = null;
var playerReady = null; var playerReady = null;
var isPaused = null; var isPaused = null;
var seekDetector = null;
var playReceivedNow = null; var playReceivedNow = null;
var prevTime = null;
var prevNow = null;
var initialState = null; var initialState = null;
var sandbox = new Sandbox($("#youtubeplayer", $element)[0]); var sandbox = new Sandbox($("#youtubeplayer", $element)[0]);
@ -98,6 +109,10 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
var isYouTubeIframeAPIReady = isYouTubeIframeAPIReadyDefer.promise; var isYouTubeIframeAPIReady = isYouTubeIframeAPIReadyDefer.promise;
var onPostMessage = function(event) { var onPostMessage = function(event) {
if (event.origin !== "null" || event.source !== sandbox.target) {
// the sandboxed data-url iframe has "null" as origin
return;
}
var msg = event.data; var msg = event.data;
var data = msg[msg.type] || {}; var data = msg[msg.type] || {};
switch (msg.type) { switch (msg.type) {
@ -119,8 +134,8 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
break; break;
case "youtube.event": case "youtube.event":
$scope.$apply(function(scope) { $scope.$apply(function(scope) {
console.log("State change", data.event); console.log("State change", data);
scope.$emit(data.event); scope.$emit(data.event, data.position);
}); });
break; break;
default: default:
@ -190,82 +205,34 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
return null; return null;
} }
var startDetectSeek = function() { $scope.$on("youtube.playing", function(event, position) {
// TODO(fancycode): seek detection should be implemented in the sandbox
/*
var checkSeek = function() {
if (!player) {
return;
}
var now = new Date();
var time = player.getCurrentTime();
if (prevTime === null) {
prevTime = time;
}
if (prevNow === null) {
prevNow = now;
}
var deltaTime = Math.abs(time - prevTime);
var deltaNow = (now - prevNow) * 0.001;
if (deltaTime > deltaNow * 1.1) {
safeApply($scope, function(scope) {
scope.$emit("youtube.seeked", time);
});
}
prevNow = now;
prevTime = time;
};
if (!seekDetector) {
seekDetector = $window.setInterval(function() {
checkSeek();
}, 1000);
}
checkSeek();
*/
};
var stopDetectSeek = function() {
if (seekDetector) {
$window.clearInterval(seekDetector);
seekDetector = null;
}
prevNow = null;
};
$scope.$on("youtube.playing", function() {
if (initialState === 2) { if (initialState === 2) {
initialState = null; initialState = null;
player.pauseVideo(); player.pauseVideo();
return; return;
} }
prevTime = null;
startDetectSeek();
if (isPaused) { if (isPaused) {
isPaused = false; isPaused = false;
mediaStream.webrtc.callForEachCall(function(peercall) { mediaStream.webrtc.callForEachCall(function(peercall) {
mediaStreamSendYouTubeVideo(peercall, currentToken, { mediaStreamSendYouTubeVideo(peercall, currentToken, {
Type: "Resume", Type: "Resume",
Resume: { Resume: {
position: player.getCurrentTime() position: position
} }
}); });
}); });
} }
}); });
$scope.$on("youtube.buffering", function() { $scope.$on("youtube.buffering", function(event, position) {
if (initialState === 2) { if (initialState === 2) {
initialState = null; initialState = null;
player.pauseVideo(); player.pauseVideo();
} }
startDetectSeek();
}); });
$scope.$on("youtube.paused", function() { $scope.$on("youtube.paused", function(event, position) {
stopDetectSeek();
if (!$scope.isPublisher || !currentToken) { if (!$scope.isPublisher || !currentToken) {
return; return;
} }
@ -276,7 +243,7 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
mediaStreamSendYouTubeVideo(peercall, currentToken, { mediaStreamSendYouTubeVideo(peercall, currentToken, {
Type: "Pause", Type: "Pause",
Pause: { Pause: {
position: player.getCurrentTime() position: position
} }
}); });
}); });
@ -284,7 +251,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
}); });
$scope.$on("youtube.ended", function() { $scope.$on("youtube.ended", function() {
stopDetectSeek();
}); });
$scope.$on("youtube.seeked", function($event, position) { $scope.$on("youtube.seeked", function($event, position) {
@ -306,8 +272,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
playerReady.done(function() { playerReady.done(function() {
$("#youtubeplayer").show(); $("#youtubeplayer").show();
$scope.playbackActive = true; $scope.playbackActive = true;
prevTime = null;
prevNow = null;
isPaused = null; isPaused = null;
if (playReceivedNow) { if (playReceivedNow) {
var delta = ((new Date()) - playReceivedNow) * 0.001; var delta = ((new Date()) - playReceivedNow) * 0.001;
@ -585,7 +549,6 @@ define(['jquery', 'underscore', 'text!partials/youtubevideo.html', 'text!partial
$scope.currentVideoUrl = null; $scope.currentVideoUrl = null;
$scope.currentVideoId = null; $scope.currentVideoId = null;
peers = {}; peers = {};
stopDetectSeek();
playerReady = null; playerReady = null;
initialState = null; initialState = null;
mediaStream.webrtc.e.off("statechange", updater); mediaStream.webrtc.e.off("statechange", updater);

82
static/partials/youtubevideo_sandbox.html

@ -24,17 +24,22 @@
<script> <script>
(function () { (function () {
var PARENT_ORIGIN = "__PARENT__ORIGIN__"; // will get replaced with real origin
var YouTubeSandbox = function(window) { var YouTubeSandbox = function(window) {
this.head = document.getElementsByTagName('head')[0]; this.head = document.getElementsByTagName('head')[0];
this.window = window; this.window = window;
this.addedIframeScript = false; this.addedIframeScript = false;
this.player = null; this.player = null;
this.seekDetector = null;
this.prevTime = null;
this.prevNow = null;
}; };
YouTubeSandbox.prototype.postMessage = function(type, message) { YouTubeSandbox.prototype.postMessage = function(type, message) {
var msg = {"type": type}; var msg = {"type": type};
msg[type] = message; msg[type] = message;
this.window.parent.postMessage(msg, "*"); this.window.parent.postMessage(msg, PARENT_ORIGIN);
}; };
YouTubeSandbox.prototype.onYouTubeIframeAPIReady = function() { YouTubeSandbox.prototype.onYouTubeIframeAPIReady = function() {
@ -87,7 +92,23 @@
return; return;
} }
that.postMessage("youtube.event", {"event": msg}); switch (msg) {
case "youtube.playing":
that.prevTime = null;
that.startDetectSeek();
break;
case "youtube.buffering":
that.startDetectSeek();
break;
case "youtube.paused":
that.stopDetectSeek();
break;
case "youtube.ended":
that.stopDetectSeek();
break;
}
that.postMessage("youtube.event", {"event": msg, "position": that.player.getCurrentTime()});
} }
} }
}); });
@ -95,6 +116,7 @@
}; };
YouTubeSandbox.prototype.destroyPlayer = function() { YouTubeSandbox.prototype.destroyPlayer = function() {
this.stopDetectSeek();
if (this.player) { if (this.player) {
this.player.destroy(); this.player.destroy();
this.player = null; this.player = null;
@ -102,6 +124,8 @@
}; };
YouTubeSandbox.prototype.loadVideo = function(id, position) { YouTubeSandbox.prototype.loadVideo = function(id, position) {
this.prevTime = null;
this.prevNow = null;
if (typeof(position) !== "undefined") { if (typeof(position) !== "undefined") {
this.player.loadVideoById(id, position); this.player.loadVideoById(id, position);
} else { } else {
@ -125,10 +149,53 @@
if (typeof(allowSeekAhead) !== "undefined") { if (typeof(allowSeekAhead) !== "undefined") {
this.player.seekTo(position, allowSeekAhead); this.player.seekTo(position, allowSeekAhead);
} else { } else {
this.player.seekTo(positio); this.player.seekTo(position);
} }
}; };
YouTubeSandbox.prototype.setVolume = function(volume) {
this.player.setVolume(volume);
};
YouTubeSandbox.prototype.startDetectSeek = function() {
var that = this;
var checkSeek = function() {
if (!that.player) {
return;
}
var now = new Date();
var time = that.player.getCurrentTime();
if (that.prevTime === null) {
that.prevTime = time;
}
if (that.prevNow === null) {
that.prevNow = now;
}
var deltaTime = Math.abs(time - that.prevTime);
var deltaNow = (now - that.prevNow) * 0.001;
if (deltaTime > deltaNow * 1.1) {
that.postMessage("youtube.event", {"event": "youtube.seeked", "position": time});
}
that.prevNow = now;
that.prevTime = time;
};
if (!this.seekDetector) {
this.seekDetector = this.window.setInterval(function() {
checkSeek();
}, 1000);
}
checkSeek();
};
YouTubeSandbox.prototype.stopDetectSeek = function() {
if (this.seekDetector) {
this.window.clearInterval(this.seekDetector);
this.seekDetector = null;
}
this.prevNow = null;
};
var sandbox = new YouTubeSandbox(window); var sandbox = new YouTubeSandbox(window);
window.onYouTubeIframeAPIReady = function() { window.onYouTubeIframeAPIReady = function() {
@ -136,6 +203,10 @@
}; };
window.addEventListener("message", function(event) { window.addEventListener("message", function(event) {
if (event.origin !== PARENT_ORIGIN) {
// only accept messages from spreed-webrtc
return;
}
var msg = event.data; var msg = event.data;
var data = msg[msg.type] || {}; var data = msg[msg.type] || {};
switch (msg.type) { switch (msg.type) {
@ -163,8 +234,11 @@
case "seekTo": case "seekTo":
sandbox.seekTo(data.position, data.allowSeekAhead); sandbox.seekTo(data.position, data.allowSeekAhead);
break; break;
case "setVolume":
sandbox.setVolume(data.volume);
break;
default: default:
// ignore unknown messages (e.g. received from YT player) console.log("Unknown message received", event);
break; break;
} }
}, false); }, false);

Loading…
Cancel
Save