aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRblSb <msrblsb@gmail.com>2020-04-03 04:48:36 +0300
committerRblSb <msrblsb@gmail.com>2020-04-03 04:48:36 +0300
commit5f2a3b89eaa1199d9bc2ddd10622f9803cec983f (patch)
treeee9064ee7b683cfe2ac7b504ba81674b490367b6
parent62c9be74228549ff888b684a62f77fb056571470 (diff)
Sync playback rate
-rw-r--r--.vscode/tasks.json21
-rw-r--r--build-server.hxml1
-rw-r--r--build/server.js47
-rw-r--r--res/client.js66
-rw-r--r--src/Types.hx7
-rw-r--r--src/client/IPlayer.hx2
-rw-r--r--src/client/Main.hx11
-rw-r--r--src/client/Player.hx26
-rw-r--r--src/client/players/Iframe.hx6
-rw-r--r--src/client/players/Raw.hx9
-rw-r--r--src/client/players/Youtube.hx13
-rw-r--r--src/server/Main.hx21
-rw-r--r--src/server/VideoTimer.hx36
-rw-r--r--test/Main.hx15
-rw-r--r--test/tests/TestTimer.hx163
-rw-r--r--tests.hxml6
16 files changed, 436 insertions, 14 deletions
diff --git a/.vscode/tasks.json b/.vscode/tasks.json
index f68272e..0b315f6 100644
--- a/.vscode/tasks.json
+++ b/.vscode/tasks.json
@@ -16,6 +16,27 @@
"group": {
"kind": "build",
"isDefault": true
+ },
+ "presentation": {
+ "clear": true
+ }
+ },
+ {
+ "label": "Run tests",
+ "type": "hxml",
+ "file": "tests.hxml",
+ "problemMatcher": [
+ "$haxe-absolute",
+ "$haxe",
+ "$haxe-error",
+ "$haxe-trace"
+ ],
+ "group": {
+ "kind": "test",
+ "isDefault": true
+ },
+ "presentation": {
+ "clear": true
}
}
]
diff --git a/build-server.hxml b/build-server.hxml
index 5f181aa..49def02 100644
--- a/build-server.hxml
+++ b/build-server.hxml
@@ -2,6 +2,7 @@
-lib hxnodejs-ws
# Client libs for completion
-lib youtubeIFramePlayer:git:https://github.com/okawa-h/youtubeIFramePlayer-externs.git
+-lib utest
-cp src
--main server.Main
-D analyzer-optimize
diff --git a/build/server.js b/build/server.js
index 5641bd5..5077240 100644
--- a/build/server.js
+++ b/build/server.js
@@ -1393,7 +1393,17 @@ server_Main.prototype = {
this.onMessage(client,{ type : "SkipVideo", skipVideo : { url : this.videoList[this.itemPos].url}});
return;
}
- this.send(client,{ type : "GetTime", getTime : { time : this.videoTimer.getTime(), paused : this.videoTimer.isPaused()}});
+ var obj = { type : "GetTime", getTime : { time : this.videoTimer.getTime()}};
+ if(this.videoTimer.isPaused()) {
+ obj.getTime.paused = true;
+ }
+ if(this.videoTimer.getRate() != 1) {
+ if(!ClientTools.hasLeader(this.clients)) {
+ this.videoTimer.setRate(1);
+ }
+ obj.getTime.rate = this.videoTimer.getRate();
+ }
+ this.send(client,obj);
break;
case "Login":
var name = data.login.clientName;
@@ -1551,6 +1561,7 @@ server_Main.prototype = {
if(this.videoTimer.isPaused()) {
this.videoTimer.play();
}
+ this.videoTimer.setRate(1);
this.broadcast({ type : "Play", play : { time : this.videoTimer.getTime()}});
}
break;
@@ -1565,6 +1576,16 @@ server_Main.prototype = {
_$VideoList_VideoList_$Impl_$.setNextItem(this.videoList,pos,this.itemPos);
this.broadcast(data);
break;
+ case "SetRate":
+ if(this.videoList.length == 0) {
+ return;
+ }
+ if((client.group & 2) == 0) {
+ return;
+ }
+ this.videoTimer.setRate(data.setRate.rate);
+ this.broadcastExcept(client,data);
+ break;
case "SetTime":
if(this.videoList.length == 0) {
return;
@@ -1775,6 +1796,8 @@ server_Utils.shuffle = function(arr) {
}
};
var server_VideoTimer = function() {
+ this.rate = 1.0;
+ this.rateStartTime = 0.0;
this.pauseStartTime = 0.0;
this.startTime = 0.0;
this.isStarted = false;
@@ -1785,6 +1808,7 @@ server_VideoTimer.prototype = {
this.isStarted = true;
this.startTime = Date.now() / 1000;
this.pauseStartTime = 0;
+ this.rateStartTime = Date.now() / 1000;
}
,stop: function() {
this.isStarted = false;
@@ -1792,20 +1816,23 @@ server_VideoTimer.prototype = {
this.pauseStartTime = 0;
}
,pause: function() {
+ this.startTime += this.rateTime() - this.rateTime() * this.rate;
this.pauseStartTime = Date.now() / 1000;
+ this.rateStartTime = 0;
}
,play: function() {
if(!this.isStarted) {
this.start();
}
this.startTime += this.pauseTime();
+ this.rateStartTime = Date.now() / 1000;
this.pauseStartTime = 0;
}
,getTime: function() {
if(this.startTime == 0) {
return 0;
}
- return Date.now() / 1000 - this.startTime - this.pauseTime();
+ return Date.now() / 1000 - this.startTime - this.rateTime() + this.rateTime() * this.rate - this.pauseTime();
}
,setTime: function(secs) {
this.startTime = Date.now() / 1000 - secs;
@@ -1820,12 +1847,28 @@ server_VideoTimer.prototype = {
return true;
}
}
+ ,getRate: function() {
+ return this.rate;
+ }
+ ,setRate: function(rate) {
+ if(!this.isPaused()) {
+ this.startTime += this.rateTime() - this.rateTime() * this.rate;
+ this.rateStartTime = Date.now() / 1000;
+ }
+ this.rate = rate;
+ }
,pauseTime: function() {
if(this.pauseStartTime == 0) {
return 0;
}
return Date.now() / 1000 - this.pauseStartTime;
}
+ ,rateTime: function() {
+ if(this.rateStartTime == 0) {
+ return 0;
+ }
+ return Date.now() / 1000 - this.rateStartTime - this.pauseTime();
+ }
};
var sys_FileSystem = function() { };
sys_FileSystem.__name__ = true;
diff --git a/res/client.js b/res/client.js
index 0611166..6519d6c 100644
--- a/res/client.js
+++ b/res/client.js
@@ -1091,6 +1091,15 @@ client_Main.prototype = {
this.onTimeGet.run();
break;
case "GetTime":
+ if(data.getTime.paused == null) {
+ data.getTime.paused = false;
+ }
+ if(data.getTime.rate == null) {
+ data.getTime.rate = 1;
+ }
+ if(this.player.getPlaybackRate() != data.getTime.rate) {
+ this.player.setPlaybackRate(data.getTime.rate);
+ }
var newTime = data.getTime.time;
var time = this.player.getTime();
if((this.personal.group & 1 << ClientGroup.Leader._hx_index) != 0) {
@@ -1175,6 +1184,12 @@ client_Main.prototype = {
case "SetNextItem":
this.player.setNextItem(data.setNextItem.pos);
break;
+ case "SetRate":
+ if((this.personal.group & 1 << ClientGroup.Leader._hx_index) != 0) {
+ return;
+ }
+ this.player.setPlaybackRate(data.setRate.rate);
+ break;
case "SetTime":
var newTime1 = data.setTime.time;
var time1 = this.player.getTime();
@@ -1543,6 +1558,7 @@ client_MobileView.init = function() {
};
};
var client_Player = function(main) {
+ this.skipSetRate = false;
this.skipSetTime = false;
this.isLoaded = false;
this.itemPos = 0;
@@ -1653,6 +1669,16 @@ client_Player.prototype = {
}
this.main.send({ type : "SetTime", setTime : { time : this.getTime()}});
}
+ ,onRateChange: function() {
+ if(this.skipSetRate) {
+ this.skipSetRate = false;
+ return;
+ }
+ if((this.main.personal.group & 2) == 0) {
+ return;
+ }
+ this.main.send({ type : "SetRate", setRate : { rate : this.getPlaybackRate()}});
+ }
,addVideoItem: function(item,atEnd) {
var url = StringTools.htmlEscape(item.url,true);
var itemEl = this.nodeFromString("<li class=\"queue_entry pluid-0\" title=\"" + Lang.get("addedBy") + ": " + item.author + "\">\n\t\t\t\t<a class=\"qe_title\" href=\"" + url + "\" target=\"_blank\">" + StringTools.htmlEscape(item.title) + "</a>\n\t\t\t\t<span class=\"qe_time\">" + this.duration(item.duration) + "</span>\n\t\t\t\t<div class=\"qe_clear\"></div>\n\t\t\t\t<div class=\"btn-group\">\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-play\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-play\"></span>" + Lang.get("play") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-next\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-share-alt\"></span>" + Lang.get("setNext") + "\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-tmp\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-flag\"></span>\n\t\t\t\t\t</button>\n\t\t\t\t\t<button class=\"btn btn-xs btn-default qbtn-delete\">\n\t\t\t\t\t\t<span class=\"glyphicon glyphicon-trash\"></span>" + Lang.get("delete") + "\n\t\t\t\t\t</button>\n\t\t\t\t</div>\n\t\t\t</li>");
@@ -1833,6 +1859,25 @@ client_Player.prototype = {
this.skipSetTime = isLocal;
this.player.setTime(time);
}
+ ,getPlaybackRate: function() {
+ if(this.player == null) {
+ return 1;
+ }
+ return this.player.getPlaybackRate();
+ }
+ ,setPlaybackRate: function(rate,isLocal) {
+ if(isLocal == null) {
+ isLocal = true;
+ }
+ if(!this.main.isSyncActive) {
+ return;
+ }
+ if(this.player == null) {
+ return;
+ }
+ this.skipSetRate = isLocal;
+ this.player.setPlaybackRate(rate);
+ }
};
var client_Settings = function() { };
client_Settings.__name__ = true;
@@ -1982,6 +2027,11 @@ client_players_Iframe.prototype = {
}
,setTime: function(time) {
}
+ ,getPlaybackRate: function() {
+ return 1;
+ }
+ ,setPlaybackRate: function(rate) {
+ }
};
var client_players_Raw = function(main,player) {
this.playAllowed = true;
@@ -2047,6 +2097,7 @@ client_players_Raw.prototype = {
return;
};
this.video.onpause = ($_=this.player,$bind($_,$_.onPause));
+ this.video.onratechange = ($_=this.player,$bind($_,$_.onRateChange));
this.playerEl.appendChild(this.video);
}
,removeVideo: function() {
@@ -2090,6 +2141,12 @@ client_players_Raw.prototype = {
}
this.video.currentTime = time;
}
+ ,getPlaybackRate: function() {
+ return this.video.playbackRate;
+ }
+ ,setPlaybackRate: function(rate) {
+ this.video.playbackRate = rate;
+ }
};
var client_players_Youtube = function(main,player) {
this.matchSeconds = new EReg("([0-9]+)S","");
@@ -2282,6 +2339,9 @@ client_players_Youtube.prototype = {
break;
}
return;
+ }, onPlaybackRateChange : function(e2) {
+ _gthis.player.onRateChange();
+ return;
}}});
}
,removeVideo: function() {
@@ -2317,6 +2377,12 @@ client_players_Youtube.prototype = {
}
this.youtube.seekTo(time,true);
}
+ ,getPlaybackRate: function() {
+ return this.youtube.getPlaybackRate();
+ }
+ ,setPlaybackRate: function(rate) {
+ this.youtube.setPlaybackRate(rate);
+ }
};
var haxe_Log = function() { };
haxe_Log.__name__ = true;
diff --git a/src/Types.hx b/src/Types.hx
index 2501cc4..366b2ed 100644
--- a/src/Types.hx
+++ b/src/Types.hx
@@ -134,11 +134,15 @@ typedef WsEvent = {
},
?getTime:{
time:Float,
- paused:Bool
+ ?paused:Bool,
+ ?rate:Float
},
?setTime:{
time:Float
},
+ ?setRate:{
+ rate:Float
+ },
?rewind:{
time:Float
},
@@ -181,6 +185,7 @@ enum abstract WsEventType(String) {
var Play;
var GetTime;
var SetTime;
+ var SetRate;
var Rewind;
var SetLeader;
var PlayItem;
diff --git a/src/client/IPlayer.hx b/src/client/IPlayer.hx
index 4f29512..e414af5 100644
--- a/src/client/IPlayer.hx
+++ b/src/client/IPlayer.hx
@@ -11,4 +11,6 @@ interface IPlayer {
function pause():Void;
function getTime():Float;
function setTime(time:Float):Void;
+ function getPlaybackRate():Float;
+ function setPlaybackRate(rate:Float):Void;
}
diff --git a/src/client/Main.hx b/src/client/Main.hx
index f65640a..780f005 100644
--- a/src/client/Main.hx
+++ b/src/client/Main.hx
@@ -366,6 +366,13 @@ class Main {
player.play();
case GetTime:
+ if (data.getTime.paused == null) data.getTime.paused = false;
+ if (data.getTime.rate == null) data.getTime.rate = 1;
+
+ if (player.getPlaybackRate() != data.getTime.rate) {
+ player.setPlaybackRate(data.getTime.rate);
+ }
+
final newTime = data.getTime.time;
final time = player.getTime();
if (isLeader()) {
@@ -386,6 +393,10 @@ class Main {
if (Math.abs(time - newTime) < synchThreshold) return;
player.setTime(newTime);
+ case SetRate:
+ if (isLeader()) return;
+ player.setPlaybackRate(data.setRate.rate);
+
case Rewind:
player.setTime(data.rewind.time);
diff --git a/src/client/Player.hx b/src/client/Player.hx
index 8e55b25..53a1168 100644
--- a/src/client/Player.hx
+++ b/src/client/Player.hx
@@ -21,6 +21,7 @@ class Player {
var itemPos = 0;
var isLoaded = false;
var skipSetTime = false;
+ var skipSetRate = false;
public function new(main:Main):Void {
this.main = main;
@@ -158,6 +159,19 @@ class Player {
});
}
+ public function onRateChange():Void {
+ if (skipSetRate) {
+ skipSetRate = false;
+ return;
+ }
+ if (!main.isLeader()) return;
+ main.send({
+ type: SetRate, setRate: {
+ rate: getPlaybackRate()
+ }
+ });
+ }
+
public function addVideoItem(item:VideoItem, atEnd:Bool):Void {
final url = item.url.htmlEscape(true);
final itemEl = nodeFromString(
@@ -322,4 +336,16 @@ class Player {
player.setTime(time);
}
+ public function getPlaybackRate():Float {
+ if (player == null) return 1;
+ return player.getPlaybackRate();
+ }
+
+ public function setPlaybackRate(rate:Float, isLocal = true):Void {
+ if (!main.isSyncActive) return;
+ if (player == null) return;
+ skipSetRate = isLocal;
+ player.setPlaybackRate(rate);
+ }
+
}
diff --git a/src/client/players/Iframe.hx b/src/client/players/Iframe.hx
index f0a04c5..d79196b 100644
--- a/src/client/players/Iframe.hx
+++ b/src/client/players/Iframe.hx
@@ -59,4 +59,10 @@ class Iframe implements IPlayer {
public function setTime(time:Float):Void {}
+ public function getPlaybackRate():Float {
+ return 1;
+ }
+
+ public function setPlaybackRate(rate:Float):Void {}
+
}
diff --git a/src/client/players/Raw.hx b/src/client/players/Raw.hx
index c7fa980..cd01a42 100644
--- a/src/client/players/Raw.hx
+++ b/src/client/players/Raw.hx
@@ -67,6 +67,7 @@ class Raw implements IPlayer {
player.onPlay();
}
video.onpause = player.onPause;
+ video.onratechange = player.onRateChange;
playerEl.appendChild(video);
}
@@ -102,4 +103,12 @@ class Raw implements IPlayer {
video.currentTime = time;
}
+ public function getPlaybackRate():Float {
+ return video.playbackRate;
+ }
+
+ public function setPlaybackRate(rate:Float):Void {
+ video.playbackRate = rate;
+ }
+
}
diff --git a/src/client/players/Youtube.hx b/src/client/players/Youtube.hx
index f582ba7..eff407e 100644
--- a/src/client/players/Youtube.hx
+++ b/src/client/players/Youtube.hx
@@ -208,7 +208,10 @@ class Youtube implements IPlayer {
player.onSetTime();
case CUED:
}
- }
+ },
+ onPlaybackRateChange: e -> {
+ player.onRateChange();
+ },
}
});
}
@@ -239,4 +242,12 @@ class Youtube implements IPlayer {
youtube.seekTo(time, true);
}
+ public function getPlaybackRate():Float {
+ return youtube.getPlaybackRate();
+ }
+
+ public function setPlaybackRate(rate:Float):Void {
+ youtube.setPlaybackRate(rate);
+ }
+
}
diff --git a/src/server/Main.hx b/src/server/Main.hx
index f056ac6..5142f48 100644
--- a/src/server/Main.hx
+++ b/src/server/Main.hx
@@ -438,11 +438,17 @@ class Main {
});
return;
}
- send(client, {
+ final obj:WsEvent = {
type: GetTime, getTime: {
- time: videoTimer.getTime(),
- paused: videoTimer.isPaused()
- }});
+ time: videoTimer.getTime()
+ }
+ };
+ if (videoTimer.isPaused()) obj.getTime.paused = true;
+ if (videoTimer.getRate() != 1) {
+ if (!clients.hasLeader()) videoTimer.setRate(1);
+ obj.getTime.rate = videoTimer.getRate();
+ }
+ send(client, obj);
case SetTime:
if (videoList.length == 0) return;
@@ -450,6 +456,12 @@ class Main {
videoTimer.setTime(data.setTime.time);
broadcastExcept(client, data);
+ case SetRate:
+ if (videoList.length == 0) return;
+ if (!client.isLeader) return;
+ videoTimer.setRate(data.setRate.rate);
+ broadcastExcept(client, data);
+
case Rewind:
if (!checkPermission(client, RewindPerm)) return;
if (videoList.length == 0) return;
@@ -474,6 +486,7 @@ class Main {
if (videoList.length == 0) return;
if (!clients.hasLeader()) {
if (videoTimer.isPaused()) videoTimer.play();
+ videoTimer.setRate(1);
broadcast({
type: Play, play: {
time: videoTimer.getTime()
diff --git a/src/server/VideoTimer.hx b/src/server/VideoTimer.hx
index 4bc29db..508b97b 100644
--- a/src/server/VideoTimer.hx
+++ b/src/server/VideoTimer.hx
@@ -1,19 +1,22 @@
package server;
-import haxe.Timer;
+import haxe.Timer.stamp;
class VideoTimer {
public var isStarted(default, null) = false;
var startTime = 0.0;
var pauseStartTime = 0.0;
+ var rateStartTime = 0.0;
+ var rate = 1.0;
public function new() {}
public function start():Void {
isStarted = true;
- startTime = Timer.stamp();
+ startTime = stamp();
pauseStartTime = 0;
+ rateStartTime = stamp();
}
public function stop():Void {
@@ -23,22 +26,26 @@ class VideoTimer {
}
public function pause():Void {
- pauseStartTime = Timer.stamp();
+ startTime += rateTime() - rateTime() * this.rate;
+ pauseStartTime = stamp();
+ rateStartTime = 0;
}
public function play():Void {
if (!isStarted) start();
startTime += pauseTime();
+ rateStartTime = stamp();
pauseStartTime = 0;
}
public function getTime():Float {
if (startTime == 0) return 0;
- return Timer.stamp() - startTime - pauseTime();
+ final time = stamp() - startTime;
+ return time - rateTime() + rateTime() * rate - pauseTime();
}
public function setTime(secs:Float):Void {
- startTime = Timer.stamp() - secs;
+ startTime = stamp() - secs;
if (isPaused()) pause();
}
@@ -46,9 +53,26 @@ class VideoTimer {
return !isStarted || pauseStartTime != 0;
}
+ public function getRate():Float {
+ return rate;
+ }
+
+ public function setRate(rate:Float):Void {
+ if (!isPaused()) {
+ startTime += rateTime() - rateTime() * this.rate;
+ rateStartTime = stamp();
+ }
+ this.rate = rate;
+ }
+
function pauseTime():Float {
if (pauseStartTime == 0) return 0;
- return Timer.stamp() - pauseStartTime;
+ return stamp() - pauseStartTime;
+ }
+
+ function rateTime():Float {
+ if (rateStartTime == 0) return 0;
+ return stamp() - rateStartTime - pauseTime();
}
}
diff --git a/test/Main.hx b/test/Main.hx
new file mode 100644
index 0000000..d2ea286
--- /dev/null
+++ b/test/Main.hx
@@ -0,0 +1,15 @@
+package;
+
+import utest.Runner;
+import utest.ui.Report;
+
+class Main {
+
+ static function main() {
+ final runner = new Runner();
+ runner.addCases(test.tests);
+ Report.create(runner);
+ runner.run();
+ }
+
+}
diff --git a/test/tests/TestTimer.hx b/test/tests/TestTimer.hx
new file mode 100644
index 0000000..9403b75
--- /dev/null
+++ b/test/tests/TestTimer.hx
@@ -0,0 +1,163 @@
+package test.tests;
+
+import haxe.PosInfos;
+import utest.Assert;
+import haxe.Timer;
+import server.VideoTimer;
+
+class TestTimer extends utest.Test {
+
+ @:timeout(500)
+ function testMain(async:utest.Async) {
+ final timer = new VideoTimer();
+ timer.start();
+ Timer.delay(() -> {
+ almostEq(0.1, timer.getTime());
+ timer.setTime(1);
+ almostEq(1, timer.getTime());
+ }, 100);
+ Timer.delay(() -> {
+ almostEq(1.1, timer.getTime());
+ timer.setTime(0.1);
+ almostEq(0.1, timer.getTime());
+ }, 200);
+ Timer.delay(() -> {
+ almostEq(0.2, timer.getTime());
+ Assert.equals(false, timer.isPaused());
+ Assert.equals(true, timer.isStarted);
+ timer.stop();
+ Assert.equals(0, timer.getTime());
+ Assert.equals(true, timer.isPaused());
+ Assert.equals(false, timer.isStarted);
+ async.done();
+ }, 300);
+ }
+
+ @:timeout(500)
+ function testRate(async:utest.Async) {
+ final timer = new VideoTimer();
+ timer.start();
+ timer.setRate(2);
+ almostEq(0, timer.getTime());
+ Timer.delay(() -> {
+ almostEq(0.2, timer.getTime());
+ timer.setRate(1);
+ almostEq(0.2, timer.getTime());
+ }, 100);
+ Timer.delay(() -> {
+ almostEq(0.3, timer.getTime());
+ timer.setRate(2);
+ almostEq(0.3, timer.getTime());
+ }, 200);
+ Timer.delay(() -> {
+ almostEq(0.5, timer.getTime());
+ timer.pause();
+ almostEq(0.5, timer.getTime());
+ Assert.equals(true, timer.isPaused());
+ Assert.equals(true, timer.isStarted);
+ }, 300);
+ Timer.delay(() -> {
+ almostEq(0.5, timer.getTime());
+ Assert.equals(true, timer.isPaused());
+ Assert.equals(true, timer.isStarted);
+ async.done();
+ }, 400);
+ }
+
+ @:timeout(500)
+ function testRatePause(async:utest.Async) {
+ final timer = new VideoTimer();
+ timer.start();
+ timer.setRate(2);
+ timer.setTime(1);
+ almostEq(1, timer.getTime());
+ Timer.delay(() -> {
+ almostEq(1.2, timer.getTime());
+ timer.pause();
+ almostEq(1.2, timer.getTime());
+ }, 100);
+ Timer.delay(() -> {
+ almostEq(1.2, timer.getTime());
+ timer.play();
+ almostEq(1.2, timer.getTime());
+ }, 200);
+ Timer.delay(() -> {
+ almostEq(1.4, timer.getTime());
+ timer.pause();
+ almostEq(1.4, timer.getTime());
+ timer.setRate(3);
+ }, 300);
+ Timer.delay(() -> {
+ almostEq(1.4, timer.getTime());
+ timer.play();
+ almostEq(1.4, timer.getTime());
+ timer.setRate(1);
+ almostEq(1.4, timer.getTime());
+ async.done();
+ }, 400);
+ }
+
+ @:timeout(500)
+ function testPauseRate(async:utest.Async) {
+ final timer = new VideoTimer();
+ timer.start();
+ timer.setTime(100);
+ timer.pause();
+ Timer.delay(() -> {
+ almostEq(100, timer.getTime());
+ timer.setRate(2);
+ almostEq(100, timer.getTime());
+ }, 100);
+ Timer.delay(() -> {
+ almostEq(100, timer.getTime());
+ timer.setRate(1);
+ almostEq(100, timer.getTime());
+ }, 200);
+ Timer.delay(() -> {
+ almostEq(100, timer.getTime());
+ timer.setRate(2);
+ almostEq(100, timer.getTime());
+ timer.play();
+ almostEq(100, timer.getTime());
+ }, 300);
+ Timer.delay(() -> {
+ almostEq(100.2, timer.getTime());
+ timer.setRate(1);
+ almostEq(100.2, timer.getTime());
+ async.done();
+ }, 400);
+ }
+
+ @:timeout(500)
+ function testBigRate(async:utest.Async) {
+ final timer = new VideoTimer();
+ timer.start();
+ timer.setRate(3);
+ timer.setTime(10);
+ almostEq(10, timer.getTime());
+ Timer.delay(() -> {
+ almostEq(10.3, timer.getTime());
+ }, 100);
+ Timer.delay(() -> {
+ almostEq(10.6, timer.getTime());
+ timer.pause();
+ almostEq(10.6, timer.getTime());
+ }, 200);
+ Timer.delay(() -> {
+ almostEq(10.6, timer.getTime());
+ timer.play();
+ almostEq(10.6, timer.getTime());
+ }, 300);
+ Timer.delay(() -> {
+ almostEq(10.9, timer.getTime());
+ timer.setRate(1);
+ almostEq(10.9, timer.getTime());
+ async.done();
+ }, 400);
+ }
+
+ function almostEq(a:Float, b:Float, ?p:PosInfos):Void {
+ Assert.equals(Math.round(a * 10) / 10, Math.round(b * 10) / 10, p);
+ }
+
+}
diff --git a/tests.hxml b/tests.hxml
new file mode 100644
index 0000000..c95f9d8
--- /dev/null
+++ b/tests.hxml
@@ -0,0 +1,6 @@
+-cp src
+-cp test
+--main Main
+-lib utest
+--interp
+#-D test=9133
send patches to the email below
yukais@pinapelz.com
include the subject [PATCH repo_name]
pinapelz.com
homepage