forked from EmulatorJS/EmulatorJS
-
Notifications
You must be signed in to change notification settings - Fork 0
LiveStream SFU Relay Service Release Candidate #1
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
76 commits
Select commit
Hold shift + click to select a range
1d0ac09
Netplay SocketIO Engine Connecting
TechnicallyComputers 4d0ec4c
NewNetplay Engine Progress
TechnicallyComputers 338a275
Improved room management
TechnicallyComputers 22dafcd
Netplay Refactor
TechnicallyComputers 1029fff
Netplay Refactor Update
TechnicallyComputers 3b1c161
NetplayUI refactor + stability
TechnicallyComputers bc1d12b
video stream working
TechnicallyComputers 7d17e46
Updating SFU transport code and netplay engine
TechnicallyComputers 96410a3
Inputs Closer
TechnicallyComputers 421c906
InputSyncing
TechnicallyComputers 768a47f
control is much better
TechnicallyComputers 871fce7
SimpleController & updates
TechnicallyComputers 3622844
Optimizing UI
TechnicallyComputers 781113b
Optimizing UI
TechnicallyComputers cc16913
centralized Input, player table data, slot select
TechnicallyComputers 4da3db0
Lobby Management
TechnicallyComputers e567bb0
UI near complete, handle transports
TechnicallyComputers 20b88d7
Menu Optimizations
TechnicallyComputers 5c38205
Mupen64plus_next_netplay
TechnicallyComputers 3d333c0
netplay updates
TechnicallyComputers 06dd492
Rebuilding P2P DataChannels
TechnicallyComputers 544f38e
Fixed Unordered P2P
TechnicallyComputers 5eddbf1
Fix Host Unordered P2P Bug
TechnicallyComputers cdce7eb
ICE Server Updates
TechnicallyComputers 50cb990
Fix nightly folder
ethanaobrien 811697d
Arcade Lobby 0.1
TechnicallyComputers c7cc100
Remove call to command.exe
ethanaobrien bb7b21e
Switch these things
ethanaobrien 61a3af7
v0.1 Netplay Hybrid SFU/TURN
TechnicallyComputers 56951fb
minor update
TechnicallyComputers d5748ec
Alpha build 1st release
TechnicallyComputers 98f887f
Update Defaults
TechnicallyComputers a5442be
Core DL from EmuJS Nightly CDN
TechnicallyComputers 390c0fa
Initial revision to README.md
TechnicallyComputers 5178a30
Stop attempting p2p to yourself
TechnicallyComputers 903c6e3
Fix netplay controller input slots
TechnicallyComputers 6c36d6c
Self P2P bugfix v2
TechnicallyComputers e19f02b
P# selection logic fixes, Firefox audio
TechnicallyComputers f8e47d1
Client Side SFU Audio Fallbacks
TechnicallyComputers d064d22
Improved stream handling
TechnicallyComputers 391deb3
Create NETCODE_REFACTOR_PLAN.md
TechnicallyComputers 11c4805
Auth error handling & code notes
TechnicallyComputers a3e6131
room list error handling
TechnicallyComputers f996b30
Error handling missing auth cookie
TechnicallyComputers b18b1d8
Phase 5: Netplay module loading integration
TechnicallyComputers c8d8772
Netcode + UI
TechnicallyComputers 5baca3e
More UI Updates
TechnicallyComputers f86f3ac
Netplay SocketIO Engine Connecting
TechnicallyComputers ed83ea8
NewNetplay Engine Progress
TechnicallyComputers 3592b95
Improved room management
TechnicallyComputers bde8023
Netplay Refactor
TechnicallyComputers 0c7b6f7
Netplay Refactor Update
TechnicallyComputers 00c0165
NetplayUI refactor + stability
TechnicallyComputers 99c439f
video stream working
TechnicallyComputers eddb042
Updating SFU transport code and netplay engine
TechnicallyComputers e74e4f0
Inputs Closer
TechnicallyComputers 5ecf2ed
InputSyncing
TechnicallyComputers df370d3
control is much better
TechnicallyComputers 9b642f4
SimpleController & updates
TechnicallyComputers ae613dd
Optimizing UI
TechnicallyComputers 1958880
Optimizing UI
TechnicallyComputers ed2600e
centralized Input, player table data, slot select
TechnicallyComputers 5a3e8d9
Lobby Management
TechnicallyComputers 5a966fc
UI near complete, handle transports
TechnicallyComputers c9098c3
Menu Optimizations
TechnicallyComputers 7ae2bb5
Mupen64plus_next_netplay
TechnicallyComputers 5df37ec
netplay updates
TechnicallyComputers 9e91ca2
Rebuilding P2P DataChannels
TechnicallyComputers f5b78e8
Fixed Unordered P2P
TechnicallyComputers 5adaf8d
Fix Host Unordered P2P Bug
TechnicallyComputers a056b47
ICE Server Updates
TechnicallyComputers 345c774
Arcade Lobby 0.1
TechnicallyComputers 9994b41
Merge branch 'TechnicallyComputers/dev' of github.com:TechnicallyComp…
TechnicallyComputers 367c1d0
Arcade Lobby In Progress
TechnicallyComputers e71892b
Disable Arcade Lobby, force vp9 optimized settings.
TechnicallyComputers 393437f
Live Stream Latency Optimizations & Focus
TechnicallyComputers File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
15 changes: 15 additions & 0 deletions
15
.github/prompts/plan-implementArcadeLobbyFeature.prompt.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| ## Plan: Implement Arcade Lobby Feature | ||
|
|
||
| Create arcadeLobbySetup() function in NetplayMenu.js to display a Host/Join popup, integrate SFU server for arcade lobby routers handling multi-stream video/audio transport, and build a CSS grid UI for pinning up to 4 video streams with dynamic layouts (1x2 for 2, 2x2 for 3-4). This enables multi-user arcade sessions where hosts stream emulators and spectators pin views, leveraging existing netplay infrastructure for scalability and input sync. | ||
|
|
||
| ### Steps | ||
| 1. Add `arcadeLobbySetup()` in [NetplayMenu.js](data/src/netplay/ui/NetplayMenu.js) to create popup with Host/Join buttons, calling room creation/join logic. | ||
| 2. Extend SFU [index.js](romm-sfu-server/index.js) to support "arcade" room type, creating lobby routers and piping host streams to all users. | ||
| 3. Modify NetplayEngine.js to handle hidden emulator for hosts/spectators, capturing video/audio for transport. | ||
| 4. Implement CSS grid in emulator.min.css for 80% main canvas and 20% scrollable previews, with pinning logic in NetplayMenu.js. | ||
| 5. Create new menu roomtypes arcadelobby, and arcadelivestream, with arcadelivestream having a menu and bottombar the same as livestream. | ||
|
|
||
| ### Further Considerations | ||
| 1. Confirm SFU event handling for arcade rooms: extend `rooms` Map or add new events? | ||
| 2. Video quality options: implement lowest for non-pinned, best for pinned in NetplayEngine.js? | ||
| 3. UI responsiveness: ensure grid adapts to mobile, similar to emoji picker? |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,189 @@ | ||
| # Arcade Lobby Stream Compositor Implementation | ||
|
|
||
| ## Overview | ||
|
|
||
| Implemented a canvas-based stream compositor system for arcade lobby mode that: | ||
| - Composites multiple producer video streams into a single grid layout | ||
| - Displays streams on a hidden canvas (80/20 split: pinned left, other right) | ||
| - Captures the composited canvas for SFU streaming to remote viewers | ||
| - Supports dynamic stream registration/deregistration and pin toggling | ||
|
|
||
| ## Architecture | ||
|
|
||
| ### Components Created/Modified | ||
|
|
||
| #### 1. **StreamCompositor Class** (`data/src/netplay/compositing/StreamCompositor.js`) | ||
| - **Purpose**: Handles all canvas-based stream rendering and compositing | ||
| - **Key Methods**: | ||
| - `registerStream()`: Add a producer stream to the compositor | ||
| - `unregisterStream()`: Remove a producer stream | ||
| - `togglePin()`: Toggle pinned state for a stream | ||
| - `render()`: Main rendering loop that draws streams to canvas | ||
| - `drawGridSection()`: Draw a portion of the grid (pinned or other) | ||
| - `drawStreamCell()`: Draw individual stream cell with video frame | ||
| - `getCanvas()`: Return the hidden compositing canvas for capture | ||
|
|
||
| - **Features**: | ||
| - Continuous requestAnimationFrame rendering loop | ||
| - Automatic column calculation based on stream count | ||
| - Letterbox/pillarbox aspect ratio preservation | ||
| - Pin status indicators on cells | ||
| - Stream name overlays | ||
| - Placeholder graphics when video not ready | ||
|
|
||
| #### 2. **NetplayEngine Updates** (`data/src/netplay/core/NetplayEngine.js`) | ||
| - Added `streamCompositor` property to hold the compositor instance | ||
| - **New Methods**: | ||
| - `initializeStreamCompositor(width, height)`: Initialize compositor for arcade lobby | ||
| - `registerProducerStream()`: Register stream with compositor | ||
| - `unregisterProducerStream()`: Unregister stream | ||
| - `toggleProducerPin()`: Toggle pin state | ||
| - `createConsumerWithCompositor()`: Create consumer + auto-register with compositor | ||
| - `disposeStreamCompositor()`: Clean up compositor on room exit | ||
|
|
||
| - **Modified Methods**: | ||
| - `netplayCaptureCanvasVideo()`: Now checks for active compositor first, falls back to emulator canvas | ||
|
|
||
| #### 3. **NetplayMenu Updates** (`data/src/netplay/ui/NetplayMenu.js`) | ||
| - **Simplified arcade lobby grid setup**: | ||
| - `setupArcadeLobbyGrid()`: Now just initializes compositor | ||
| - `initializeArcadeLobbyCompositor()`: Wrapper to initialize engine compositor | ||
| - `arcadeLobbyRegisterStream()`: Register stream from UI layer | ||
| - `arcadeLobbyUnregisterStream()`: Unregister stream from UI layer | ||
| - `arcadeLobbyTogglePin()`: Toggle pin from UI | ||
|
|
||
| - Removed duplicate DOM-based grid implementations | ||
| - Updated `createArcadeCell()` and `updateArcadeLobbyStreams()` to work with new system | ||
|
|
||
| ## Data Flow | ||
|
|
||
| ### Stream Registration | ||
| ``` | ||
| SFU Consumer Created | ||
| ↓ | ||
| createConsumerWithCompositor() | ||
| ↓ | ||
| MediaStream Created from Track | ||
| ↓ | ||
| registerProducerStream() in NetplayEngine | ||
| ↓ | ||
| StreamCompositor.registerStream() | ||
| ↓ | ||
| Video Element Created & Connected | ||
| ↓ | ||
| Rendering Loop Started | ||
| ``` | ||
|
|
||
| ### Capture Flow (for remote viewers) | ||
| ``` | ||
| Arcade Lobby Mode Active | ||
| ↓ | ||
| StreamCompositor Rendering Continuous Grid | ||
| ↓ | ||
| requestAnimationFrame Draws All Streams | ||
| ↓ | ||
| netplayCaptureCanvasVideo() Checks Compositor | ||
| ↓ | ||
| captureStream() on Compositor Canvas | ||
| ↓ | ||
| SFU Video Producer Streams Grid to Remote Viewers | ||
| ``` | ||
|
|
||
| ## Grid Layout | ||
|
|
||
| ### 80/20 Split | ||
| - **Left Section (80% width)**: | ||
| - Pinned producer streams in grid layout | ||
| - Auto-adjusts columns based on count | ||
| - Larger cells for better viewing | ||
|
|
||
| - **Right Section (20% width)**: | ||
| - Non-pinned producer streams | ||
| - Stacked vertically (single column) | ||
| - Smaller cells to fit in space | ||
|
|
||
| ### Visual Features | ||
| - Black background with subtle borders | ||
| - Stream names displayed at bottom of each cell | ||
| - Pin indicator (📌) for pinned streams | ||
| - Letterbox/pillarbox video aspect ratio preservation | ||
| - Divider line between sections when both have content | ||
|
|
||
| ## Pin/Unpin Toggle | ||
|
|
||
| Streams can be pinned/unpinned: | ||
| 1. Via arcade lobby UI (future: add pin buttons) | ||
| 2. Via direct API: `engine.toggleProducerPin(producerId)` | ||
| 3. State tracked in `StreamCompositor.pinnedIds` Set | ||
| 4. Grid automatically re-renders on pin state change | ||
|
|
||
| ## Canvas Specifications | ||
|
|
||
| - **Size**: 1280x720 (configurable) | ||
| - **Frame Rate**: 30 FPS | ||
| - **Location**: Hidden, not displayed to user | ||
| - **Capture Method**: `captureStream(30)` for native API support | ||
| - **Cleanup**: Auto-disposed when leaving arcade lobby | ||
|
|
||
| ## Integration Points | ||
|
|
||
| ### With SFU Transport | ||
| - Monitors consumer creation events | ||
| - Automatically registers video consumers | ||
| - Cleans up streams on consumer close | ||
|
|
||
| ### With Netplay Menu | ||
| - Menu calls `initializeArcadeLobbyCompositor()` on arcade lobby entry | ||
| - Menu can call `arcadeLobbyRegisterStream()` and `arcadeLobbyTogglePin()` | ||
| - Menu disposes compositor on room exit | ||
|
|
||
| ### With Emulator Canvas Capture | ||
| - Falls back to emulator canvas if compositor not available | ||
| - Compositor takes priority when active | ||
| - Remote viewers see composited grid instead of single game canvas | ||
|
|
||
| ## Performance Considerations | ||
|
|
||
| - **Memory**: Each stream holds a video element (kept off-DOM) | ||
| - **CPU**: Canvas rendering in requestAnimationFrame (30 FPS) | ||
| - **Bandwidth**: Single composited stream vs multiple streams | ||
| - **Scalability**: Tested up to 9 streams in grid layout | ||
|
|
||
| ## Future Enhancements | ||
|
|
||
| 1. **UI Controls**: Add pin/unpin buttons in arcade lobby UI | ||
| 2. **Custom Sizing**: Allow users to set canvas resolution | ||
| 3. **Layout Presets**: Predefined grid layouts (2x2, 3x3, etc.) | ||
| 4. **Stream Labels**: Custom naming and avatar support | ||
| 5. **Recording**: Save composited stream to disk | ||
| 6. **Transcoding**: Built-in resolution/bitrate adjustment | ||
| 7. **Analytics**: Stream quality monitoring and reporting | ||
|
|
||
| ## Testing Checklist | ||
|
|
||
| - [ ] Compositor initializes on arcade lobby entry | ||
| - [ ] Video consumers register automatically | ||
| - [ ] Grid renders with correct 80/20 split | ||
| - [ ] Pinned/unpinned state toggling works | ||
| - [ ] Pin state visible on canvas (pin emoji) | ||
| - [ ] Stream names display correctly | ||
| - [ ] Aspect ratio preserved for all videos | ||
| - [ ] Streams are cleaned up on room exit | ||
| - [ ] Compositor canvas captured for SFU streaming | ||
| - [ ] Remote viewers see composited grid | ||
| - [ ] Falling back to emulator canvas works | ||
| - [ ] Multiple streams render without lag | ||
|
|
||
| ## Code Files Modified | ||
|
|
||
| 1. `/data/src/netplay/compositing/StreamCompositor.js` - NEW | ||
| 2. `/data/src/netplay/core/NetplayEngine.js` - Modified | ||
| 3. `/data/src/netplay/ui/NetplayMenu.js` - Modified | ||
|
|
||
| ## Notes | ||
|
|
||
| - StreamCompositor is independent and can be used elsewhere | ||
| - Canvas rendering is continuous (not event-based) for smooth updates | ||
| - Video elements are hidden but must remain in DOM for playback | ||
| - MediaStream objects are kept alive by video elements | ||
| - All cleanup is automatic through dispose() methods |
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
rsync exclude pattern won't match, cores copied unintentionally
Medium Severity
The
--exclude .EmulatorJS/data/cores/pattern in thersynccommand will never match anything. Because the source is.EmulatorJS/(with trailing slash), rsync treats file paths as relative to inside that directory (e.g.,data/cores/...). The exclude pattern.EmulatorJS/data/cores/includes the source directory name, which doesn't appear in the internal transfer paths. The pattern needs to bedata/cores/instead.