Keep a playing video when the window comes back to the front (#402)
Chrome draws no frames for a hidden page, so the scene stopped asking
for its videos. The sweeper of the VideoLibrary kept running and
dropped every player after 2 s. Back in the window, the video started
over, and Pixi warned that a texture source was destroyed while still
bound to a shader.
- The sweeper skips a hidden page. The time hidden does not count as
idle, the 2 s start once the page is shown again.
- A dropped player only unloads its video source instead of destroying
it. A shader that still holds the source no longer warns.
- CI serves videos through a new router for php -S. The built-in
server answers no Range requests, so Chrome could not seek. e2e 66
had 4 red checks in the suite job of d48f174 because of it. nginx on
stein2 hid this.
Tests:
- Unit video-library.test.ts (new): 3 tests
- e2e 66 (atx): ALL PASSED, 18 checks
- Router checked with curl: 206 with the right bytes
- Counter-check: the old sweep fails both hidden-page tests
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
1 parent
d48f174caf
commit
c815d2c35f
4 files changed
+154
-8
No files matched your search
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
// Router of the CI jobs' dev server (see serve.sh). `php -S` answers no Range requests, and Chrome
|
||||
// cannot seek in a video served without them (#402): a clip stayed at the video's first frame. On
|
||||
// stein2 nginx does this. Here the converted videos get their ranges; everything else is left to
|
||||
// the server as before.
|
||||
|
||||
$path = rawurldecode((string) parse_url($_SERVER['REQUEST_URI'] ?? '', PHP_URL_PATH));
|
||||
if (!preg_match('#^/game-maker/data/videos/[0-9a-z]+/[0-9a-f]{64}\.mp4$#', $path)) {
|
||||
return false;
|
||||
}
|
||||
$file = $_SERVER['DOCUMENT_ROOT'] . $path;
|
||||
if (!is_file($file)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$size = filesize($file);
|
||||
$start = 0;
|
||||
$end = $size - 1;
|
||||
header('Content-Type: video/mp4');
|
||||
header('Accept-Ranges: bytes');
|
||||
if (preg_match('/^bytes=(\d*)-(\d*)$/', $_SERVER['HTTP_RANGE'] ?? '', $range)) {
|
||||
if ($range[1] === '') {
|
||||
$start = max(0, $size - (int) $range[2]);
|
||||
} else {
|
||||
$start = (int) $range[1];
|
||||
if ($range[2] !== '') {
|
||||
$end = min($end, (int) $range[2]);
|
||||
}
|
||||
}
|
||||
if ($start > $end) {
|
||||
http_response_code(416);
|
||||
header("Content-Range: bytes */$size");
|
||||
return true;
|
||||
}
|
||||
http_response_code(206);
|
||||
header("Content-Range: bytes $start-$end/$size");
|
||||
}
|
||||
header('Content-Length: ' . ($end - $start + 1));
|
||||
if ($_SERVER['REQUEST_METHOD'] === 'HEAD') {
|
||||
return true;
|
||||
}
|
||||
$in = fopen($file, 'rb');
|
||||
$out = fopen('php://output', 'wb');
|
||||
stream_copy_to_stream($in, $out, $end - $start + 1, $start);
|
||||
return true;
|
||||
+2
-2
@@ -40,8 +40,8 @@ game_maker_serve() {
|
||||
# game-maker-video, here a process beside the server.
|
||||
php "$root/tools/video-worker.php" "$root/data" >/tmp/video-worker.log 2>&1 &
|
||||
# Without workers the single-threaded dev server stalls: the editor fetches project and
|
||||
# textures in parallel.
|
||||
PHP_CLI_SERVER_WORKERS=8 php -S 0.0.0.0:8080 -t /srv >/tmp/php-server.log 2>&1 &
|
||||
# textures in parallel. The router serves videos with Range requests, see there.
|
||||
PHP_CLI_SERVER_WORKERS=8 php -S 0.0.0.0:8080 -t /srv "$root/tools/ci/router.php" >/tmp/php-server.log 2>&1 &
|
||||
|
||||
for _ in $(seq 60); do
|
||||
curl -sf "${GAME_MAKER_BASE_URL}api/index.php?r=auth/session" >/dev/null 2>&1 && break
|
||||
|
||||
Reference in new issue
Block a user