Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion flashdreams/flashdreams/api_v2/client_window.py
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ class IClientWindow(InputSource, OutputSink, ABC):
is given that description in :meth:`OutputSink.open`.

One thread makes every call on a window, so an implementation needs no
locking of its own.
locking except when its backend delivers input from another thread.

Created by the runtime, never by an application.
"""
44 changes: 44 additions & 0 deletions flashdreams/flashdreams/runtime_v2/application_runner.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Application lifecycle runner for the v2 runtime."""

from collections.abc import Sequence

from flashdreams.api_v2.application import IApplication
from flashdreams.api_v2.client_window import IClientWindow
from flashdreams.runtime_v2.session_desc import SessionDesc
from flashdreams.runtime_v2.session_runner import run_session


class ApplicationRunner:
"""Create and run one application session against one client window."""

def __init__(self, application: IApplication, client_window: IClientWindow) -> None:
"""
Args:
application: Long-lived application that creates the session.
client_window: Window that supplies input and presents generated output.
"""
self._application = application
self._client_window = client_window

def run(
self,
session_desc: SessionDesc,
commandline_args: Sequence[str] = (),
) -> None:
"""Initialize the application, create one session, and run it.

The application is closed before this method returns or raises.

Args:
session_desc: Output shape and timing requested for the session.
commandline_args: Arguments owned and parsed by the application.
"""
try:
self._application.init(commandline_args)
session = self._application.create_session(session_desc)
run_session(session, self._client_window)
finally:
self._application.close()
27 changes: 27 additions & 0 deletions flashdreams/flashdreams/runtime_v2/client_window_factory.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just leaving a note that I did not use this for the Mp4ClientWindow, as I assume it will be superseded by the new flashdreams-run, so we can remove this file when that happens. Is my understanding right?

# SPDX-License-Identifier: Apache-2.0

"""Create v2 client windows from runtime arguments."""

import argparse

from flashdreams.api_v2.client_window import IClientWindow
from flashdreams.runtime_v2.webrtc_client_window import WebRTCClientWindow


def create_client_window(parsed_args: argparse.Namespace) -> IClientWindow:
"""Create the client window selected by the presentation mode.

Args:
parsed_args: Runtime arguments. Mode-specific fields are read only by
the selected mode.

Returns:
Client window for the selected mode.

Raises:
ValueError: ``mode`` is unsupported.
"""
if parsed_args.mode == "webrtc":
return WebRTCClientWindow(host=parsed_args.host, port=parsed_args.port)
raise ValueError(f"Unsupported client-window mode: {parsed_args.mode!r}.")
4 changes: 4 additions & 0 deletions flashdreams/flashdreams/runtime_v2/serving/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
# SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
# SPDX-License-Identifier: Apache-2.0

"""Serving backends for the v2 runtime."""
61 changes: 61 additions & 0 deletions flashdreams/flashdreams/runtime_v2/serving/web/app.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
// SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
// SPDX-License-Identifier: Apache-2.0

const peer = new RTCPeerConnection();
const controls = peer.createDataChannel("controls");
peer.addTransceiver("video", {direction: "recvonly"});

peer.ontrack = event => {
document.getElementById("video").srcObject =
event.streams[0] ?? new MediaStream([event.track]);
};

const send = payload => {
if (controls.readyState === "open") {
controls.send(JSON.stringify(payload));
}
};

window.addEventListener("keydown", event => {
send({type: "keyboard", key: event.key, pressed: true});
});

window.addEventListener("keyup", event => {
send({type: "keyboard", key: event.key, pressed: false});
});

let activationPressed = false;
document.getElementById("activate").onclick = event => {
activationPressed = !activationPressed;
event.currentTarget.textContent =
activationPressed ? "Deactivate" : "Activate";
send({type: "keyboard", key: "r", pressed: activationPressed});
};

document.getElementById("reset").onclick = () => {
send({type: "reset"});
};

window.addEventListener("beforeunload", () => send({type: "close"}));

async function connect() {
while (true) {
const health = await fetch("/healthz");
if (health.ok && (await health.json()).open) {
break;
}
await new Promise(resolve => setTimeout(resolve, 100));
}
await peer.setLocalDescription(await peer.createOffer());
const response = await fetch("/api/webrtc/offer", {
method: "POST",
headers: {"content-type": "application/json"},
body: JSON.stringify(peer.localDescription),
});
if (!response.ok) {
throw new Error(await response.text());
}
await peer.setRemoteDescription(await response.json());
}

connect();
18 changes: 18 additions & 0 deletions flashdreams/flashdreams/runtime_v2/serving/web/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
<!doctype html>
<!--
SPDX-FileCopyrightText: Copyright (c) 2026 NVIDIA CORPORATION & AFFILIATES. All rights reserved.
SPDX-License-Identifier: Apache-2.0
-->

<html lang="en">
<head>
<meta charset="utf-8">
<title>FlashDreams WebRTC</title>
</head>
<body>
<video id="video" autoplay playsinline></video>
<button id="activate" type="button">Activate</button>
<button id="reset" type="button">Reset</button>
<script src="/app.js"></script>

Copy link
Copy Markdown
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is meant to demo the functionality. Can be cleaned up. In the production, only the video track and <script src="/app.js"></script> for registering browser event handlers are needed

</body>
</html>
Loading
Loading