Compare commits

...

396 Commits

Author SHA1 Message Date
Luke Bermingham cb741add4f
Readme to new repo: https://github.com/EpicGamesExt/PixelStreamingInfrastructure
More details can be found here: https://forums.unrealengine.com/t/migrating-optional-epic-games-git-repositories-to-new-github-organization/1718666

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2024-02-29 15:02:21 +10:00
mcottontensor 88d82e1112
Merge pull request #492 from mcottontensor/setting_option_fix
Setting option fix
2024-02-20 15:20:32 +11:00
mcottontensor caddb00ed3
Merge branch 'master' into setting_option_fix 2024-02-20 15:18:34 +11:00
Matthew Cotton f0fd72768c
Fixed incorrect settings setup with SettingOption 2024-02-20 15:13:29 +11:00
Matthew Cotton 7cbe5227dd
Merge remote-tracking branch 'upstream/master' 2024-02-20 15:05:43 +11:00
mcottontensor 672397e6a8
Update README.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2024-02-20 14:58:20 +11:00
David MacPherson fa75e9d8c5
Implemented a bug fix to remove the setupWebRTCtcpDetectEvent from the event emitter (#490) 2024-02-19 13:23:01 +10:00
David MacPherson 4969548535
Add TCP+Relay detection event (#485)
* Change the label for the remote candidate
* Added the following missing WebRTC stats id,timestamp,type,lastPacketReceivedTimestamp,lastPacketSentTimestamp,priority,remoteCandidateId,transportId and writable
* Added relayProtocol and transport ID to the candidate Stat
* Refactored the candidate pair to be an array as many pairs are generated
* Implemeneted a WebRtcTCPRelayDetectedEvent that is fired when WebRTC transport is TCP AND we are using a relay candidate (e.g. a TURN server is being used).
* Refactored the stats panel to use the `getActiveCandidatePair()`
2024-02-19 10:52:32 +10:00
Luke Bermingham e91781b6fa
Create angular/readme.md
Added a readme.md for angular implementations that links to community provided examples.

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2024-02-16 14:04:17 +10:00
Bryan eea0faff60
Fix typo readme (#488)
Signed-off-by: Bryan <69793084+Ahhj93@users.noreply.github.com>
2024-02-15 11:49:07 +10:00
William Belcher 664d40b801
Update TouchStart and TouchMove handlers to force a touch force of 1 if the touch.force member is 0 (#486) 2024-02-14 14:02:48 +10:00
mcottontensor 5cf2735c5f
Update README.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2024-01-24 15:52:58 +11:00
mcottontensor 2544b717ae
Merge pull request #476 from EpicGames/UE5.4
Syncing master with UE5.4
2024-01-24 15:34:31 +11:00
mcottontensor b2cdcf10f3
Update RELEASE_VERSION
Updating main minor version for the release.

Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2024-01-24 15:31:20 +11:00
Matthew Cotton e44a9ff734
Bumping minor version and library reference. 2024-01-24 15:29:54 +11:00
mcottontensor 8734e5bb56
Update package.json
Bumping minor version

Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2024-01-24 15:26:57 +11:00
mcottontensor f272cefb93
Merge pull request #475 from EpicGames/master
Syncing with master
2024-01-24 15:22:53 +11:00
mcottontensor d61b989bff
Merge pull request #453 from kroecks/master
Fix for build-all script dependencies
2024-01-24 15:20:35 +11:00
mcottontensor 4aded6b752
Merge branch 'master' into master 2024-01-24 15:19:31 +11:00
mcottontensor dee225c03a
Merge pull request #464 from EpicGames/dependabot/npm_and_yarn/Frontend/implementations/react/follow-redirects-1.15.4
Bump follow-redirects from 1.15.2 to 1.15.4 in /Frontend/implementations/react
2024-01-24 15:18:42 +11:00
mcottontensor ce2a493114
Merge branch 'master' into dependabot/npm_and_yarn/Frontend/implementations/react/follow-redirects-1.15.4 2024-01-24 15:16:47 +11:00
mcottontensor 44367dfa8a
Merge pull request #465 from EpicGames/dependabot/npm_and_yarn/Frontend/implementations/typescript/follow-redirects-1.15.4
Bump follow-redirects from 1.15.2 to 1.15.4 in /Frontend/implementations/typescript
2024-01-24 15:16:22 +11:00
mcottontensor 23e562dfdf
Merge branch 'master' into master 2024-01-24 15:15:10 +11:00
mcottontensor 20987e006e
Merge branch 'master' into dependabot/npm_and_yarn/Frontend/implementations/react/follow-redirects-1.15.4 2024-01-24 15:14:37 +11:00
mcottontensor a0f9b34dde
Merge branch 'master' into dependabot/npm_and_yarn/Frontend/implementations/typescript/follow-redirects-1.15.4 2024-01-24 15:13:44 +11:00
Denis Phoenix f4380ab2c0
Update copyright/licence year (#474)
Update licence and copyright year in all relevant files.
2024-01-23 14:30:41 +10:00
Matthew Cotton 556ecc5df3
Allowing signalling test action to be manually triggered 2024-01-22 12:17:59 +11:00
Matthew Cotton cb58c2c068
adding a signalling test action to master so it can be run in the signalling_tester branch 2024-01-22 12:16:42 +11:00
William Belcher 6d59c44126
Export NO_SUDO so it's available for use in launched processes (#472) 2024-01-15 13:29:41 +10:00
William Belcher 04c2bc5e70
Move settings order so that they are parsed default settings -> intitial settings -> url params (#471) 2024-01-15 11:33:46 +10:00
dependabot[bot] d355d6685a
Bump follow-redirects in /Frontend/implementations/typescript
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-10 21:12:16 +00:00
dependabot[bot] 1b00462e1c
Bump follow-redirects in /Frontend/implementations/react
Bumps [follow-redirects](https://github.com/follow-redirects/follow-redirects) from 1.15.2 to 1.15.4.
- [Release notes](https://github.com/follow-redirects/follow-redirects/releases)
- [Commits](https://github.com/follow-redirects/follow-redirects/compare/v1.15.2...v1.15.4)

---
updated-dependencies:
- dependency-name: follow-redirects
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2024-01-10 13:38:27 +00:00
mcottontensor ce299ebd37
Merge pull request #452 from Belchy06/master
Add support for non-latin characters
2023-12-15 10:17:09 +11:00
Ken Roecks 7315292918
Merge branch 'master' into master 2023-12-13 18:03:03 -08:00
William Belcher 8b838f48fe
Add support for non-latin characters 2023-12-13 13:22:45 +10:00
mcottontensor 87b9c9aaed
Merge pull request #451 from Belchy06/master
Fix warnings about GamepadButtonReleased
2023-12-13 11:02:50 +11:00
William Belcher 898504d3a6
Fix warnings about GamepadButtonReleased 2023-12-13 09:53:49 +10:00
Kenneth Roecks 6ac47fffcd Fix for build-all script dependencies 2023-12-12 13:54:01 -08:00
William Belcher 606298d40d Ensure gamepad disconnect is triggered whenever a user navigates away from the player page 2023-12-12 20:26:24 +10:00
mcottontensor d8a4e118a6
Merge pull request #448 from alien299/alien299-ContributingGuidelines-patch01-Closes-#445
Update CONTRIBUTING.md - Added Verified Commits as a Requirement - Closes#445
2023-12-11 09:12:30 +11:00
mcottontensor eb7d4c6262
Merge branch 'master' into alien299-ContributingGuidelines-patch01-Closes-#445 2023-12-11 09:12:10 +11:00
mcottontensor 4ebc522437
Merge pull request #443 from mcottontensor/stale_legacy_timer
Small signalling server fixes.
2023-12-11 09:10:12 +11:00
mcottontensor c6ad00f2ca
Merge branch 'master' into stale_legacy_timer 2023-12-11 09:09:56 +11:00
mcottontensor c05f3b18ce
Merge pull request #441 from alien299/alien299-WebsocketErrorPatch
Update cirrus.js - More informative error messages - Fixes EpicGames/PixelStreamingInfrastructure#184
2023-12-11 09:09:18 +11:00
Patrik Nagy db6273513a
Update CONTRIBUTING.md - Added Verified Commits as a Requirement
Signed-off-by: Patrik Nagy <52012944+alien299@users.noreply.github.com>
2023-12-07 18:30:26 +01:00
pnagy e5f2ff8dd1
Merge branch 'alien299-WebsocketErrorPatch' of https://github.com/alien299/PixelStreamingInfrastructure into alien299-WebsocketErrorPatch 2023-11-30 10:07:54 +01:00
pnagy 2c5628124a
Update cirrus.js - More informative error messages
Fixed an Issue regarding the Websocket disconnect error messages. I made them more informative so they can assist with debugging.
[Issue #184](https://github.com/EpicGames/PixelStreamingInfrastructure/issues/184)
2023-11-30 10:05:45 +01:00
Matthew Cotton 05821c7656
Fixing small issue where if a streamer disconnected before identifying the signalling server would create a legacy name that would be left behind.
Fixing some logging calls that would not properly be handled by the logging system.
2023-11-29 12:02:02 +11:00
pnagy 92de29dbc9 Update cirrus.js - More informative error messages
Fixed an Issue regarding the Websocket disconnect error messages. I made them more informative so they can assist with debugging.
[Issue #184](https://github.com/EpicGames/PixelStreamingInfrastructure/issues/184)
2023-11-28 12:38:50 +01:00
mcottontensor 28e7c0c1f3
Merge pull request #432 from mcottontensor/fix_late_streamer_id
Fixing left behind streamer IDs when they're late to ID themselves.
2023-11-23 11:24:00 +11:00
mcottontensor 649d6b2dcb
Merge branch 'master' into fix_late_streamer_id 2023-11-22 16:32:23 +11:00
mcottontensor a3b76a3acc
Merge pull request #438 from mcottontensor/player_config_streamerid
Fixing handling of StreamerId in the initial config settings.
2023-11-22 16:32:05 +11:00
mcottontensor 5a734f2204
Merge branch 'master' into fix_late_streamer_id 2023-11-22 13:08:54 +11:00
Matthew Cotton 6fe29baa95
Fixing small typos 2023-11-22 13:07:30 +11:00
Matthew Cotton 5e71c6ff97
Fixing default behaviour when joining with one streamer. 2023-11-22 12:52:26 +11:00
Matthew Cotton 6462905b76
Adding support to set the streamer id in the pixel streaming initial settings. Fixes #436 2023-11-22 11:55:24 +11:00
Even Stensberg 7eba788faa
chore: remove explicit /dist dir in Webpack as it is implicit (#434)
Signed-off-by: Even Stensberg <evenstensberg@gmail.com>
2023-11-22 09:13:59 +10:00
Matthew Cotton e9b860428d
Bumping protocol docs version number 2023-11-22 10:08:49 +11:00
Matthew Cotton 4fd2948d99
Adding a little more context to the changed id message documentation. 2023-11-22 10:06:00 +11:00
Matthew Cotton 78640671d4
Adding the id change message to the protocol docs for signalling. 2023-11-22 10:00:29 +11:00
timbotimbo cfbe5a0f86
Fix formatting in bug_report template. (#437)
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
2023-11-22 08:33:58 +10:00
Matthew Cotton ae4b5b7a6d
Updating the settings UI when streamer id changes. 2023-11-21 13:26:40 +11:00
mcottontensor a8de900166
Merge branch 'master' into fix_late_streamer_id 2023-11-21 11:54:10 +11:00
mcottontensor 12a08e1624
Merge pull request #431 from mcottontensor/sfu_docker
Dockerfile for SFU
2023-11-21 11:53:53 +11:00
Matthew Cotton a9b4f31a7d
Adding some information on running the docker image to the new documentation. 2023-11-21 11:53:32 +11:00
mcottontensor d8ac1b62d8
Merge branch 'master' into sfu_docker 2023-11-21 11:44:01 +11:00
mcottontensor e66dacf750
Merge pull request #429 from mcottontensor/new_docs
New docs
2023-11-21 11:43:42 +11:00
Matthew Cotton 8080d2aebb
Adding in new streamer id changed event/message so that the frontend can keep track of its streamer (mostly for reconnecting). 2023-11-21 11:18:28 +11:00
Matthew Cotton 4fd080675e
Adding container build to existing container action. Also added container reference on main README. 2023-11-21 09:55:19 +11:00
Matthew Cotton bbba5e0a67
Small fixes from reviews 2023-11-20 16:19:29 +11:00
Matthew Cotton c37095d229
Fixing the issue when a streamer was late to ID itself, it would leave behind the legacy id 2023-11-20 15:55:38 +11:00
Matthew Cotton f94039dac8
Fixing up some linux scripts. Cleaning up SFU dockerfile 2023-11-20 04:09:56 +00:00
Matthew Cotton 76bdc5e683
Attempting to add dockerfile for SFU 2023-11-20 14:00:47 +11:00
mcottontensor 0f5e2d9e12
Merge branch 'master' into new_docs 2023-11-17 12:53:10 +11:00
Matthew Cotton 1aad4a6e58
Adding info about simulcast streaming from UE 2023-11-17 12:49:52 +11:00
Matthew Cotton 65ebcfe03e
Adding SFU docs. 2023-11-17 11:16:08 +11:00
Matthew Cotton d5efa38acf
Fixing readme filename. Maybe? 2023-11-17 10:28:18 +11:00
mcottontensor 7d3a6b64c4
Delete SignallingWebServer/Readme.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-11-17 10:25:48 +11:00
Matthew Cotton 32d6e2b0b1
Updating main doc to link to signalling docs 2023-11-17 10:23:35 +11:00
Matthew Cotton 7f54018320
Adding some new documentation for signalling 2023-11-17 10:22:29 +11:00
William Belcher 5bea564755
Update platform scripts so that the BASH_LOCATION works on Mac as well (#428) 2023-11-16 16:19:40 +10:00
mcottontensor 7320398ef3
Merge pull request #427 from mcottontensor/legacynamefix
Fixing missed function rename.
2023-11-15 11:42:00 +11:00
Matthew Cotton 082284b6e6
Fixing missed function rename. 2023-11-15 11:39:56 +11:00
mcottontensor a7afbc3d0c
Merge pull request #425 from mcottontensor/initial_bitrates
Bitrate negotiation on stream startup
2023-11-14 08:49:22 +11:00
Matthew Cotton ffcf7b4b3a
Typo 2023-11-10 16:23:01 +11:00
Matthew Cotton bbf812b9c2
More shuffling. 2023-11-10 16:09:00 +11:00
Matthew Cotton 8847ee7440
Small cleanup. 2023-11-10 15:49:57 +11:00
Matthew Cotton 72ebc33558
- Adding support for requesting min/max bitrates on initial negotiation
(offer/answer) from the player
- Fixing bitrate values units and parsing.
2023-11-09 11:01:30 +11:00
mcottontensor edef2915ee
Merge pull request #420 from mcottontensor/ps_expose
Exposing the pixelstreaming interface to the browser.
2023-11-02 12:43:10 +11:00
mcottontensor 1e051866c1
Merge pull request #419 from mcottontensor/fix_reconnect_flow
Rewriting a bunch of reconnect and disconnect handling.
2023-11-02 12:26:18 +11:00
mcottontensor 458e8aa9cb
Merge branch 'master' into fix_reconnect_flow 2023-11-02 09:27:34 +11:00
mcottontensor ea7b1ea030
Merge branch 'master' into ps_expose 2023-11-02 09:27:13 +11:00
Matthew Cotton 9cb4d2c572
Exposing the pixelstreaming interface to the browser. This allows automation to directly interact with the pixelstreaming features for testing etc. 2023-11-02 09:22:24 +11:00
mcottontensor 5cffec3b42
Merge pull request #414 from mcottontensor/remove_login
Removing authentication features.
2023-11-02 09:13:35 +11:00
Matthew Cotton ac6450fbbd
A few small tweaks to text and some comments. 2023-11-01 16:58:17 +11:00
Matthew Cotton 449079871c
Little name cleanup for ease of use 2023-11-01 16:48:08 +11:00
mcottontensor 3af6bff71b
Merge branch 'master' into remove_login 2023-11-01 13:29:06 +11:00
Matthew Cotton 84c8b96a66
Rewriting a bunch of reconnect and disconnect handling. Fixes #401 2023-11-01 13:16:56 +11:00
mcottontensor 44d6c4c829
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-11-01 10:35:34 +11:00
Matthew Cotton 912265a6f8
Updating frontend library versions 2023-11-01 10:34:12 +11:00
Matthew Cotton 537acc2476
Updating package lock 2023-11-01 10:33:27 +11:00
Matthew Cotton c78be0404c
Updating frontend library versions 2023-11-01 10:32:46 +11:00
mcottontensor 41e7029e0c
Update package.json
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-11-01 10:30:44 +11:00
mcottontensor e90a685096
Merge pull request #417 from EpicGames/master
Merging master into 5.4
2023-11-01 10:29:09 +11:00
mcottontensor da0a871234
Merge branch 'UE5.4' into master 2023-11-01 10:26:11 +11:00
mcottontensor b16bb6c75c
Merge pull request #416 from EpicGames/backport/UE5.4/pr-411
[UE5.4] Merge pull request #411 from mcottontensor/streamer_ids_fix
2023-11-01 10:05:25 +11:00
Matthew Cotton 22de24e61a Fixing sfu forwarding.
(cherry picked from commit 7f07f4b29e)
2023-10-31 22:57:16 +00:00
Matthew Cotton fdb6d6d8a0 Catching case where we're sanitizing a streamer id that is numeric. Updating docs to remove PreferSFU (SFU is just selected as a streamer now).
(cherry picked from commit 339aa088cc)
2023-10-31 22:57:16 +00:00
Matthew Cotton 3d7bfb0723 Updating the handling of generating new legacy streamer and sfu ids.
(cherry picked from commit 403fe39f4b)
2023-10-31 22:57:16 +00:00
Matthew Cotton 63f8a320e1 Cleanup and fixing sfu behaviour.
(cherry picked from commit adfca6c42d)
2023-10-31 22:57:16 +00:00
Matthew Cotton 78d68a8a8b Removing PreferSFU option since this is now handled with the stream selection option. Fixing browser behaviour when multiple streamers detected (previous failed tests).
(cherry picked from commit bbcfe8a6b5)
2023-10-31 22:57:16 +00:00
Matthew Cotton e88871c226 Just some small cleanup
(cherry picked from commit 2ce53023ee)
2023-10-31 22:57:16 +00:00
Matthew Cotton 48b256753a Fixing the windows build script nuking the PATH env variable.
(cherry picked from commit 090cc89b08)
2023-10-31 22:57:16 +00:00
Matthew Cotton ddb4c4776e Allowing SFU to work with multiple streamers.
(cherry picked from commit c0e715ca9d)
2023-10-31 22:57:16 +00:00
Matthew Cotton f8de08ab61 working on handling multiple sfus gracefully
(cherry picked from commit 01d8056bee)
2023-10-31 22:57:16 +00:00
Matthew Cotton 1e5d075d5f Better handling of streamer ids. Specifically legacy ids.
(cherry picked from commit 127feac2e4)
2023-10-31 22:57:16 +00:00
mcottontensor 25024f6848
Merge pull request #411 from mcottontensor/streamer_ids_fix
Fixes for Streamers changing IDs when connecting & Updates to SFU behaviour relating to multi streamer changes.
2023-11-01 09:56:47 +11:00
Matthew Cotton 7f07f4b29e
Fixing sfu forwarding. 2023-10-31 12:54:41 +11:00
Luke Bermingham f2cde5176a
Update link to frontend docs to be /frontend
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-10-31 09:07:28 +10:00
Luke Bermingham 5c65721da3
Update link to frontend docs to go to /frontend
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-10-31 09:05:57 +10:00
Matthew Cotton ea74d91658
Removing authentication features. 2023-10-31 09:44:41 +11:00
mcottontensor b97dcb11cd
Merge pull request #410 from timbotimbo/faketouch-ui
[Frontend] Fix faketouch capturing touches on UI.
2023-10-31 09:28:19 +11:00
Matthew Cotton 339aa088cc
Catching case where we're sanitizing a streamer id that is numeric. Updating docs to remove PreferSFU (SFU is just selected as a streamer now). 2023-10-31 09:17:26 +11:00
Matthew Cotton 403fe39f4b
Updating the handling of generating new legacy streamer and sfu ids. 2023-10-30 16:52:26 +11:00
Matthew Cotton adfca6c42d
Cleanup and fixing sfu behaviour. 2023-10-27 15:15:41 +11:00
Matthew Cotton bbcfe8a6b5
Removing PreferSFU option since this is now handled with the stream selection option. Fixing browser behaviour when multiple streamers detected (previous failed tests). 2023-10-26 10:01:31 +11:00
Matthew Cotton 2ce53023ee
Just some small cleanup 2023-10-25 11:59:45 +11:00
Matthew Cotton 090cc89b08
Fixing the windows build script nuking the PATH env variable. 2023-10-25 11:50:33 +11:00
Matthew Cotton c0e715ca9d
Allowing SFU to work with multiple streamers. 2023-10-25 11:49:55 +11:00
Matthew Cotton 01d8056bee
working on handling multiple sfus gracefully 2023-10-24 15:01:34 +11:00
Matthew Cotton 127feac2e4
Better handling of streamer ids. Specifically legacy ids. 2023-10-24 11:42:30 +11:00
timbotimbo 1478eceb9b
Fix faketouch capturing touches on UI.
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
2023-10-23 13:46:50 +02:00
mcottontensor d8007a3530
Merge pull request #409 from EpicGames/backport/UE5.4/pr-381
[UE5.4] Merge pull request #381 from New-Game-Plus/fix-video-autoplay
2023-10-23 15:35:18 +11:00
Bramford Horton 23eb2601e1 Fix/allow video autoplay without click
(cherry picked from commit 75cd975400)
2023-10-23 03:32:47 +00:00
mcottontensor 52f8a17e48
Merge pull request #381 from New-Game-Plus/fix-video-autoplay
Fix/allow video autoplay without click
2023-10-23 14:32:22 +11:00
mcottontensor ac6cafae85
Merge pull request #406 from EpicGames/backport/UE5.4/pr-403
[UE5.4] Merge pull request #403 from mcottontensor/mm_linux_fix
2023-10-23 14:13:21 +11:00
Matthew Cotton df2ef8ba04 Small fix to allow the matchmaker start scripts to find the custom install of node.
(cherry picked from commit c76284041e)
2023-10-23 03:04:14 +00:00
mcottontensor 8a6a5bbfc5
Merge pull request #403 from mcottontensor/mm_linux_fix
Allowing the Matchmaker to run on linux.
2023-10-23 14:03:47 +11:00
Matthew Cotton c76284041e
Small fix to allow the matchmaker start scripts to find the custom install of node. 2023-10-23 11:29:27 +11:00
William Belcher 2a21ee6566
Ensure that we have a non-null codecId when we try to update the preferred codec (#400) 2023-10-19 16:17:37 +10:00
William Belcher bf6dcade68
Update SignallingWebServer bash platform scripts to default to Linux (#399) 2023-10-19 14:55:10 +10:00
William Belcher ee82bd398c
Update SignallingWebServer platform scripts to support Mac (#389)
* Update SignallingWebServer platform scripts to support Mac x86_64 and Arm64

* Update bash scripts to default to Linux

* Update coturn URLs to use the binaries provided by the PixelStreamingInfrastructure
2023-10-19 14:40:52 +10:00
github-actions[bot] 952b309c71
Expose JSS InsertionPoint (#397)
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
(cherry picked from commit 8ba410154d)

Co-authored-by: timbotimbo <timbotimbo@users.noreply.github.com>
2023-10-19 10:48:19 +10:00
timbotimbo 8ba410154d
Expose JSS InsertionPoint (#390)
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-10-19 10:46:40 +10:00
github-actions[bot] 16d80e27e1
Handle statsPanel or settingsPanel being undefined. (#394)
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
(cherry picked from commit af5339bec8)

Co-authored-by: timbotimbo <timbotimbo@users.noreply.github.com>
2023-10-19 10:44:18 +10:00
timbotimbo af5339bec8
Handle statsPanel or settingsPanel being undefined. (#392)
Signed-off-by: timbotimbo <timbotimbo@users.noreply.github.com>
2023-10-19 10:42:58 +10:00
github-actions[bot] 1301fde89a
Bump @babel/traverse from 7.21.3 to 7.23.2 in /Frontend/library (#388)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.3 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 81c3f52f84)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-10-17 14:26:44 +10:00
github-actions[bot] ad85b02b5e
Bump postcss from 8.4.21 to 8.4.31 in /Frontend/implementations/react (#386)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.21 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.21...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 55b771e633)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-10-17 14:24:19 +10:00
dependabot[bot] 81c3f52f84
Bump @babel/traverse from 7.21.3 to 7.23.2 in /Frontend/library (#384)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.21.3 to 7.23.2.
- [Release notes](https://github.com/babel/babel/releases)
- [Changelog](https://github.com/babel/babel/blob/main/CHANGELOG.md)
- [Commits](https://github.com/babel/babel/commits/v7.23.2/packages/babel-traverse)

---
updated-dependencies:
- dependency-name: "@babel/traverse"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 14:23:03 +10:00
github-actions[bot] 828123c6c8
Bump postcss in /Frontend/implementations/typescript (#383)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.21 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.21...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
(cherry picked from commit 1a749cea8a)

Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 14:10:42 +10:00
dependabot[bot] 55b771e633
Bump postcss from 8.4.21 to 8.4.31 in /Frontend/implementations/react (#379)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.21 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.21...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 14:09:37 +10:00
dependabot[bot] 1a749cea8a
Bump postcss in /Frontend/implementations/typescript (#380)
Bumps [postcss](https://github.com/postcss/postcss) from 8.4.21 to 8.4.31.
- [Release notes](https://github.com/postcss/postcss/releases)
- [Changelog](https://github.com/postcss/postcss/blob/main/CHANGELOG.md)
- [Commits](https://github.com/postcss/postcss/compare/8.4.21...8.4.31)

---
updated-dependencies:
- dependency-name: postcss
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-10-17 14:07:22 +10:00
Bramford Horton 75cd975400 Fix/allow video autoplay without click 2023-10-10 14:42:38 +13:00
Belchy06 4c3eda6e9b Update coturn install to pull different binaries depending on os arch 2023-10-03 14:45:29 +10:00
Belchy06 20a409526d Update supported architectures 2023-10-03 13:35:37 +10:00
Belchy06 354a97e11d Add Mac support to bash platform scripts 2023-10-03 13:31:16 +10:00
mcottontensor bb388fec27
Merge pull request #374 from rt-nikowiss/master
Fix emitUIInteraction method
2023-09-21 15:47:37 +10:00
rt-nikowiss aa12e8967a
Fix emitUIInteraction method
Signed-off-by: rt-nikowiss <94848689+rt-nikowiss@users.noreply.github.com>
2023-09-18 14:37:42 +02:00
mcottontensor 2902bdc22b
Merge pull request #373 from MWillWallT/master
Fix broken SFU Layer images
2023-09-14 11:29:38 +10:00
Michael Wallace 830e1440b4
Merge branch 'master' into master 2023-09-14 11:26:36 +10:00
MWillWallT e858b809b7 Merge branch 'master' of https://github.com/MWillWallT/PixelStreamingInfrastructure 2023-09-14 11:24:01 +10:00
MWillWallT fef026bfad Fix broken images 2023-09-14 11:23:56 +10:00
github-actions[bot] 3816f4b535
Remove unit conversion for bitrate from URL. URL is already in kbps (#369) (#372)
(cherry picked from commit eb9a665a0a)

Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-09-14 10:47:07 +10:00
William Belcher eb9a665a0a
Remove unit conversion for bitrate from URL. URL is already in kbps (#369) 2023-09-14 10:45:22 +10:00
mcottontensor 55ab66076e
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-13 13:00:50 +10:00
mcottontensor f6d724a3fe
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-13 12:56:26 +10:00
mcottontensor cabf32a879
Touching ui-library to trigger build action.
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-13 12:55:25 +10:00
mcottontensor 24b8082f35
Merge pull request #368 from EpicGames/master
Updating workflows.
2023-09-13 12:53:41 +10:00
mcottontensor f7bde64c42
Merge pull request #367 from mcottontensor/update_workflows
Updating workflows so some can be manually started.
2023-09-13 12:52:17 +10:00
Matthew Cotton 66fc4bc68e
Updating workflows so some can be manually started. 2023-09-13 12:51:39 +10:00
mcottontensor f7c4fd2f3c
Merge pull request #366 from EpicGames/master
Merging in master for some missed 5.3 references.
2023-09-13 12:49:01 +10:00
mcottontensor e2ccbfb28b
Merge pull request #365 from mcottontensor/5.4-fixes
Missed some 5.3 references and updating package-lock
2023-09-13 12:45:24 +10:00
Matthew Cotton bc2e34821b
Missed some 5.3 references and updating package-lock 2023-09-13 12:44:41 +10:00
mcottontensor e6797144d4
Merge pull request #364 from EpicGames/master
Merging in master to generate npm packages.
2023-09-13 12:21:09 +10:00
mcottontensor 6b8f4f6324
Merge pull request #361 from MWillWallT/master
Shift of Matchmaker and SFU pages to Infra
2023-09-13 12:17:46 +10:00
mcottontensor d6b55fccec
Merge branch 'master' into master 2023-09-13 12:17:09 +10:00
mcottontensor 292b75e9f3
Merge pull request #363 from mcottontensor/update_actions
Updated actions to reference 5.4
2023-09-13 12:16:50 +10:00
Matthew Cotton 0cde16d497
Updated actions to reference 5.4 2023-09-13 12:15:34 +10:00
mcottontensor 759cb9ae3f
Merge pull request #362 from mcottontensor/54npmlibs
Updating NPM libs to 5.4
2023-09-13 12:11:44 +10:00
Matthew Cotton 57c895482d
merged in upstream master 2023-09-13 12:07:12 +10:00
Matthew Cotton a0f874bcc0
Updated 5.3 references to 5.4. 2023-09-13 12:02:51 +10:00
MWillWallT e1d0904417 Shift of Matchmaker and SFU pages to Infra 2023-09-13 11:38:34 +10:00
mcottontensor eb5313b734
Merge branch 'UE5.3' into master
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-12 14:46:51 +10:00
mcottontensor 9fd9c0618c
Update README.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-12 14:38:58 +10:00
I-m-None-user 8b25630852
Update Application.ts add check ipad
Signed-off-by: I-m-None-user <122039782+I-m-None-user@users.noreply.github.com>
2023-09-12 14:15:10 +10:00
mcottontensor c21f4c5b97
Merge pull request #342 from I-m-None-user/patch-1
Update Application.ts add check ipad
2023-09-12 13:51:16 +10:00
mcottontensor 3dcc00db4d
Merge branch 'master' into patch-1 2023-09-12 13:50:37 +10:00
Matthew Cotton 2a34f838e2
merged in origin master 2023-09-12 13:49:42 +10:00
mcottontensor 19d1ac8d90
Merge pull request #315 from gingernaz/data_channel_latency_test
Add: DataChannel latency test
2023-09-12 11:18:08 +10:00
mcottontensor 4722f86aab
Merge branch 'master' into data_channel_latency_test
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-09-12 11:16:43 +10:00
mcottontensor 54eb5b73b5
Merge pull request #192 from kass-kass/master
Added ability to mute/unmute mic and enable it later than PixelStreaming creation time
2023-09-12 11:15:21 +10:00
mcottontensor 9e802dde92
Merge branch 'master' into master 2023-09-12 10:58:54 +10:00
Luke Bermingham ca70087ce0
Update CHANGELOG.md
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-12 08:41:07 +10:00
Luke Bermingham 10d61a2ea1
Bump RELEASE_VERSION to 0.0.4
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-12 08:30:28 +10:00
Luke Bermingham 7f8a86435e Change /ui-library version back to 0.0.4 and update package-lock.json 2023-09-12 08:27:19 +10:00
Luke Bermingham 53bf8deece
Bump /ui-library to 0.0.5 in UE5.3
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:37:56 +10:00
Luke Bermingham c0b941acf7
Update publish-ui-library-to-npm.yml
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:36:31 +10:00
Luke Bermingham 301b624806
Lock github action to NodeJS 18.17.0
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:36:08 +10:00
Luke Bermingham 2159bb4272
Update publish-ui-library-to-npm.yml
Lock github action to NodeJS 18.17.0

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:35:06 +10:00
Luke Bermingham dbb54d14eb
Lock NodeJS version to 18.17.0 in Github action
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:33:42 +10:00
Luke Bermingham 75cb711348
Bump /ui-library version to 0.0.4 in 5.3
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:29:59 +10:00
Luke Bermingham a907d2b926
Bump frontend /library version to 0.0.3 in 5.3
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:28:53 +10:00
Luke Bermingham 1468459f93
Update CHANGELOG.md
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-11 22:23:38 +10:00
mcottontensor aeddc8fe74
Merge pull request #358 from mcottontensor/early_reconnect
Auto connect on new streamer
2023-09-11 13:11:44 +10:00
Matthew Cotton 3dc7591f7f
Renamed config parameter 2023-09-11 13:09:16 +10:00
Matthew Cotton 8d0d498310
Exposing retry delay as a configurable value 2023-09-11 12:59:07 +10:00
mcottontensor 0dcef11533
Merge branch 'master' into early_reconnect 2023-09-11 10:42:34 +10:00
Matthew Cotton d8ba9e5e95
Adding better support for auto connect to first available streamer. 2023-09-11 10:31:13 +10:00
Matthew Cotton 24577cdfd8
Revert "Adding the ability to connect automatically when a new streamer joins the signalling server"
This reverts commit bcc6bc7d08.
2023-09-08 13:52:07 +10:00
Matthew Cotton bcc6bc7d08
Adding the ability to connect automatically when a new streamer joins the signalling server 2023-09-08 12:58:41 +10:00
Luke Bermingham 65238c6c47
Added headings to building various pieces of the frontend
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-08 11:53:41 +10:00
Luke Bermingham efcbf7be9f
Added prerequisites step for setting up node dev environment
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-08 11:51:30 +10:00
Matthew Cotton e6093213fc
Merge remote-tracking branch 'upstream/master' 2023-09-08 11:41:14 +10:00
Luke Bermingham fc1c98cd66
Update README.md for building frontend library and implementations
Also added warning about Node version we support for the frontend.

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-09-08 11:39:28 +10:00
William Belcher ff10231cb0
Update CONTRIBUTING.md (#357)
Signed-off-by: William Belcher <william.belcher@xa.epicgames.com>
2023-09-07 13:58:26 +10:00
github-actions[bot] 81e065f84e
Consume the context menu event instead of sending a mouse up (#356)
(cherry picked from commit e4946abba2)

Co-authored-by: Michael Stopa <michael.stopa@xa.epicgames.com>
2023-09-04 15:07:12 +10:00
Michael Stopa 6e14dbb34b
Merge pull request #354 from StomyPX/no_context_event
Consume the context menu event instead of sending a mouse up
2023-09-04 14:28:20 +09:30
Michael Stopa e4946abba2
Consume the context menu event instead of sending a mouse up 2023-09-04 12:45:01 +09:30
Matthew Cotton 081b66b25d
dont want these anymore 2023-09-04 12:18:16 +10:00
Matthew Cotton b158ebdada
Does this one work?? 2023-09-04 11:40:33 +10:00
Matthew Cotton b6f63fc30e
I dont understand why schedule isnt working 2023-09-04 11:37:38 +10:00
Matthew Cotton d1afc80bba
bad formatting maybe? 2023-09-04 11:32:30 +10:00
Matthew Cotton 7368039b50
Maybe this will work 2023-09-04 11:29:03 +10:00
Matthew Cotton 33b675f09b
Adding scheduled test to master 2023-09-04 11:17:47 +10:00
Matthew Cotton 1c7ecb67aa
Merge branch 'data_channel_latency_test' of github.com:gingernaz/PixelStreamingInfrastructure into naz-data-channel-latency-test 2023-08-31 16:06:03 +10:00
Matthew Cotton ae7861a69f
Removing empty file left over from merge conflict. 2023-08-31 16:05:43 +10:00
mcottontensor d319891abb
Merge branch 'master' into data_channel_latency_test 2023-08-31 16:02:43 +10:00
Matthew Cotton b3c5c82d25
Merged in master and resolved conflicts. 2023-08-31 15:59:13 +10:00
mcottontensor 6b742d3577
Merge pull request #211 from kasp1/master
New matchmaker queue screen with easy customization
2023-08-31 15:34:41 +10:00
Matthew Cotton 22489b6e1e
Merge remote-tracking branch 'origin/master' into kasp1-matchmaker-queue 2023-08-31 14:33:19 +10:00
Matthew Cotton 158ca0a909
Fixing missing import 2023-08-31 13:58:51 +10:00
Matthew Cotton 4806a96bf2
Resolving conflicts with main 2023-08-31 13:54:02 +10:00
Matthew Cotton ce3bf3e080
Merge remote-tracking branch 'upstream/master' 2023-08-31 12:48:28 +10:00
Luke Bermingham 19438d8654
Update README.md
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-08-25 08:55:36 +10:00
Luke Bermingham b0294701d5
Update README.md
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-08-25 08:53:33 +10:00
Denis Phoenix 21abd3892d
Add contribution guideline `CONTRIBUTING.md` (#352)
* Added CONTRIBUTING.md
2023-08-24 16:39:21 +10:00
mcottontensor 2b73af42f7
Merge branch 'EpicGames:master' into master 2023-08-01 10:48:26 +10:00
I-m-None-user 2ff5a8aa0f
Update Application.ts add check ipad
Signed-off-by: I-m-None-user <122039782+I-m-None-user@users.noreply.github.com>
2023-07-31 14:42:44 +02:00
William Belcher 20dd81f606
Update LatencyTest handler to accept data (#340) 2023-07-27 17:09:06 +10:00
William Belcher 5b250b7148
Refactor SignallingWebServer to a single docker file (#337) for UE5.3 (#339) 2023-07-27 16:41:26 +10:00
William Belcher 6051ea52fc
Refactor SignallingWebServer to a single docker file (#337) for UE5.2 (#338) 2023-07-27 16:41:15 +10:00
William Belcher 1373f41257
Add: Protocol structures can now contain strings (#336)
* Modify message struct: no need for byteLength; strings are now supported as a type

* Remove TwoWayMap as it's no longer needed. Add getter for streamer handlers

* Fix keyup sending too many args

* Update log message to print js types. Update default protocol

* Register handler for TextboxEntry. Add check to make sure handler is defined when registering for a fromStreamer message

* Remove unncessary import from player.ts

* Update data type to reflect that it could contain strings
2023-07-27 16:03:11 +10:00
William Belcher 4078871c1c
Remove bash specific dockerfile in favour of using the platform agnostic version in /SignallingWebServer (#337) 2023-07-27 15:47:44 +10:00
github-actions[bot] 5fcd53614e
Properly inject new params into SDP to get stereo back on Chrome (#332) 2023-07-27 10:08:43 +10:00
github-actions[bot] 333c5fbab8
Properly inject new params into SDP to get stereo back on Chrome (#332) 2023-07-27 10:07:09 +10:00
Michael Stopa 11387d642a
Have matchmaker ask for authentication instead of EACCES (#333) 2023-07-27 10:04:17 +10:00
Michael Stopa 1947760e2b
Properly inject new params into SDP to get stereo back on Chrome (#332) 2023-07-27 10:02:26 +10:00
Michael Stopa 7ca3114698
Bump Node.js to latest LTS (#321) 2023-07-27 09:52:01 +10:00
mcottontensor f20b38bb30
Delete run-test.yml
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-07-25 11:45:43 +10:00
mcottontensor c6bfe08766
Create run-test.yml
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-07-25 11:35:47 +10:00
dependabot[bot] 5f7ebe1471
Bump word-wrap from 1.2.3 to 1.2.5 in /Frontend/ui-library (#327)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.5.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.5)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 13:32:52 +10:00
dependabot[bot] 42dedc698b
Bump word-wrap from 1.2.3 to 1.2.4 in /Frontend/library (#320)
Bumps [word-wrap](https://github.com/jonschlinkert/word-wrap) from 1.2.3 to 1.2.4.
- [Release notes](https://github.com/jonschlinkert/word-wrap/releases)
- [Commits](https://github.com/jonschlinkert/word-wrap/compare/1.2.3...1.2.4)

---
updated-dependencies:
- dependency-name: word-wrap
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 13:31:10 +10:00
dependabot[bot] bc845a0d99
Bump tough-cookie from 4.1.2 to 4.1.3 in /Frontend/library (#290)
Bumps [tough-cookie](https://github.com/salesforce/tough-cookie) from 4.1.2 to 4.1.3.
- [Release notes](https://github.com/salesforce/tough-cookie/releases)
- [Changelog](https://github.com/salesforce/tough-cookie/blob/master/CHANGELOG.md)
- [Commits](https://github.com/salesforce/tough-cookie/compare/v4.1.2...v4.1.3)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-07-24 13:30:48 +10:00
Joel-Patteson af6fc4bd18
Fix TypeError: console.warning is not a function (#326)
Co-authored-by: Joel Patteson <joelpatteson7@gmail.com>
2023-07-22 21:51:44 +10:00
Joel-Patteson b3f966bc8e
Fix TypeError: console.warning is not a function (#325)
Co-authored-by: Joel Patteson <joelpatteson7@gmail.com>
2023-07-22 21:43:18 +10:00
github-actions[bot] aa13c254fd
Ensure touch is relative to absolute location of parent rect (#316)
(cherry picked from commit 4e370e5439)

Co-authored-by: Michael Stopa <michael.stopa@xa.epicgames.com>
2023-07-19 15:24:16 +10:00
github-actions[bot] 8914e616db
Ensure touch is relative to absolute location of parent rect (#316)
(cherry picked from commit 4e370e5439)

Co-authored-by: Michael Stopa <michael.stopa@xa.epicgames.com>
2023-07-19 15:24:01 +10:00
Michael Stopa 4e370e5439
Ensure touch is relative to absolute location of parent rect (#316) 2023-07-19 15:23:18 +10:00
Nazar Rudenko 2a952a11b3
Friendly output instead of NaN if UE doesn't support the test 2023-07-19 10:39:06 +10:00
Nazar Rudenko 930c396aeb
Add: DataChannelLatencyTest 2023-07-19 10:13:17 +10:00
Mirek Kaspar c6c3e4cd87 fixed html template of the matchmaker queue screen 2023-07-18 10:11:13 +03:00
Mirek Kaspar 80d165950f Merge https://github.com/EpicGames/PixelStreamingInfrastructure 2023-07-18 10:08:09 +03:00
github-actions[bot] 2dea212048
Rename implementations/EpicGames to implementations/typescript (#177)
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
(cherry picked from commit d92e46e301)

Co-authored-by: gunsha <gonzaller@gmail.com>
2023-07-18 16:33:06 +10:00
gunsha d92e46e301
Rename implementations/EpicGames to implementations/typescript (#177)
Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 16:32:02 +10:00
github-actions[bot] 149e526360
Fix: Firefox console errors `TypeError: this.preferredCodec.split is not a function` (#310) (#313)
* Fix select codec on Firefox

* Restore indentation in cirrus

(cherry picked from commit 503b565bc5)

Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 15:32:43 +10:00
github-actions[bot] 3bcffb2b68
Fix: Firefox console errors `TypeError: this.preferredCodec.split is not a function` (#310) (#312)
* Fix select codec on Firefox

* Restore indentation in cirrus

(cherry picked from commit 503b565bc5)

Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 15:32:30 +10:00
William Belcher 503b565bc5
Fix: Firefox console errors `TypeError: this.preferredCodec.split is not a function` (#310)
* Fix select codec on Firefox

* Restore indentation in cirrus
2023-07-18 14:48:42 +10:00
github-actions[bot] 6852ed39c0
Show player count in stats panel (#303)
(cherry picked from commit 6bdbf509eb)

Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 14:32:51 +10:00
github-actions[bot] 9598623648
Show player count in stats panel (#303)
(cherry picked from commit 6bdbf509eb)

Co-authored-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 14:32:28 +10:00
William Belcher d5d8db1bd9
Add .backportrc.json to enable auto merging of backport PRs
Signed-off-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 14:31:26 +10:00
William Belcher 2ad3674a56
Update stale message on Issues and PRs
Signed-off-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 14:06:54 +10:00
William Belcher 6bdbf509eb
Show player count in stats panel (#303) 2023-07-18 12:04:18 +10:00
mcottontensor 4124bb759f
Update stale.yml
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-07-18 11:27:50 +10:00
mcottontensor 8646e47653
Merge pull request #306 from Belchy06/stale
Update stale workflow to also auto close stale issues and PRs
2023-07-18 11:23:16 +10:00
William Belcher 10d6cd699c
update stale workflow to also auto close stale issues and PRs 2023-07-18 11:17:59 +10:00
William Belcher fc4872f464
Update stale.yml to include manual trigger (#305)
Signed-off-by: William Belcher <william.belcher@xa.epicgames.com>
2023-07-18 10:53:32 +10:00
William Belcher 1e11c6a78d
Add github action for PR and Issue management (#304)
* Add stale action for issues/PRs that are inactive for 30 days
2023-07-18 10:37:59 +10:00
mcottontensor d6ee7301e7
Merge pull request #288 from EpicGames/mcottontensor-patch-1
Update SignallingProtocol.md
2023-07-07 14:10:58 +10:00
mcottontensor f56cb1089f
Update SignallingProtocol.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-07-07 10:47:11 +10:00
mcottontensor f5993e7f5c
Merge pull request #271 from mcottontensor/ss_message_doc
Signaling message reference doc
2023-06-29 15:35:06 +10:00
mcottontensor 5be8187e71
Merge branch 'master' into ss_message_doc 2023-06-29 15:34:54 +10:00
mcottontensor 36631072a3
Merge pull request #285 from mcottontensor/fix_autoconnect
Fixing auto reconnect to not reconnect when the page is refreshed.
2023-06-29 15:34:19 +10:00
Matthew Cotton 530cf9e804 Merge branch 'fix_autoconnect' of github.com:mcottontensor/PixelStreamingInfrastructure into fix_autoconnect 2023-06-29 15:20:25 +10:00
Matthew Cotton 6c20889572 A little bit more context for the change
Signed-off-by: Matthew Cotton <matt@tensorworks.com.au>
2023-06-29 15:20:02 +10:00
Matthew Cotton c24549366d A little bit more context for the change 2023-06-29 15:05:50 +10:00
Matthew Cotton c4d6ddb204 Removing debug prints 2023-06-29 14:48:57 +10:00
Matthew Cotton 3a480aa540 Only reconnecting when the close event is not a locally initiated close event 2023-06-29 14:32:40 +10:00
Matthew Cotton 1f3644eff7 Bump release version 2023-06-21 11:31:53 +10:00
Matthew Cotton 039354b151 Bump ui-library version 2023-06-21 11:31:23 +10:00
Matthew Cotton 8d6ebc6910 Bump library version 2023-06-21 11:29:39 +10:00
mcottontensor 0fd71b6887 Merge pull request #273 from jibranabsarulislam/jibranabsarulislam/add-CRD-events
Include create, reconnect, and update events (with associated tests)
2023-06-21 11:28:52 +10:00
Matthew Cotton 4b5660cd0c Bump release version 2023-06-21 11:28:06 +10:00
Matthew Cotton 31d363455c Bump ui-library version 2023-06-21 11:26:51 +10:00
Matthew Cotton a6eb05993b Bump library version 2023-06-21 11:23:46 +10:00
mcottontensor bfd1e66973 Merge pull request #273 from jibranabsarulislam/jibranabsarulislam/add-CRD-events
Include create, reconnect, and update events (with associated tests)
2023-06-21 11:08:08 +10:00
mcottontensor f1edea5fd9
Merge pull request #273 from jibranabsarulislam/jibranabsarulislam/add-CRD-events
Include create, reconnect, and update events (with associated tests)
2023-06-21 10:28:10 +10:00
Matthew Cotton fd41a63c22 Updating reconnect test 2023-06-21 10:23:43 +10:00
Matthew Cotton daf9a3fd35 Adding version to the signalling doc 2023-06-21 10:01:52 +10:00
Matthew Cotton 551c399555 Renamed the protocol document 2023-06-20 14:38:36 +10:00
Matthew Cotton 6d33562d4c Adding root readme 2023-06-20 14:37:21 +10:00
mcottontensor 69f8c7befb
Merge branch 'master' into ss_message_doc 2023-06-20 14:32:48 +10:00
Matthew Cotton a4362d52c2 Adding small note about legacy streamer ids 2023-06-20 14:31:25 +10:00
mcottontensor 21580b2dba
Merge branch 'master' into jibranabsarulislam/add-CRD-events 2023-06-20 13:44:25 +10:00
mcottontensor ab4bd67ffe
Update backport.yml
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-06-20 13:41:39 +10:00
mcottontensor 430da8f576
Create backport.yml
Attempting to add auto backport action.

Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-06-20 13:40:56 +10:00
Matthew Cotton c28b466385 Adding an example sequence diagram for a typical streaming session 2023-06-20 12:09:58 +10:00
Matthew Cotton 71598b4503 Adding some extra comments on some messages. 2023-06-19 13:02:25 +10:00
Matthew Cotton 338c22e26b Updating signalling messages doc 2023-06-19 12:07:53 +10:00
Matthew Cotton fc3af1dcdd updating references with some extra formatting 2023-06-19 10:34:46 +10:00
jayway 715ae99127
Merge branch 'EpicGames:master' into jibranabsarulislam/add-CRD-events 2023-06-16 03:25:05 -04:00
Jibran Absarulislam 276e956808 keep import consistent with rest of delcarations 2023-06-16 03:21:25 -04:00
Jibran Absarulislam bb202813a6 refactor using Pre to clarify when the event fires 2023-06-16 03:20:34 -04:00
Luke Bermingham a0fd9e6b83
Merge pull request #274 from Belchy06/UE5.3
Fix iOS touch in some cases when setting panel is open
2023-06-16 16:24:02 +10:00
jibranabsarulislam 6445f36bdf add event emitters to methods with accompanying tests 2023-06-16 01:40:06 -04:00
jibranabsarulislam c7ec8822dc create & export connect, reconnect, and disconnect classes and types 2023-06-16 01:39:39 -04:00
Luke Bermingham 6214829ec1
Shorten frontend ui lib action name
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-16 15:04:46 +10:00
Luke Bermingham 18d0a7b3c9
Shorten action name for publishing npm lib
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-16 15:03:56 +10:00
William Belcher 0197bc788d
Mobile QOL improvements. Fix scolling on long panels as well as css attributes not respecting the webkit prefix 2023-06-16 15:00:56 +10:00
Matthew Cotton 001170f0e2 Adding some signaling message documentation 2023-06-16 12:19:09 +10:00
Matthew Cotton 900f45ce4d Revert "Adding some documentation for signaling messages"
This reverts commit 322fc69206.
2023-06-16 12:17:23 +10:00
Matthew Cotton daa4024dac Revert "Separating out parts of cirrus into modules to clean up the code a little"
This reverts commit c89193e46d.
2023-06-16 12:13:46 +10:00
Matthew Cotton 322fc69206 Adding some documentation for signaling messages 2023-06-16 12:01:23 +10:00
Matthew Cotton c89193e46d Separating out parts of cirrus into modules to clean up the code a little 2023-06-14 13:43:32 +10:00
Luke Bermingham 357a665994
Update RELEASE_VERSION to 0.0.2 to include iOS fullscreen fix
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-14 13:02:59 +10:00
Luke Bermingham d9dfa12b62 Bumped ui library to 0.0.2 to include iOS fullscreen fix 2023-06-14 13:01:18 +10:00
Luke Bermingham e7cd55a303
Update RELEASE_VERSION to 0.6.4 to include iOS fullscreen fix
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-14 12:46:05 +10:00
Luke Bermingham 63227f6b1c Upgraded ui library version to 0.4.3 as part of iOS fix 2023-06-14 12:44:24 +10:00
Luke Bermingham 124fc6658d
Merge pull request #268 from Belchy06/UE5.3
Bring BR 266 to 5.3
2023-06-12 16:53:51 +10:00
William Belcher 6ec23ebbb2
Re-enable iOS and iPadOS fullscreen. Additionaly, only use the native…
… webplayer in iOS
2023-06-12 16:51:51 +10:00
Luke Bermingham 21f5685ae7
Merge pull request #267 from Belchy06/UE5.2
Bring PR 266 to 5.2
2023-06-12 16:50:49 +10:00
Luke Bermingham 9554d031e3
Shorten action name for pushing cirrus container images
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 16:47:24 +10:00
Luke Bermingham c7a2147be6
Update README.md (#265)
Added Github action badges to readme.md for build health.

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 16:45:34 +10:00
William Belcher 5811f32d1c
Re-enable iOS and iPadOS fullscreen. Additionaly, only use the native…
… webplayer in iOS
2023-06-12 16:44:05 +10:00
William Belcher d95c0012df
Re-enable iOS and iPadOS fullscreen. Additionaly, only use the native webplayer in iOS. (#266) 2023-06-12 16:40:05 +10:00
Luke Bermingham 39fda9bb37
Merge pull request #264 from EpicGames/UE5.3
Bring 5.3 changes to master
2023-06-12 16:09:24 +10:00
Luke Bermingham 23f3e7065a
Reset UE5.3 RELEASE_VERSION to 0.0.1
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 15:56:19 +10:00
Luke Bermingham 4b47f93b4a
Force Github release 0.0.2 on UE5.3
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 15:51:23 +10:00
Luke Bermingham 0cf54307c9
Force Github release on UE5.3 branch
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 15:48:25 +10:00
Luke Bermingham dd1e88e902
Force ui-library rebuild.
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 15:43:20 +10:00
Luke Bermingham 97f6f5987b Updated ui library package-lock.json to include frontend 5.3 2023-06-12 15:35:53 +10:00
Luke Bermingham fa1eb9631b Update package-lock.json for ui library to have 5.3 frontend lib. 2023-06-12 15:33:04 +10:00
Luke Bermingham 707a0eae2b
Merge pull request #263 from EpicGames/master
Bring 5.3 up to date with master
2023-06-12 15:20:27 +10:00
Luke Bermingham 464e8a0c37
Upgrade 5.2 to 5.3 in libraries, docs, log messages, build pipelines (#262)
* Updated github actions to work on UE5.3 branch and reset release version to 0.0.1 for the UE5.3 branch.

* Update bug report template to include UE5.X prefix.

* Refactored frontend deps to move from 5.2 to 5.3

* Update container-images Github action to use 5.3 tag

* Bump 5.2 t 5.3 in various docs and log strings.
2023-06-12 15:06:53 +10:00
Luke Bermingham 321abc4762 Bump 5.2 t 5.3 in various docs and log strings. 2023-06-12 14:56:26 +10:00
Luke Bermingham 4ee6c7c0e5 Update container-images Github action to use 5.3 tag 2023-06-12 14:50:58 +10:00
Luke Bermingham 9fc6dbcab0 Refactored frontend deps to move from 5.2 to 5.3 2023-06-12 14:44:15 +10:00
Luke Bermingham 516b3245b8 Update bug report template to include UE5.X prefix. 2023-06-12 11:48:17 +10:00
Luke Bermingham 8f137ec537 Updated github actions to work on UE5.3 branch and reset release version to 0.0.1 for the UE5.3 branch. 2023-06-12 11:43:07 +10:00
Luke Bermingham 32873a4a55
Update CHANGELOG.md
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 10:56:33 +10:00
Luke Bermingham 778e749b5a
Update CHANGELOG.md
- Added 5.2 changelog items 
- Added a new section for 5.3 changelog (coming soon)

Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-06-12 10:55:17 +10:00
mcottontensor 7625da4647
Merge pull request #261 from EpicGames/UE5.2
Merging 5.2 changes.
2023-06-09 09:28:33 +10:00
mcottontensor d587558dd8
Merge pull request #260 from EpicGames/mcottontensor-patch-1
Update RELEASE_VERSION
2023-06-09 09:20:46 +10:00
mcottontensor 4415468127
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-06-09 09:19:32 +10:00
Matthew Cotton dfee2a8756 Updating ui-library version and deps 2023-06-09 09:15:39 +10:00
mcottontensor 099c060998
Update package.json
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-06-09 09:05:25 +10:00
mcottontensor 8a4c6b1865
Merge pull request #259 from EpicGames/master
Main merge
2023-06-09 09:03:12 +10:00
Michael Wallace 83e21b5e6d
New general docs page/ToC + new security page. (#254)
* New security tips page.
* Update README.md with docs links
* Linked tickets for TO DO docs pages in readme.md
---------

Signed-off-by: Michael Wallace <90592038+MWillWallT@users.noreply.github.com>
2023-06-09 08:56:43 +10:00
mcottontensor 5202ef6136
Merge pull request #253 from StomyPX/logging_adjustments
Changed forwarded logs to Cyan, added warning for missing playerId
2023-06-08 11:01:15 +10:00
Michael Stopa d62e326019
Changed forwarded logs to Cyan, added warning for missing playerId 2023-06-07 12:11:08 +09:30
mcottontensor 8b9c41b401
Update README.md
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-06-06 17:15:24 +10:00
mcottontensor 323481ec69
Small update to README (#248)
* Adding small note to README to note that the container images require you to be part of Epics github org. As suggested in #231
2023-06-06 16:49:41 +10:00
mcottontensor 7732b3283f
Fixing viewport resizing not always working due to improperly calling timer. #239 (#247) 2023-06-06 16:42:01 +10:00
Chris Hassebrook 9c871b5f9e
Added "media-playout" to prevent spam in Aggregated Stats (#232)
* Added "media-playout" to prevent spam in Aggregated Stats

Signed-off-by: Chris Hassebrook <chasse20@gmail.com>
2023-06-06 15:27:38 +10:00
Devraj Gadhvi 9dbe8c1548
added 'stat PixelStreamingGraphs' to showcase frontend #229 (#238)
Co-authored-by: Devraj <idevrajgadhvi@gmail.com>
2023-06-06 15:22:42 +10:00
mcottontensor 25d35772d3
Fixing hovering mouse mode set in URL being overridden on refresh. (#246)
Fixes: #222
* Fixed the frontend not respecting the url set mouse mode. 
* Note: the initial setting config message can supply true or false for the hover mode and it should be respected. Only when it's omitted should the URL take control.
2023-06-06 15:14:50 +10:00
mcottontensor 556d5012c0
Fixing matchmaker directing users to HTTP when the signalling server is using HTTPS. (#245)
Fixes https://github.com/EpicGames/PixelStreamingInfrastructure/issues/207
2023-06-06 14:57:22 +10:00
mcottontensor 9add4d6310
Merge pull request #244 from EpicGames/dependabot/npm_and_yarn/Matchmaker/socket.io-parser-4.2.4
Bump socket.io-parser from 4.2.2 to 4.2.4 in /Matchmaker
2023-06-06 09:50:46 +10:00
dependabot[bot] 4534adc9dd
Bump socket.io-parser from 4.2.2 to 4.2.4 in /Matchmaker
Bumps [socket.io-parser](https://github.com/socketio/socket.io-parser) from 4.2.2 to 4.2.4.
- [Release notes](https://github.com/socketio/socket.io-parser/releases)
- [Changelog](https://github.com/socketio/socket.io-parser/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/socket.io-parser/compare/4.2.2...4.2.4)

---
updated-dependencies:
- dependency-name: socket.io-parser
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-06-05 06:08:35 +00:00
mcottontensor af29daf208
Merge pull request #243 from EpicGames/UE5.2
Ue5.2
2023-06-05 16:04:25 +10:00
Matthew Cotton c8868c7a7b Fixing some visibility issues on ui buttons due to their config. Fixes #205 2023-06-05 16:00:15 +10:00
DenisTensorWorks 896fc5c1e5
Adding microphone feature documentation UE5.2 (#228)
Moved docs for mic feature from main to 5.2 branch
2023-05-15 11:44:23 +10:00
Luke Bermingham ef222fb5f4
Merge pull request #224 from EpicGames/master
Update readme.md for frontend settings and TURN not support for full local setup
2023-05-12 11:31:17 +10:00
DenisTensorWorks eea7839f51
Signalling Server readme updates (#223)
Update README.md in platform_scripts to mention TURN server is not support for running locally.
2023-05-12 11:28:06 +10:00
Luke Bermingham c4890de826
Update README.md to include settings panel
Signed-off-by: Luke Bermingham <1215582+lukehb@users.noreply.github.com>
2023-05-08 10:53:48 +10:00
mcottontensor 6b12e0e6ed
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-05-05 09:09:06 +10:00
mcottontensor ed0b788b9d
Merge pull request #220 from EpicGames/master
Merging in security update from master
2023-05-05 09:07:11 +10:00
mcottontensor 1b16e15afc
Merge pull request #218 from EpicGames/dependabot/npm_and_yarn/Matchmaker/engine.io-6.4.2
Bump engine.io from 6.4.0 to 6.4.2 in /Matchmaker
2023-05-05 09:04:55 +10:00
dependabot[bot] 13b63c9d54
Bump engine.io from 6.4.0 to 6.4.2 in /Matchmaker
Bumps [engine.io](https://github.com/socketio/engine.io) from 6.4.0 to 6.4.2.
- [Release notes](https://github.com/socketio/engine.io/releases)
- [Changelog](https://github.com/socketio/engine.io/blob/main/CHANGELOG.md)
- [Commits](https://github.com/socketio/engine.io/compare/6.4.0...6.4.2)

---
updated-dependencies:
- dependency-name: engine.io
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
2023-05-04 01:30:55 +00:00
mcottontensor 4769b8c698
Merge pull request #217 from EpicGames/UE5.2
Merging changes back from 5.2
2023-05-03 12:56:37 +10:00
mcottontensor a5704855ca
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-05-03 12:51:33 +10:00
Matthew Cotton 7959929893 Updating package version 2023-05-03 12:48:21 +10:00
mcottontensor 3076ea6a62
Update package.json
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-05-03 12:40:19 +10:00
mcottontensor 1e6baa4076
Merge pull request #216 from EpicGames/master
Bringing master changes to 5.2
2023-05-03 12:34:54 +10:00
mcottontensor 79a1de63ef
Merge pull request #215 from Belchy06/issue-203
Fix: Reconnects will be attempted even when a disconnect is triggered by afk timeout
2023-05-03 12:30:38 +10:00
William Belcher b6b26a0781
update unit tests 2023-05-03 11:55:11 +10:00
William Belcher 05ebc84e0f
set shouldReconnect to false is programmatically closing websocket connection 2023-05-03 11:25:17 +10:00
Mirek Kaspar f76abf3e33 New matchmaker queue screen with easy customization 2023-04-29 15:41:54 +02:00
William Belcher 282138b4a5
Make webrtcPlayerController and webXrController protected instead of private. This allows users to extend the base PixelStreaming class and access these member 2023-04-26 15:14:57 +10:00
DenisTensorWorks 28d079df8b
Add microphone feature documentation (#208)
Signed-off-by: DenisTensorWorks <127062860+DenisTensorWorks@users.noreply.github.com>
2023-04-26 14:01:14 +10:00
mcottontensor 94b5c32577
Merge pull request #199 from EpicGames/UE5.2
Merging UE5.2 changes back to master
2023-04-13 15:06:35 +10:00
mcottontensor 063ed002a2
Update RELEASE_VERSION
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-04-13 13:18:27 +10:00
Matthew Cotton f832cace44 Bump versions 2023-04-13 13:14:50 +10:00
mcottontensor 54db01551b
Update package.json
Signed-off-by: mcottontensor <80377552+mcottontensor@users.noreply.github.com>
2023-04-13 13:06:59 +10:00
mcottontensor cae8a7ad54
Merge pull request #198 from EpicGames/master
Bringing changes from master into 5.2
2023-04-13 13:05:45 +10:00
k_a_s_s 252b958bb7 Added documentation for UseMic 2023-04-07 13:41:46 +02:00
k_a_s_s 89d8505181 Added option to (un)mute mic in PixelStreaming 2023-04-07 13:25:02 +02:00
178 changed files with 4369 additions and 1998 deletions

4
.backportrc.json Normal file
View File

@ -0,0 +1,4 @@
{
"autoMerge": true,
"autoMergeMethod": "squash"
}

View File

@ -7,11 +7,11 @@ assignees: ''
---
**UE Version: **
**UE Version:**
E.g. UE 5.1.1
**Frontend Version: **
E.g. 0.3.0
**Frontend Version:**
E.g. UE5.3-0.3.0
**Problem component**
E.g. Signalling Server, Frontend, Pixel Streaming C++ plugin

33
.github/workflows/backport.yml vendored Normal file
View File

@ -0,0 +1,33 @@
name: Backport
on:
pull_request_target:
types: ["labeled", "closed"]
jobs:
backport:
name: Backport PR
runs-on: ubuntu-latest
if: |
github.event.pull_request.merged == true
&& contains(github.event.pull_request.labels.*.name, 'auto-backport')
&& (
(github.event.action == 'labeled' && github.event.label.name == 'auto-backport')
|| (github.event.action == 'closed')
)
steps:
- name: Backport Action
uses: sqren/backport-github-action@v8.9.3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
auto_backport_label_prefix: auto-backport-to-
add_original_reviewers: true
- name: Info log
if: ${{ success() }}
run: cat ~/.backport/backport.info.log
- name: Debug log
if: ${{ failure() }}
run: cat ~/.backport/backport.debug.log

View File

@ -1,8 +1,9 @@
name: Publish the Signalling Server container image from our dev branch
name: Publish Cirrus container
on:
push:
branches: ['UE5.2']
workflow_dispatch:
branches: ['UE5.4']
paths: ['SignallingWebServer/**']
jobs:
@ -23,10 +24,19 @@ jobs:
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
-
name: Build and push the Signalling Server container image for Unreal Engine based on our development branch
name: Build and push the Signalling Server container image
uses: docker/build-push-action@v3
with:
context: .
tags: 'ghcr.io/epicgames/pixel-streaming-signalling-server:5.2'
tags: 'ghcr.io/epicgames/pixel-streaming-signalling-server:5.4'
push: true
file: SignallingWebServer/Dockerfile
-
name: Build and push the SFU container image
uses: docker/build-push-action@v3
with:
context: .
tags: 'ghcr.io/epicgames/pixel-streaming-sfu:5.4'
push: true
file: SFU/Dockerfile

View File

@ -2,7 +2,7 @@ name: Releases
on:
push:
branches: ['UE5.2']
branches: ['UE5.4']
paths: ['RELEASE_VERSION']
jobs:
@ -48,16 +48,16 @@ jobs:
working-directory: ./Frontend/ui-library
run: npm run build-all
- name: Install implementations/EpicGames deps
working-directory: ./Frontend/implementations/EpicGames
- name: Install implementations/typescript deps
working-directory: ./Frontend/implementations/typescript
run: npm ci
- name: NPM link frontend and ui-library into implementations/EpicGames
working-directory: ./Frontend/implementations/EpicGames
- name: NPM link frontend and ui-library into implementations/typescript
working-directory: ./Frontend/implementations/typescript
run: npm link ../../library ../../ui-library
- name: Build implementations/EpicGames
working-directory: ./Frontend/implementations/EpicGames
- name: Build implementations/typescript
working-directory: ./Frontend/implementations/typescript
run: npm run build-all
- name: Move all content into output directory for archiving
@ -70,7 +70,7 @@ jobs:
path: 'PixelStreamingInfrastructure-${{ github.ref_name }}-${{ steps.getversion.outputs.version }}'
type: 'tar'
filename: '${{ github.ref_name }}-${{ steps.getversion.outputs.version }}.tar.gz'
exclusions: '.git .github output Frontend/Docs Frontend/library/dist Frontend/library/types Frontend/library/node_modules Frontend/ui-library/dist Frontend/ui-library/types Frontend/ui-library/node_modules Frontend/implementations/EpicGames/node_modules'
exclusions: '.git .github output Frontend/Docs Frontend/library/dist Frontend/library/types Frontend/library/node_modules Frontend/ui-library/dist Frontend/ui-library/types Frontend/ui-library/node_modules Frontend/implementations/typescript/node_modules'
- name: Archive Release .zip
uses: thedoctor0/zip-release@0.7.1

View File

@ -1,7 +1,8 @@
name: Publish library package to npmjs
name: Publish frontend lib
on:
push:
branches: ['UE5.2']
workflow_dispatch:
branches: ['UE5.4']
paths: ['Frontend/library/package.json']
jobs:
build:
@ -13,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.x'
node-version: '18.17.0'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build

View File

@ -1,7 +1,8 @@
name: Publish ui-library package to npmjs
name: Publish frontend-ui lib
on:
push:
branches: ['UE5.2']
workflow_dispatch:
branches: ['UE5.4']
paths: ['Frontend/ui-library/package.json']
jobs:
build:
@ -13,7 +14,7 @@ jobs:
- uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '16.x'
node-version: '18.17.0'
registry-url: 'https://registry.npmjs.org'
- run: npm ci
- run: npm run build

View File

@ -0,0 +1,42 @@
name: Run signalling tests
on:
workflow_dispatch:
push:
branches: ['signalling_tester']
paths: ['SignallingWebServer/**']
pull_request:
branches: ['signalling_tester']
paths: ['SS_Test/**']
jobs:
build:
runs-on: ubuntu-latest
defaults:
run:
working-directory: ./
permissions:
contents: write
steps:
- name: "Checkout source code"
uses: actions/checkout@v3
- uses: actions/setup-node@v3
with:
node-version: '18.x'
registry-url: 'https://registry.npmjs.org'
- name: Run signalling server
working-directory: ./SignallingWebServer
run: ./platform_scripts/bash/run_local.sh &
- name: Install library deps
working-directory: ./SS_Test
run: npm ci
- name: Run frontend lib tests
working-directory: ./SS_Test
run: npm run start

28
.github/workflows/stale.yml vendored Normal file
View File

@ -0,0 +1,28 @@
name: Mark and close stale issues and pull requests
on:
workflow_dispatch:
schedule:
- cron: "0 0 * * *"
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v8
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: 'Issues go stale after 30 days of inactivity. Please comment or re-open the issue if you are still interested in getting this issue fixed.'
stale-issue-label: 'stale'
exempt-issue-labels: 'enhancement'
stale-pr-message: 'PRs go stale after 30 days of inactivity. Please comment or re-open the PR if you are still working on this PR.'
stale-pr-label: 'stale'
exempt-pr-labels: 'awaiting-approval'
days-before-stale: 30
days-before-close: 0

View File

@ -4,10 +4,159 @@ The changelog is a summary of commits between releases of Unreal Engine.
As a reminder each UE-X branch/tag in this repository corresponds to a version of Unreal Engine.
## UE 5.2
Coming soon...
## [UE 5.3 (Current)](https://github.com/EpicGames/PixelStreamingInfrastructure/commits/UE5.3)
## [UE 5.1 (Current)](https://github.com/EpicGames/PixelStreamingInfrastructure/commits/UE5.1)
### Features
- Protocol structures can now contain strings by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/336
- Added the ability for the frontend peer to auto connect when a new streamer is available by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/358
### Enhancements
- Upgrade 5.2 to 5.3 in libraries, docs, log messages, build pipelines by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/262
- Include create, reconnect, and update events (with associated tests) by @jibranabsarulislam in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/273
- Add github action for PR and Issue management by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/304
- Update stale.yml by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/305
- Update stale workflow to also auto close stale issues and PRs by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/306
- Show player count in stats panel by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/303
- Change implementations/EpicGames to implementations/typescript #166 by @gunsha in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/177
- Refactor SignallingWebServer to a single docker file by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/337
- Update LatencyTest handler to accept input data by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/340
- Add contribution guideline `CONTRIBUTING.md` by @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/352
- New matchmaker queue screen with easy customization by @kasp1 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/211
- Updated CONTRIBUTING.md with backport rules by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/357
### Documentation
- Signaling message reference doc by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/271
- Update SignallingProtocol.md by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/288
### Bug fixes
- Fixed auto reconnect to not reconnect when the page is refreshed. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/285
- Fixed iOS touch when settings panel is open by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/274
- Fixed Firefox console errors `TypeError: this.preferredCodec.split is not a function` by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/310
- Fixed ensuring touch is relative to absolute location of parent rect by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/316
- Fixed injecting new params into SDP to get stereo back on Chrome by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/332
- Fixed matchmaker asking for OS authentication instead of erroring out with EACCESS by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/333
- Fixed consuming the context menu event instead of sending a mouse up by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/354
### Security
- Bump tough-cookie from 4.1.2 to 4.1.3 in /Frontend/library by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/290
- Bump word-wrap from 1.2.3 to 1.2.4 in /Frontend/library by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/320
- Bump word-wrap from 1.2.3 to 1.2.5 in /Frontend/ui-library by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/327
- Bump Node.js to latest LTS by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/321
## [UE 5.2](https://github.com/EpicGames/PixelStreamingInfrastructure/commits/UE5.2)
### Features
- Added minimal sample React implementation by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/159
- Added a new frontend for the Pixel Streaming Demo showcase project by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/158
- Added multiple streamer support by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/74
- Added `DefaultToHover` being parsed as a config option in `InitialSettings` message by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/68
- Added indication to the signalling server when the browser intends to send the offer by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/75
- Added experimental support for WebXR based experiences by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/85
### Docs
- New general docs page/ToC + new security page. by @MWillWallT in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/254
- Update README to mention container images require being part of Epic's Github org by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/248
- Update platform_scripts readme.md to explain the different scripts by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/224
- Improve signalling Server readme @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/223
- Adding microphone feature documentation for UE5.2 by @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/228
- Adding microphone feature documentation by @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/208
- Added new general docs page/ToC + new security page. by @MWillWallT in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/254
- Settings Panel Documentation by @MWillWallT in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/135
- Customised Pixel Streaming Player Page by @MWillWallT in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/90
- Updated Signalling Server docs by @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/223
- Updated docs for frontend for settings and TURN by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/224
- Adding docs for microphone feature by @DenisTensorWorks in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/228
- Updated README to mention container images require being part of Epic's Github org by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/248
- Updated the Frontend Docs to move some material from UE docs official to this repo by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/152
- Update Docs to remove broken links by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/122
### Enhancements
- Add repository health status in the form of Github badges table on readme.md by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/265
- Re-enable iOS and iPadOS fullscreen by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/266
- Changed forwarded logs to Cyan, added warning for missing playerId by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/253
- Added "media-playout" to prevent spam in Aggregated Stats by @chasse20 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/232
- Added 'stat PixelStreamingGraphs' to showcase frontend #229 by @devrajgadhvi in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/238
- Bump socket.io-parser from 4.2.2 to 4.2.4 in /Matchmaker by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/244
- Bump engine.io from 6.4.0 to 6.4.2 in /Matchmaker by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/220
- Allow inheritance of webrtcPlayerController and webXrController by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/209
- Pass command line args when calling run_local.bat by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/109
- Customize frontend styles through UI API by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/133
- Force URL param settings when receiving initial application settings by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/134
- Added ability to pass HTTPS certificate locations via Cirrus configuration by @marcinbiegun in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/149
- Added unit tests for library by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/156
- Converted frontend javascript to typescript and refactor. by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/63
- Removed useless code, make code style more consistent by @Senseme in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/59
- Multi-streamer QOL improvements by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/88
- Removing the player id from forwarded messages by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/91
- Added a QOL message when multiple streamers are detected by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/94
- Added dev and prod configs to webpack by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/102
- Added github actions to create an NPM package for frontend library and make a release for the repo by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/103
- Neaten up install scripts by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/106
- Added 'stat PixelStreamingGraphs' to showcase frontend #229 by @devrajgadhvi in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/238
- Changed forwarded logs to Cyan, added warning for missing playerId by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/253
- Allow inheritance of webrtcPlayerController and webXrController by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/209
- Alter reconnection flow to request streamer message list and fail out after N attempts. by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/195
- Added exports for UI configuration types by @kass-kass in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/193
- Added ability to optionally disable certain frontend elements by @kass-kass in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/161
- Added support for programmatically changing peer layers when using the SFU by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/179
- Improved frontend API support for UE communication by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/132
- Added ability in frontend to Enable/disable user input devices by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/136
- Exposed websocketController and webXRController to public API by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/124
- Added XR events: xrSessionStarted, xrSessionEnded, xrFrame by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/125
- Decouple UI from the frontend library by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/110
- Replaced hardcoded log path with given parameter path by @Mirmidion in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/39
### Bug fixes
- Fixed viewport resizing not always working due to improperly calling timer. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/247
- Fixed hovering mouse mode set in URL being overridden on refresh. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/246
- Fixed matchmaker directing users to http when the signalling server is using https by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/245
- Fixed reconnects will be attempted even when a disconnect is triggered by afk timeout by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/215
- Fixed datachannels not working when using the SFU by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/137
- Fixed SFU having clashing datachannel/stream ids, now using mediasoup's internal stream ids for SCTP by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/129
- Fixed controller indices from multiple peers would clash by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/165
- Fixed Connecting to Unreal 5.1 app with the 5.2 frontend crashes on connect by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/180
- Fixed sfu player would try subscribing when sfu disconnected by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/172
- Fixed bug where stress tester would leave orphaned Pixel Streaming connections by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/185
- Fixed bug where reconnects were being attempted even when a disconnect is triggered by afk timeout by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/215
- Fixed viewport resizing not always working due to improperly calling timer. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/247
- Fixed log spam caused by missing "media-playout" in Aggregated Stats by @chasse20 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/232
- Fixed hovering mouse mode set in URL being overridden on refresh. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/246
- Fixed matchmaker directing users to http when the signalling server is using https by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/245
- Fixed frontend library not building on Linux due to incorrect casing by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/96
- Fixed SFU peer datachannels aren't being created by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/95 and https://github.com/EpicGames/PixelStreamingInfrastructure/pull/97
- Fixed crash on browsers where the xr object wasn't on the navigator by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/93
- Fixed Preferred codec selector causes no stream if application launched without `-PixelStreamingNegotiateCodecs` by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/83
- Fixed adding the rest of the browsers supported codecs after setting the preferred codec (#83) by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/84
- Fixed delayed mic input by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/77 and @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/78
- Fixed syntax error by @mcianni in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/44
- Fixed check if KeyboardEvent.keyCode deprecated then use KeyboardEvent.code + mapping instead. by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/48
- Fixed bug when negating property in and removing duplicate property by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/49
- Fixed incorrect login page path when using authentication by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/55
- Fixed handling of "defaultToHover" field in offer by @StomyPX in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/60
- Fixed Pixel Streaming session disconnecting entirely when using the new frontend by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/141
- Fixed input would not entirely unregister when using the new frontend by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/144
- Fixed frontend not working with older NodeJS versions due ts-jest and jest by @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/168
- Fixed webpack was double bundling frontend lib into the final bundle (#117) by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/118 @hmuurine in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/117
- Fixed cirrus Dockerfile that resulting in a non-functional signalling server by @Belchy06 in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/123
### Security
- Various security updates by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/220
- Security updates for default turn server configuration. by @gingernaz in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/196
- Bumped qs and express in /SignallingWebServer by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/69
- Bumped qs and express in /Matchmaker by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/70
- Bumped passport from 0.4.1 to 0.6.0 in /SignallingWebServer by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/71
- Bumped engine.io and socket.io in /Matchmaker by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/72
- Bumped socket.io-parser from 4.2.2 to 4.2.4 in /Matchmaker by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/244
- Patched Uncaught exception in PixelStreamingInfrastructure via engine by @imhunterand in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/61
- Fixed insufficient validation when decoding a Socket packet by @iot-defcon in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/57
- @ CVE-2022-25896 by @mik-patient in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/35
- Bump webpack from 5.75.0 to 5.76.0 in /Frontend/library by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/153
- Bump webpack from 5.75.0 to 5.76.0 in /Frontend/ui-library by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/155
- Bump webpack from 5.75.0 to 5.76.0 in /Frontend/implementations/EpicGames by @dependabot in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/154
- Fixing security warnings. by @mcottontensor in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/163
- Moved all package.json under @epicgames-ps scope to avoid package confusion by @lukehb in https://github.com/EpicGames/PixelStreamingInfrastructure/pull/187
## [UE 5.1](https://github.com/EpicGames/PixelStreamingInfrastructure/commits/UE5.1)
### Bug fixes
- [3b1b84](https://github.com/EpicGames/PixelStreamingInfrastructure/commit/3b1b8417227fc0cbd8e14326da046876fdf926a3) Fix black screen flickering when receiving freeze frames.

68
CONTRIBUTING.md Normal file
View File

@ -0,0 +1,68 @@
# Welcome to Pixel Streaming contribution guide
First and foremost, thank you for your time and contribution to Pixel Streaming!
We are proud and excited to be a part of a passionate community that continuously helps us improve Pixel Streaming 🎉
If you are not familiar with contributing on GitHub, have a look at the [official documentation](https://docs.github.com/get-started) to learn more about repositories structure, forks, branches, commits, issues, and PRs.
### Code of conduct
Please remain patient, courteous, and professional at all times. Any form of spam, abuse, or discrimination will not be tolerated.
## Getting started
### Creating issues
If you have encountered a bug, have suggestions for our documentation or infrastructure, or would like to propose a feature that could enhance Pixel Streaming in various use case scenarios, you can raise this with us by creating a new issue.
1. First, search all open and closed issues [here](https://github.com/EpicGames/PixelStreamingInfrastructure/issues?q=is%3Aissue+) - your issue may have already been discussed or addressed.
2. If your issue doesn't exist, open a new issue [here](https://github.com/EpicGames/PixelStreamingInfrastructure/issues/new/choose) by selecting a bug or feature request.
3. Make sure to fill in the template as much as possible; any information you can provide, such as repro steps, crash stacks, screenshots, etc., can help us triage and fix the problem as quickly as possible.
4. Keep an eye on the status of your issue; our developers or other users might reach out with requests for more information. If this happens, issues that have not received a response in over 30 days will be automatically closed.
5. Be patient while waiting on a resolution; we prioritize the issues internally and some less critical features (however much we'd love to implement them!) will take a backseat to more pressing priorities, so some issues can take a while to get resolved.
### Creating pull requests (PR)
If you have a solution to a problem you've encountered or to any other open issue, you can create a pull request with your changes.
1. Fork the repo and branch off of the `main` branch in your fork.
2. Implement your changes in your branch and make sure your commits are Verified! Signed commits are required for merging! [Github Signing Documentation](https://docs.github.com/en/authentication/managing-commit-signature-verification/about-commit-signature-verification)
3. Do as much testing as you can, and when you are happy, tidy up your work and commit the update.
4. Create a [pull request](https://github.com/EpicGames/PixelStreamingInfrastructure/pulls) and don't forget to link it to an issue if there's an existing one. Add as much information as possible to your PR: describe the problem your change solves, mention any testing you have done and attach any relevant documents and screenshots.
5. If your are contributing a PR for a new feature, we strongly encourage you to accompany it with relevant documentation and a detailed description of the tests you have done. PRs that don't have this information may take a long time to be addressed, since our team will have to do the testing.
6. If your PR is good to go, we will merge it in. Woohoo! Thank you for your time and efforts! 🎉
7. Keep a close eye on your PR - quite often, our developers will review your PR and leave comments; we might request some minor code changes and modifications, style unification, or leave any general comments and questions that are preventing us from merging the PR.
8. If we do not hear from you after requesting more information within 30 days, the PR will auto-close. In this case, we might elect to open our own PR and re-use some of the changes that you proposed, supplemented with anything else that was required to be added in your original PR.
9. If your PR fixes a problem in the previous [still-supported UE branches](https://github.com/EpicGames/PixelStreamingInfrastructure#versions), feel free to add the `auto-backport` and `auto-backport-to-UEX.X` labels. You'll need to add a `auto-backport-to-UEX.X` label for each branch you wish your change to be merged back to. Note that if a change to any of the previous branches is not trivial and requires a lot of testing and compatibility checks, we might elect to close it if we do not think that it brings enough value to the branch.
### Other ways to contribute
- Keep an eye on our repo and stay active on existing issues and PRs; you can help by adding informative comments to the discussions, additional repro steps, repros in different environments, or any suggestions as to what could be causing the issue and how it could be solved.
- Work on [issues labeled for community](https://github.com/EpicGames/PixelStreamingInfrastructure/issues?q=is%3Aopen+is%3Aissue+label%3A%22good+first+issue%22). We specifically created this label to mark issues that we would love the community to help us with.
- Create documentation for undocumented features. Please open an issue first, so our developers can provide you with some guidance.
- Write more unit test coverage.
- Document functions in the public API that are not documented.
- Write new frontend implementations using another web framework, e.g. Angular, Vue, etc.
- Perform QA on different engine versions, particularly previews, and create issues based on the bugs that you have found.
## Coding style
- TypeScript should be used over JavaScript.
- All TypeScript should adhere to the following [linting rules](https://github.com/EpicGames/PixelStreamingInfrastructure/blob/master/Frontend/library/.eslintrc.js).
- Names should follow US English spelling.
- All public functions/API should have comments.
- Code formatting should adhere to the following [whitespace and indentation rules](https://github.com/EpicGames/PixelStreamingInfrastructure/blob/master/Frontend/library/.prettierrc.json).
- All new features should have accompanying unit tests and documentation when they are submitted.
- Prefer early returns in `if` statements to decrease indentation.
- Prefer functions to not exceed ~20 lines.
- Prefer comments in longer functions.
- Prefer verbosity over syntactic sugar.
- Prefer exporting a minimal public API surface for iteration and support reasons.
- Try not to exceed three levels of nesting in a function.
## Documentation style
All documentation should be written in US English and follow correct grammar and spelling. Endeavour to lay out the document in a logical fashion with headings, lists, and bullet points where appropriate.
Documentation should be broken up into separate `.md` files per directory, ideally with a `readme.md` file in the root of each top-level directory for a component to explain it. Where appropriate, these documentation pages should be linked to a table of contents in the relevant part of the repository.
## Legal
© 2004-2024, Epic Games, Inc. Unreal and its logo are Epics trademarks or registered trademarks in the US and elsewhere.

12
Docs/README.md Normal file
View File

@ -0,0 +1,12 @@
# General Documentation and Information
Welcome to the general documentation page for Pixel Streaming. This page serves as the central hub for accessing various documentation related to Pixel Streaming. It also functions as a Table of Contents, providing easy navigation to different sections of this repository.
[Documentation Table of Contents](/README.md#documentation)
### General Documentation
* [Security Guidelines](/Docs/Security-Guidelines.md)
## Legal
© 2004-2024, Epic Games, Inc. Unreal and its logo are Epics trademarks or registered trademarks in the US and elsewhere.

View File

@ -0,0 +1,20 @@
# Security Guidelines
To enhance the security of your Pixel Streaming deployments, it is wise to implement additional measures for protection. This documentation page aims to provide you with valuable recommendations and suggestions to bolster the security of your deployments. By following these guidelines, you can significantly enhance the overall security posture and safeguard your Pixel Streaming environment effectively.
## Tips to Improve Security
Please note that implementing the following suggestions may introduce additional setup complexity and could result in increased latency.
1. **Isolate Unreal Engine Instance:** Avoid deploying the Unreal Engine instance on a cloud machine with a public IP. Instead, only allowlist the necessary servers, such as the signalling and TURN servers, to communicate with the UE instance.
2. **Route Media Traffic through TURN Server:** For enhanced security, enforce routing all media traffic through the TURN server. By doing so, only the TURN server and signalling server will be permitted to communicate with the UE instance. Keep in mind that this approach may introduce some additional latency.
3. **Secure TURN Server with User Credentials:** Configure the TURN server with a user database and assign unique credentials to each user. This additional security layer prevents unauthorized access to the relay. By default, Pixel Streaming employs the same TURN credentials for every session, which may simplify access for potential attackers.
4. **Avoid Storing Important Credentials in the UE Container:** As a precautionary measure, refrain from storing any critical credentials or sensitive information within the UE container. This practice helps maintain a higher level of security.
5. **Disable Pixel Streaming Console Commands:** Pixel Streaming ensures that all media traffic is encrypted end-to-end, guaranteeing secure communication. However, note that Pixel Streaming allows users to send commands to the UE instance if enabled. To eliminate this possibility, launch without the `-AllowPixelStreamingCommands` flag.
6. **Separate TURN and Signalling Servers:** It is recommended to avoid colocating the TURN and signalling servers with the UE instance on the same IP or virtual machine (VM). This enables you to configure separate ingress/egress security policies for each server, allowing flexibility in defining the desired level of strictness or looseness. For example, the TURN server can have more relaxed policies while the UE instance can have stricter ones.
By following these tips, you can enhance the security of your Pixel Streaming setup and mitigate potential risks.

View File

@ -9,6 +9,7 @@ The following options are available in the frontend library to customize input:
| HoveringMouseMode | false | Determines whether or not the video element captures and locks the mouse when the player interacts with the widget. When enabled, the mouse cursor hovers over the player widget without interacting with it. In order to send the mouse movements to the input controller of the Unreal Engine application, the user needs to click and hold the left button of the mouse. Otherwise, clicking on the player widget causes it to capture and lock the mouse cursor. Any further movements of the mouse are passed immediately to the input controller in the Unreal Engine application. This typically allows the user to move and rotate the camera by simply dragging the mouse. To release the cursor from the control of the player widget, the user can press the **Esc** key. |
| SuppressBrowserKeys | true | When this setting is enabled, the player widget will intercept function keys (**F1** to **F12**) and the **Tab** key, and pass those keypress events through to the Unreal Engine application rather than allowing the browser to process them normally.| This means, for example, that while this setting is active, pressing **F5** will not refresh the player page in the browser. Instead, that event is passed through to the Unreal Engine application, and has its usual function of switching the view to visualize shader complexity.
| FakeMouseWithTouches | false | When this option is enabled and the user is viewing the stream on a device with a touch screen such as a smartphone or tablet, this setting causes single-finger touch events to be interpreted by the Unreal Engine application as mouse clicks and drag events. Enabling this setting can provide users on mobile devices with the ability to partially control your Unreal Engine application, even when the application's input controller does not specifically handle touch input events. |
| UseMic | false | Indicates whether or not the stream should be created with a microphone track which is sent to the UE application. This microphone track can be listened to using the [`UPixelStreamingAudioComponent`](https://docs.unrealengine.com/5.0/en-US/API/Plugins/PixelStreaming/UPixelStreamingAudioComponent/). If this flag is enabled, a microphone audio track is created (if the browser settings allow for it) and is actively sending audio. For saving bandwidth or other functionality, it's possible to mute the microphone track by calling `PixelStreaming`'s `muteMicrophone`, and later re-enable it with `unmuteMicrophone`. If the `PixelStreaming` object was created without this flag, it's possible to enable it later by calling `unmuteMicrophone(true)`, which will use the `forceEnable` parameter to add the track and trigger a full reconnection (this is a heavier operation that takes a while). |
When creating a frontend implementation, these options are visible via the [`Config`](/Frontend/library/src/Config/Config.ts) object required in order to create a [`PixelStreaming`](/Frontend/library/src/PixelStreaming/PixelStreaming.ts) stream for your frontend application. Simply set the values you want before initializing the stream object.

View File

@ -1,5 +1,5 @@
## Recommended Reading
We recommend starting with the [sample implementations](/Frontend/implementations/EpicGames/src) in order to judge how to put a new player page together and integrate it with your Unreal Engine application. Additionally, if you have cloned the Pixel Streaming Infrastructure repository and made upstream changes, you can fork the repo and make a pull request.
We recommend starting with the [sample implementations](/Frontend/implementations/typescript/src) in order to judge how to put a new player page together and integrate it with your Unreal Engine application. Additionally, if you have cloned the Pixel Streaming Infrastructure repository and made upstream changes, you can fork the repo and make a pull request.
## Using the default Player Webpage
The Pixel Streaming Signalling and Web Server provides a sample player page that is already set up to stream in media from your Unreal Engine application and to send mouse, keyboard, and touch events back to the application. You can use this default player page as-is, if it meets your needs.

View File

@ -1,6 +1,6 @@
## HTML Page Requirements
Most of the HTML that will end up on the final page will actually be introduced by the Pixel Streaming application itself. Several example HTML pages are provided in the [sample implementations](/Frontend/implementations/EpicGames/src) where you can see the base page is very minimal, only serving as a space for the application to attach to and fill. The only concrete requirements are for ensuring there's sufficient space taken up by the element being attached to for the viewport to be visible on screen. In the sample implementations this is simply a `<body>` tag set to fill the screen without scrolling.
Most of the HTML that will end up on the final page will actually be introduced by the Pixel Streaming application itself. Several example HTML pages are provided in the [sample implementations](/Frontend/implementations/typescript/src) where you can see the base page is very minimal, only serving as a space for the application to attach to and fill. The only concrete requirements are for ensuring there's sufficient space taken up by the element being attached to for the viewport to be visible on screen. In the sample implementations this is simply a `<body>` tag set to fill the screen without scrolling.
```html
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
@ -20,20 +20,18 @@ Most of the HTML that will end up on the final page will actually be introduced
</html>
```
As can be seen in the [sample implementations](/Frontend/implementations/EpicGames/src/player.ts), you must specify which element on the page the Pixel Streaming viewport is to be appended to. In the sample implementations this is typically done in the `document.body.onload` event listener and in this case appended to the `document.body` element in the DOM, causing it to fill the whole page.
As can be seen in the [sample implementations](/Frontend/implementations/typescript/src/player.ts), you must specify which element on the page the Pixel Streaming viewport is to be appended to. In the sample implementations this is typically done in the `document.body.onload` event listener and in this case appended to the `document.body` element in the DOM, causing it to fill the whole page.
[//]: # (This has yet to be done)
### Player File Location and URL
You have a few options for where you can place your custom HTML player page, and how client browsers can access it.
* You can create a new implementation page and place it in [`/Frontend/implementations/EpicGames/src/`](/Frontend/implementations/EpicGames/src) alongside the sample implementations. This must consist of both a base `.html` page and the `.ts` source for your application's entrypoint. This will then be accessible by appending the name of the `html` file to IP address or hostname of the computer running the Signalling Server.
* You can create a new implementation page and place it in [`/Frontend/implementations/typescript/src/`](/Frontend/implementations/typescript/src) alongside the sample implementations. This must consist of both a base `.html` page and the `.ts` source for your application's entrypoint. This will then be accessible by appending the name of the `html` file to IP address or hostname of the computer running the Signalling Server.
For example, the sample `stresstest` page can be accessed on a locally-running infrastructure at `http:/127.0.0.1/stresstest.html`.
* You can customize the `HomepageFile` parameter for the Signaling and Web Server, and set the path to the filename of your custom HTML player page relative to the [Frontend implementations source folder](/Frontend/implementations/src). It will then be accessible when you access the IP address or hostname of the computer running the Signaling and Web Server.
* You can also use the **AdditionalRoutes** parameter for the Signaling and Web Server to customize the mapping between URL paths and local folders on your computer.
For additional details on these parameters, see also the [Pixel Streaming Reference](https://docs.unrealengine.com/5.2/en-US/unreal-engine-pixel-streaming-reference/).
### Building the Frontend
When starting the infrastructure Signalling Server, the Frontend should be built automatically. If not, you can run the [`setup script`](/SignallingWebServer/platform_scripts/) for your platform to do so. If you subsequently make any changes to your local copy of the frontend, you will need to run the script again, appending `--build` as an argument to force a rebuild.
When starting the infrastructure Signalling Server, the Frontend should be built automatically. If not, you can run the [`setup_frontend`](/SignallingWebServer/platform_scripts/) script for your platform to do so. If you subsequently make any changes to your local copy of the frontend, you will need to run the script again, appending `--build` as an argument to force a rebuild.

Binary file not shown.

After

Width:  |  Height:  |  Size: 981 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -19,7 +19,6 @@ This page will be updated with new features and commands as they become availabl
| **Browser send offer** | The browser will start the WebRTC handshake instead of the Unreal Engine application. This is an advanced setting for users customising the frontend. Primarily for backwards compatibility for 4.x versions of the engine. |
| **Use microphone** | Will start receiving audio input from your microphone and transmit it to the Unreal Engine. |
| **Start video muted** | Muted audio when the stream starts. |
| **Prefer SFU** | Will attempt to use the Selective Forwarding Unit (SFU), if you have one running. |
| **Is quality controller?** | Makes the encoder of the Pixel Streaming Plugin use the current browser connection to determine the bandwidth available, and therefore the quality of the stream encoding. **See notes below** |
| **Force mono audio** | Force the browser to request mono audio in the SDP. |
| **Force TURN** | Will attempt to connect exclusively via the TURN server. Will not work without an active TURN server. |

View File

@ -0,0 +1,48 @@
## Microphone feature summary
In its current state, the microphone feature in Pixel Streaming is designed to pass the streamers microphone input audio from Pixel Streaming to Unreal Engine. The WebRTC audio stream is not exposed nor further handled inside the engine, so any custom use of the audio stream will require significant modifications by the user.
## Enabling microphone input for Pixel Streaming in UE projects
Once youve enabled the Pixel Streaming plugin in your project, youll need to add the `Pixel Streaming Audio` component to your scene. It can be attached to any actor or asset in the scene, following these steps:
- Select any enabled actor or asset in your scene;
- Click the *Add* button, located in its details panel;
- Type *Pixel Streaming Audio* in the search bar and click the matching component:
<p align="center">
<img src="Resources\Images\add-pixel-streaming-to-actor.png" alt="Add component to actor">
</p>
Once the component has been added, you can adjust its settings and specify a player or streamer ID to listen to, if you wish. The default configuration will be listening to the first peer it can hear and should be suitable for most basic use cases:
<p align="center">
<img src="Resources\Images\settings-pixel-streaming-audio.png" alt="Component configuration">
</p>
No more setup is required on the UE side, so the project is now ready to be packaged or used standalone.
## Enabling microphone in Pixel Streaming frontend
Launch Pixel Streaming and click the cog icon to open the stream settings, where you can enable the microphone toggle. Make sure to restart the stream to apply the changes:
<p align="center">
<img src="Resources\Images\mic-toggle.png" alt="Component configuration">
</p>
*Note:* Alternatively, you can enable the microphone by adding `?UseMic=true` to the url. Youll still need to refresh the page for the change to take effect.
When doing this for the first time, your browser will likely ask your permission to use the microphone on this page, which you need to allow. Some browsers and firewalls may automatically block it, so you will need to create permission rules in your browser settings.
You are ready to roll! Connect to the stream and speak into the microphone. If everything has been set up correctly, your microphone input will be passed to UE and played back to you by Pixel Streaming, so you will hear yourself.
*Note:* The above steps will not work without the `Pixel Streaming Audio` component set up in your project. If you dont hear any playback, double check your project for the appropriate component.
## Tips on handling the microphone WebRTC stream further
As mentioned earlier, the microphone audio stream isnt handled further after its passed to UE. You might want to use it in custom ways, for example, feed it back to Pixel Streaming so you could hear the other players, or pass it to another plugin to create a voice chat. Here are some tips to help you get started:
- You can choose to use a voice chat plugin, whose audio data goes through the UE audio system, which will be automatically picked up by Pixel Streaming.
- If you would like to pass the data elsewhere, e.g. to your custom plugin, you'll need to create your own audio sink, see more information [here](https://github.com/EpicGames/UnrealEngine/blob/5ca9da84c694c6eee288c30a547fcaa1a40aed9b/Engine/Plugins/Media/PixelStreaming/Source/PixelStreaming/Public/IPixelStreamingStreamer.h#L220).
- You can implement Pixel Streaming audio mixer and plug the audio from your voice plugin into it. [Here](https://github.com/EpicGames/UnrealEngine/blob/release/Engine/Plugins/Media/PixelStreaming/Source/PixelStreaming/Private/AudioInputMixer.h) is a good jumping point.
- Both camera and microphone access will be blocked on *insecure origins* (in effect since Chrome 47), so make sure to use HTTPS for production. This is not required for local use, e.g. during development.

View File

@ -5,10 +5,11 @@ The **frontend** refers to the HTML, CSS, images, and JavaScript/TypeScript code
The frontend consists of two packages:
1. [lib-pixelstreamingfrontend](/Frontend/library/): the core Pixel Streaming frontend for WebRTC, settings, input, and general functionality.
2. [lib-pixelstreamingfrontend-ui](/Frontend/implementations/EpicGames): the reference UI that users can either optionally apply on top of the core library or build on top of.
2. [lib-pixelstreamingfrontend-ui](/Frontend/implementations/typescript): the reference UI that users can either optionally apply on top of the core library or build on top of.
## Docs
- [The Settings Panel](Docs/Settings%20Panel.md)
- [Customizing the Player Webpage](Docs/Customizing%20the%20Player%20Webpage.md)
- [HTML Page Requirements](Docs/HTML%20Page%20Requirements.md)
- [Player File Location and URL](Docs/HTML%20Page%20Requirements.md)
@ -28,7 +29,7 @@ The TypeScript libraries are provided as both an [NPM](https://www.npmjs.com/set
## Usage from source
When developing your own Pixel Streaming experience the intent is you will start with this library and extend it through the use of
its public API. We have provided an example of this workflow in our [implementations/EpicGames](/Frontend/implementations/EpicGames), which is an implementation of this library.
its public API. We have provided an example of this workflow in our [implementations/typescript](/Frontend/implementations/typescript), which is an implementation of this library.
## Contributing
@ -36,6 +37,14 @@ If part of the library is not exposed and you wish to extend it, please do so in
## Developing
⚠️ Only NodeJS LTS 18.17.0 is officially supported, some newer versions on NodeJS **WILL BREAK YOUR BUILD** ⚠️
### Prerequisites
- Install NodeJS LTS 18.17.0 on your system.
- Install npm globally using: `npm install npm -g` (yes this is required)
### Building the Library
Changes to the library occur in the [/library](/Frontend/library) directory and require you to have NodeJS installed as part of your development environment.
Once you have NodeJS installed:
@ -43,16 +52,28 @@ Once you have NodeJS installed:
- `npm install`
- `npm run build`
The default user interface is provided in [/ui-library](/Frontend/ui-library) directory. You can either use it or provide your own user interface. To build the default UI, run:
### Building the UI-Library
The user interface library is provided in [/ui-library](/Frontend/ui-library) directory. You can either use it or provide your own user interface. To build run:
- Follow the steps to build the library first
- `cd ui-library`
- `npm install`
- `npm run build`
- `npm run build-all`
This will produce `player.js` under the `SignallingWebServer/Public` directory - this is the default UI.
### Building the default UI
The default user interface is provided under [/implementations/typescript](/Frontend/implementations/typescript). To build run:
- Follow the steps to build the libary and ui-library first
- `cd implementations/typescript`
- `npm install`
- `npm run build-all`
This will produce `player.html` and `player.js` under the `SignallingWebServer/Public` directory - this is the default UI.
### Making your own UI
We recommend studying [/ui-library](/Frontend/ui-library) and [player.ts](/Frontend/implementations/EpicGames/src/player.ts)/[player.html](/Frontend/implementations/EpicGames/src/player.html), or alternatively the sample React implementation in [implementations/react](/Frontend/implementations/react), then once you have copied and modified the [package.json](/Frontend/implementations/EpicGames/package.json) and `.ts` into your own `implementation/your_implementation` directory, the process is similar:
We recommend studying [/ui-library](/Frontend/ui-library) and [player.ts](/Frontend/implementations/typescript/src/player.ts)/[player.html](/Frontend/implementations/typescript/src/player.html), or alternatively the sample React implementation in [implementations/react](/Frontend/implementations/react), then once you have copied and modified the [package.json](/Frontend/implementations/typescript/package.json) and `.ts` into your own `implementation/your_implementation` directory, the process is similar:
- `cd implementation/your_implementation`
- `npm build-all`
@ -66,4 +87,4 @@ The [/library](/Frontend/library) project has unit tests that test the Pixel Str
## Legal
Copyright &copy; 2023, Epic Games. Licensed under the MIT License, see the file [LICENSE](./LICENSE) for details.
Copyright &copy; 2024, Epic Games. Licensed under the MIT License, see the file [LICENSE](./LICENSE) for details.

View File

@ -1,3 +0,0 @@
# Configuration of the Frontend UI
Todo

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

View File

@ -1 +0,0 @@
The images directory

View File

@ -1,37 +0,0 @@
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE html>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Required - the Login style sheet -->
<link rel="stylesheet" type="text/css" href="./assets/css/login.css">
<!-- Optional: set some favicons -->
<link id="favPng" rel="icon" type="image/png" href="./assets/images/favicon.png">
<!-- Optional: set a title for your page -->
<title>Pixel Streaming Login</title>
</head>
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
<form action="/login" method="post">
<div class="entry">
<input type="text" id="username" name="username" placeholder="Username"
autocomplete="username">
</div>
<div class="entry">
<input type="password" id="password" name="password" placeholder="Password"
autocomplete="current-password">
</div>
<div class="entry button">
<button type="submit">LOGIN</button>
</div>
</form>
</body>
</html>

View File

@ -1,2 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.

View File

@ -0,0 +1,9 @@
# Angular Implementations
Here are a selection of community contributed implementations of Angular frontends.
- [cheikhnadiouf](https://github.com/cheikhnadiouf)'s implementation - [LINK](https://github.com/cheikhnadiouf/PixelStreamingInfrastructure/tree/AngularImplementations/Frontend/implementations/angular)
If you wish to contribute your own example frontend, please open an issue/PR.
**Disclaimer: We do not warrant these for any fitness of purpose, nor do we maintain them.**

View File

@ -1,11 +1,11 @@
{
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.2",
"name": "@epicgames-ps/react-pixelstreamingfrontend-react-ue5.3",
"version": "0.0.1",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.2",
"name": "@epicgames-ps/react-pixelstreamingfrontend-react-ue5.3",
"version": "0.0.1",
"dependencies": {
"react": "^18.2.0",
@ -1576,9 +1576,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.2.tgz",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true,
"funding": [
{
@ -2500,10 +2500,16 @@
}
},
"node_modules/nanoid": {
"version": "3.3.4",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@ -2831,9 +2837,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.21",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.21.tgz",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@ -2843,10 +2849,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},

View File

@ -1,5 +1,5 @@
{
"name": "@epicgames-ps/reference-pixelstreamingfrontend-react-ue5.2",
"name": "@epicgames-ps/react-pixelstreamingfrontend-react-ue5.4",
"version": "0.0.1",
"description": "",
"main": "./src/index.tsx",

View File

@ -17,7 +17,8 @@ export const App = () => {
AutoConnect: true,
ss: 'ws://localhost:80',
StartVideoMuted: true,
HoveringMouse: true
HoveringMouse: true,
WaitForStreamer: true
}}
/>
</div>

View File

@ -5,7 +5,7 @@ import {
Config,
AllSettings,
PixelStreaming
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
export interface PixelStreamingWrapperProps {
initialSettings?: Partial<AllSettings>;

View File

@ -1,11 +1,11 @@
{
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.2",
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.4",
"version": "0.0.1",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.2",
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.4",
"version": "0.0.1",
"devDependencies": {
"css-loader": "^6.7.3",
@ -1390,8 +1390,9 @@
}
},
"node_modules/follow-redirects": {
"version": "1.15.2",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true,
"funding": [
{
@ -2207,9 +2208,16 @@
}
},
"node_modules/nanoid": {
"version": "3.3.4",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true,
"funding": [
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@ -2505,8 +2513,9 @@
}
},
"node_modules/postcss": {
"version": "8.4.21",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"funding": [
{
@ -2516,10 +2525,14 @@
{
"type": "tidelift",
"url": "https://tidelift.com/funding/github/npm/postcss"
},
{
"type": "github",
"url": "https://github.com/sponsors/ai"
}
],
"dependencies": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
},
@ -4886,8 +4899,9 @@
}
},
"follow-redirects": {
"version": "1.15.2",
"integrity": "sha512-VQLG33o04KaQ8uYi2tVNbdrWp1QWxNNea+nmIB4EVM28v0hmP17z7aG1+wAkNzVq4KeXTq3221ye5qTJP91JwA==",
"version": "1.15.4",
"resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.4.tgz",
"integrity": "sha512-Cr4D/5wlrb0z9dgERpUL3LrmPKVDsETIJhaCMeDfuFYcqa5bldGV6wBsAN6X/vxlXQtFBMrXdXxdL8CbDTGniw==",
"dev": true
},
"forwarded": {
@ -5463,8 +5477,9 @@
}
},
"nanoid": {
"version": "3.3.4",
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
"version": "3.3.6",
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.6.tgz",
"integrity": "sha512-BGcqMMJuToF7i1rt+2PWSNVnWIkGCU78jBG3RxO/bZlnZPK2Cmi2QaffxGO/2RvWi9sL+FAiRiXMgsyxQ1DIDA==",
"dev": true
},
"negotiator": {
@ -5680,11 +5695,12 @@
}
},
"postcss": {
"version": "8.4.21",
"integrity": "sha512-tP7u/Sn/dVxK2NnruI4H9BG+x+Wxz6oeZ1cJ8P6G/PZY0IKk4k/63TDsQf2kQq3+qoJeLm2kIBUNlZe3zgb4Zg==",
"version": "8.4.31",
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.31.tgz",
"integrity": "sha512-PS08Iboia9mts/2ygV3eLpY5ghnUcfLV/EXTOW1E2qYxJKGGBUtNjN76FYHnMs36RmARn41bC0AZmn+rR0OVpQ==",
"dev": true,
"requires": {
"nanoid": "^3.3.4",
"nanoid": "^3.3.6",
"picocolors": "^1.0.0",
"source-map-js": "^1.0.2"
}

View File

@ -1,5 +1,5 @@
{
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.2",
"name": "@epicgames-ps/reference-pixelstreamingfrontend-ue5.4",
"version": "0.0.1",
"description": "",
"main": "./src/player.ts",
@ -9,8 +9,8 @@
"watch": "npx webpack --watch",
"serve": "webpack serve --config webpack.dev.js",
"serve-prod": "webpack serve --config webpack.prod.js",
"build-all": "npm link ../../library ../../ui-library && cd ../../library && npm run build && cd ../ui-library && npm run build-all && cd ../implementations/EpicGames && npm run build",
"build-dev-all": "npm link ../../library ../../ui-library && cd ../../library && npm run build-dev && cd ../ui-library && npm run build-dev-all && cd ../implementations/EpicGames && npm run build-dev"
"build-all": "cd ../../library && npm run build && cd ../ui-library && npm run build-all && cd ../implementations/typescript && npm link ../../library ../../ui-library && npm run build",
"build-dev-all": "cd ../../library && npm run build-dev && cd ../ui-library && npm run build-dev-all && cd ../implementations/typescript && npm link ../../library ../../ui-library && npm run build-dev"
},
"devDependencies": {
"webpack-cli": "^5.0.1",

View File

@ -4,7 +4,7 @@ A plugin library that can be optionally applied on top of the core library to cr
**This is great starting point for building your UI or studying the Pixel Streaming feature set.**
![Frontend](/Frontend/implementations/EpicGames/docs/images/frontend.jpg)
![Frontend](/Frontend/implementations/typescript/docs/images/frontend.jpg)
### Key features
- An info panel (screen right) that provides a UI for displaying live statistics to the user.
@ -14,4 +14,4 @@ A plugin library that can be optionally applied on top of the core library to cr
### Adding it to your project
`npm i @epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2`
`npm i @epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4`

View File

@ -1,201 +1,203 @@
:root {
--democolor0: rgba(15, 15, 15, 1);
--democolor1: #000000;
--democolor2: #FFFFFF;
--democolor3: #0585fe;
--democolor4: rgba(26, 26, 26, 1);
--democolor5: rgba(36, 36, 36, 1);
--democolor6: rgba(53, 53, 53, 1);
--democolor7: rgba(180, 180, 180, 1);
}
body {
margin: 0px;
padding: 0px;
height: 100vh;
width: 100vw;
background-color: var(--democolor5);
font-family: verdana,sans-serif;
color: var(--democolor7);
}
code {
background-color: var(--democolor6);
}
.wrapper {
display: flex;
align-items: stretch;
height: 100%;
width: 100%;
}
.spaced-row {
display: flex;
flex-direction: row;
justify-content: space-evenly;
}
#infocontainer {
padding: 0.5em;
font-size: large;
min-height: 15vh;
max-height: 15vh;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
#infoinstructions {
background-color: var(--democolor4);
padding: 0.5em;
font-size: medium;
flex-grow: 1;
overflow-y: auto;
}
#content {
width: 100%;
flex-direction: column;
display: flex;
align-items: initial;
justify-content: center;
}
#exampletitle {
padding: 1em;
display: flex;
flex-direction: column;
justify-content: center;
align-items: baseline;
}
#sidebar {
min-width: 250px;
max-width: 250px;
background-color: var(--democolor4);
transition: all 0.3s;
font-size: small;
border-color: var(--democolor4);
border-style: solid;
border-width: 0.33em 0.33em 0em 0em;
align-content: flex-start;
display: flex;
flex-direction: column;
}
#sidebar-tab-header {
width: 100%;
}
#sidebar-header {
padding: 0.25rem 2rem 0.25rem 0.5rem;
background-color: var(--democolor5);
border-top: 1px solid var(--democolor3);
border-radius: 5px 5px 0px 0px;
margin-left: 1em;
width: -moz-fit-content;
width: fit-content;
}
#sidebarContent {
max-height:100%;
overflow-y:auto;
background-color: var(--democolor5);
flex-grow: 1;
padding-left: 1em;
padding-right: 1em;
}
#sidebar-example-selector {
background-color: var(--democolor5);
padding-top: 1em;
padding-bottom: 1em;
padding-left: 1em;
}
#psdemotext {
font-size: large;
}
#playercontainer {
background-color: var(--democolor0);
flex-grow: 1;
font-family: 'Montserrat', sans-serif;
}
select {
font-size: large;
padding: 0.5em;
color: var(--democolor7);
background-color: var(--democolor0);
border: 2px solid var(--democolor6);
outline: none !important;
border-radius: 5px;
}
select:hover {
color: var(--democolor2);
}
a, a:hover, a:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
#sidebar ul.components {
padding: 20px 0;
}
#sidebar ul p {
color: #fff;
padding: 10px;
}
#sidebar ul li a {
padding: 10px;
font-size: 1.1em;
display: block;
}
#sidebar ul li a:hover {
color: #7386D5;
background: #fff;
}
#sidebar ul li.active > a, a[aria-expanded="true"] {
color: #fff;
background: #212f44;
/*#f90;*/
}
ul ul a {
font-size: 0.9em !important;
padding-left: 30px !important;
background: #354b6d;
}
a[data-toggle="collapse"] {
position: relative;
}
.dropdown-toggle::after {
display: block;
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
.characterBtn {
width: 100%;
cursor: pointer;
}
.characterBtn:hover {
box-shadow: var(--democolor3) 0px 0px 0px 3px;
}
.characterBtn:active {
box-shadow: var(--democolor5) 0px 0px 0px 3px;
:root {
--democolor0: rgba(15, 15, 15, 1);
--democolor1: #000000;
--democolor2: #FFFFFF;
--democolor3: #0585fe;
--democolor4: rgba(26, 26, 26, 1);
--democolor5: rgba(36, 36, 36, 1);
--democolor6: rgba(53, 53, 53, 1);
--democolor7: rgba(180, 180, 180, 1);
}
body {
margin: 0px;
padding: 0px;
height: 100vh;
width: 100vw;
background-color: var(--democolor5);
font-family: verdana,sans-serif;
color: var(--democolor7);
}
code {
background-color: var(--democolor6);
}
.wrapper {
display: flex;
align-items: stretch;
height: 100%;
width: 100%;
}
.spaced-row {
display: flex;
flex-direction: row;
flex-wrap: wrap;
justify-content: space-evenly;
row-gap: 1vh;
}
#infocontainer {
padding: 0.5em;
font-size: large;
min-height: 15vh;
max-height: 15vh;
display: flex;
flex-direction: column;
justify-content: flex-start;
}
#infoinstructions {
background-color: var(--democolor4);
padding: 0.5em;
font-size: medium;
flex-grow: 1;
overflow-y: auto;
}
#content {
width: 100%;
flex-direction: column;
display: flex;
align-items: initial;
justify-content: center;
}
#exampletitle {
padding: 1em;
display: flex;
flex-direction: column;
justify-content: center;
align-items: baseline;
}
#sidebar {
min-width: 250px;
max-width: 250px;
background-color: var(--democolor4);
transition: all 0.3s;
font-size: small;
border-color: var(--democolor4);
border-style: solid;
border-width: 0.33em 0.33em 0em 0em;
align-content: flex-start;
display: flex;
flex-direction: column;
}
#sidebar-tab-header {
width: 100%;
}
#sidebar-header {
padding: 0.25rem 2rem 0.25rem 0.5rem;
background-color: var(--democolor5);
border-top: 1px solid var(--democolor3);
border-radius: 5px 5px 0px 0px;
margin-left: 1em;
width: -moz-fit-content;
width: fit-content;
}
#sidebarContent {
max-height:100%;
overflow-y:auto;
background-color: var(--democolor5);
flex-grow: 1;
padding-left: 1em;
padding-right: 1em;
}
#sidebar-example-selector {
background-color: var(--democolor5);
padding-top: 1em;
padding-bottom: 1em;
padding-left: 1em;
}
#psdemotext {
font-size: large;
}
#playercontainer {
background-color: var(--democolor0);
flex-grow: 1;
font-family: 'Montserrat', sans-serif;
}
select {
font-size: large;
padding: 0.5em;
color: var(--democolor7);
background-color: var(--democolor0);
border: 2px solid var(--democolor6);
outline: none !important;
border-radius: 5px;
}
select:hover {
color: var(--democolor2);
}
a, a:hover, a:focus {
color: inherit;
text-decoration: none;
transition: all 0.3s;
}
#sidebar ul.components {
padding: 20px 0;
}
#sidebar ul p {
color: #fff;
padding: 10px;
}
#sidebar ul li a {
padding: 10px;
font-size: 1.1em;
display: block;
}
#sidebar ul li a:hover {
color: #7386D5;
background: #fff;
}
#sidebar ul li.active > a, a[aria-expanded="true"] {
color: #fff;
background: #212f44;
/*#f90;*/
}
ul ul a {
font-size: 0.9em !important;
padding-left: 30px !important;
background: #354b6d;
}
a[data-toggle="collapse"] {
position: relative;
}
.dropdown-toggle::after {
display: block;
position: absolute;
top: 50%;
right: 20px;
transform: translateY(-50%);
}
.characterBtn {
width: 100%;
cursor: pointer;
}
.characterBtn:hover {
box-shadow: var(--democolor3) 0px 0px 0px 3px;
}
.characterBtn:active {
box-shadow: var(--democolor5) 0px 0px 0px 3px;
}

View File

Before

Width:  |  Height:  |  Size: 30 KiB

After

Width:  |  Height:  |  Size: 30 KiB

View File

Before

Width:  |  Height:  |  Size: 34 KiB

After

Width:  |  Height:  |  Size: 34 KiB

View File

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 15 KiB

View File

Before

Width:  |  Height:  |  Size: 5.5 KiB

After

Width:  |  Height:  |  Size: 5.5 KiB

View File

@ -1,28 +1,28 @@
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: apply a font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<!-- Optional: set a title for your page -->
<title>Pixel Streaming</title>
</head>
<!-- The Pixel Streaming player fills 100% of its parent element but body has a 0px height unless filled with content. As such, we explicitly force the body to be 100% of the viewport height -->
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
</body>
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: apply a font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<!-- Optional: set a title for your page -->
<title>Pixel Streaming</title>
</head>
<!-- The Pixel Streaming player fills 100% of its parent element but body has a 0px height unless filled with content. As such, we explicitly force the body to be 100% of the viewport height -->
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
</body>
</html>

View File

@ -1,24 +1,32 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2';
const PixelStreamingApplicationStyles =
new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();
document.body.onload = function() {
// Example of how to set the logger level
// Logger.SetLoggerVerbosity(10);
// Create a config object
const config = new Config({ useUrlParams: true });
// Create a Native DOM delegate instance that implements the Delegate interface class
const stream = new PixelStreaming(config);
const application = new Application({
stream,
onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode)
});
// document.getElementById("centrebox").appendChild(application.rootElement);
document.body.appendChild(application.rootElement);
}
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4';
const PixelStreamingApplicationStyles =
new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();
// expose the pixel streaming object for hooking into. tests etc.
declare global {
interface Window { pixelStreaming: PixelStreaming; }
}
document.body.onload = function() {
// Example of how to set the logger level
// Logger.SetLoggerVerbosity(10);
// Create a config object
const config = new Config({ useUrlParams: true });
// Create a Native DOM delegate instance that implements the Delegate interface class
const stream = new PixelStreaming(config);
const application = new Application({
stream,
onColorModeChanged: (isLightMode) => PixelStreamingApplicationStyles.setColorMode(isLightMode)
});
// document.getElementById("centrebox").appendChild(application.rootElement);
document.body.appendChild(application.rootElement);
window.pixelStreaming = stream;
}

View File

@ -1,61 +1,61 @@
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<title>Pixel Streaming Showcase</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<!-- Optional: load a custom font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Apply the showcase CSS -->
<link type="text/css" rel="stylesheet" href="./assets/css/showcase.css">
</head>
<body>
<!-- Load images in page body load -->
<img src="./assets/images/Aurora.jpg" style="display: none;" />
<img src="./assets/images/Crunch.jpg" style="display: none;" />
<div class="wrapper">
<!-- The details panels for the examples sidebar -->
<div id="sidebar">
<div id="exampletitle">
<p id="psdemotext"> Select an example:</p>
<select id="exampleSelect" onchange="onExampleChanged(event)" title="Select an example...">
<option>Getting Started</option>
<option>Send Data to UE</option>
<option>Send Commands to UE</option>
</select>
</div>
<div id="sidebar-header">Details</div>
<div id="sidebarContent"></div>
</div>
<div id="content">
<div id="playercontainer"></div>
<div id="infocontainer">
<div id="infoinstructions">
Information here
</div>
</div>
</div>
</div>
</body>
</html>
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html lang="en-US">
<head>
<title>Pixel Streaming Showcase</title>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<!-- Optional: load a custom font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Apply the showcase CSS -->
<link type="text/css" rel="stylesheet" href="./assets/css/showcase.css">
</head>
<body>
<!-- Load images in page body load -->
<img src="./assets/images/Aurora.jpg" style="display: none;" />
<img src="./assets/images/Crunch.jpg" style="display: none;" />
<div class="wrapper">
<!-- The details panels for the examples sidebar -->
<div id="sidebar">
<div id="exampletitle">
<p id="psdemotext"> Select an example:</p>
<select id="exampleSelect" onchange="onExampleChanged(event)" title="Select an example...">
<option>Getting Started</option>
<option>Send Data to UE</option>
<option>Send Commands to UE</option>
</select>
</div>
<div id="sidebar-header">Details</div>
<div id="sidebarContent"></div>
</div>
<div id="content">
<div id="playercontainer"></div>
<div id="infocontainer">
<div id="infoinstructions">
Information here
</div>
</div>
</div>
</div>
</body>
</html>

View File

@ -1,7 +1,7 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2';
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4';
export const PixelStreamingApplicationStyles = new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();
@ -290,6 +290,13 @@ class Showcase {
statgpuBtn.innerText = "stat pixelstreaming";
consoleCmdBtnsContainer.appendChild(statgpuBtn);
//stat pixelStreamingGraphs
const statGraphBtn = document.createElement("button");
statGraphBtn.classList.add("btn-flat");
statGraphBtn.onclick = () => { this._pixelStreaming.emitConsoleCommand("stat pixelstreaminggraphs"); }
statGraphBtn.innerText = "stat pixelstreaminggraphs";
consoleCmdBtnsContainer.appendChild(statGraphBtn);
}
}

View File

@ -1,7 +1,7 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, Flags, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2';
import { Config, Flags, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { Application, PixelStreamingApplicationStyle } from '@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4';
const PixelStreamingApplicationStyles =
new PixelStreamingApplicationStyle();
PixelStreamingApplicationStyles.applyStyleSheet();

View File

@ -1,48 +1,48 @@
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: apply a font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<style>
#clickToPlayElement.visible {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
#clickToPlayElement {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
};
</style>
<!-- Optional: set a title for your page -->
<title>Pixel Streaming</title>
</head>
<!-- The Pixel Streaming player fills 100% of its parent element but body has a 0px height unless filled with content. As such, we explicitly force the body to be 100% of the viewport height -->
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
<div id="videoParentElement"></div>
<div id="clickToPlayElement">
<div>Click to play</div>
</div>
</body>
<!-- Copyright Epic Games, Inc. All Rights Reserved. -->
<!DOCTYPE HTML>
<html style="width: 100%; height: 100%">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- Optional: apply a font -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Michroma&family=Montserrat:wght@600&display=swap" rel="stylesheet">
<!-- Optional: set some favicons -->
<link rel="shortcut icon" href="./assets/images/favicon.ico" type="image/x-icon">
<link rel="icon" type="image/png" sizes="96x96" href="./assets/images/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="32x32" href="./assets/images/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="16x16" href="./assets/images/favicon-16x16.png">
<style>
#clickToPlayElement.visible {
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
}
#clickToPlayElement {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
display: none;
};
</style>
<!-- Optional: set a title for your page -->
<title>Pixel Streaming</title>
</head>
<!-- The Pixel Streaming player fills 100% of its parent element but body has a 0px height unless filled with content. As such, we explicitly force the body to be 100% of the viewport height -->
<body style="width: 100vw; height: 100vh; min-height: -webkit-fill-available; font-family: 'Montserrat'; margin: 0px">
<div id="videoParentElement"></div>
<div id="clickToPlayElement">
<div>Click to play</div>
</div>
</body>
</html>

View File

@ -1,6 +1,6 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { Config, PixelStreaming } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
document.body.onload = function() {
// Example of how to set the logger level
@ -13,6 +13,7 @@ document.body.onload = function() {
AutoConnect: true,
ss: "ws://localhost:80",
StartVideoMuted: true,
WaitForStreamer: true,
}
});

View File

@ -1,12 +1,12 @@
{
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.2",
"version": "0.2.0",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4",
"version": "0.0.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.2",
"version": "0.2.0",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4",
"version": "0.0.3",
"license": "MIT",
"dependencies": {
"sdp": "^3.1.0"
@ -56,17 +56,89 @@
}
},
"node_modules/@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"dependencies": {
"@babel/highlight": "^7.18.6"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/code-frame/node_modules/ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"dependencies": {
"color-convert": "^1.9.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"dependencies": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"dependencies": {
"color-name": "1.1.3"
}
},
"node_modules/@babel/code-frame/node_modules/color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"node_modules/@babel/code-frame/node_modules/escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true,
"engines": {
"node": ">=0.8.0"
}
},
"node_modules/@babel/code-frame/node_modules/has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true,
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/code-frame/node_modules/supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"dependencies": {
"has-flag": "^3.0.0"
},
"engines": {
"node": ">=4"
}
},
"node_modules/@babel/compat-data": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.21.0.tgz",
@ -116,12 +188,12 @@
}
},
"node_modules/@babel/generator": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz",
"integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.21.3",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@ -174,34 +246,34 @@
"dev": true
},
"node_modules/@babel/helper-environment-visitor": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-function-name": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
"integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"dependencies": {
"@babel/template": "^7.20.7",
"@babel/types": "^7.21.0"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-hoist-variables": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"dependencies": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
@ -260,30 +332,30 @@
}
},
"node_modules/@babel/helper-split-export-declaration": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"dependencies": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.22.5"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-string-parser": {
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true,
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/helper-validator-identifier": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true,
"engines": {
"node": ">=6.9.0"
@ -313,13 +385,13 @@
}
},
"node_modules/@babel/highlight": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"dependencies": {
"@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"engines": {
@ -398,9 +470,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz",
"integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true,
"bin": {
"parser": "bin/babel-parser.js"
@ -572,33 +644,33 @@
}
},
"node_modules/@babel/template": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
},
"engines": {
"node": ">=6.9.0"
}
},
"node_modules/@babel/traverse": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz",
"integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"dependencies": {
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.21.3",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.21.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.21.3",
"@babel/types": "^7.21.3",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@ -616,13 +688,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz",
"integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"dependencies": {
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -6092,9 +6164,9 @@
}
},
"node_modules/tough-cookie": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"dependencies": {
"psl": "^1.1.33",
@ -6653,9 +6725,9 @@
"dev": true
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -6817,12 +6889,71 @@
}
},
"@babel/code-frame": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.18.6.tgz",
"integrity": "sha512-TDCmlK5eOvH+eH7cdAFlNXeVJqWIQ7gW9tY1GJIpUtFb6CmjVyq2VM3u71bOyR8CRihcCgMUYoDNyLXao3+70Q==",
"version": "7.22.13",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.22.13.tgz",
"integrity": "sha512-XktuhWlJ5g+3TJXc5upd9Ks1HutSArik6jf2eAjYFyIOf4ej3RN+184cZbzDvbPnuTJIUhPKKJE3cIsYTiAT3w==",
"dev": true,
"requires": {
"@babel/highlight": "^7.18.6"
"@babel/highlight": "^7.22.13",
"chalk": "^2.4.2"
},
"dependencies": {
"ansi-styles": {
"version": "3.2.1",
"resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz",
"integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==",
"dev": true,
"requires": {
"color-convert": "^1.9.0"
}
},
"chalk": {
"version": "2.4.2",
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
"dev": true,
"requires": {
"ansi-styles": "^3.2.1",
"escape-string-regexp": "^1.0.5",
"supports-color": "^5.3.0"
}
},
"color-convert": {
"version": "1.9.3",
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
"dev": true,
"requires": {
"color-name": "1.1.3"
}
},
"color-name": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
"integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==",
"dev": true
},
"escape-string-regexp": {
"version": "1.0.5",
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
"integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
"dev": true
},
"has-flag": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz",
"integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==",
"dev": true
},
"supports-color": {
"version": "5.5.0",
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
"dev": true,
"requires": {
"has-flag": "^3.0.0"
}
}
}
},
"@babel/compat-data": {
@ -6863,12 +6994,12 @@
}
},
"@babel/generator": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.21.3.tgz",
"integrity": "sha512-QS3iR1GYC/YGUnW7IdggFeN5c1poPUurnGttOV/bZgPGV+izC/D8HnD6DLwod0fsatNyVn1G3EVWMYIF0nHbeA==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.0.tgz",
"integrity": "sha512-lN85QRR+5IbYrMWM6Y4pE/noaQtg4pNiqeNGX60eqOfo6gtEj6uw/JagelB8vVztSd7R6M5n1+PQkDbHbBRU4g==",
"dev": true,
"requires": {
"@babel/types": "^7.21.3",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
@ -6911,28 +7042,28 @@
}
},
"@babel/helper-environment-visitor": {
"version": "7.18.9",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.18.9.tgz",
"integrity": "sha512-3r/aACDJ3fhQ/EVgFy0hpj8oHyHpQc+LPtJoY9SzTThAsStm4Ptegq92vqKoE3vD706ZVFWITnMnxucw+S9Ipg==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz",
"integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==",
"dev": true
},
"@babel/helper-function-name": {
"version": "7.21.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.21.0.tgz",
"integrity": "sha512-HfK1aMRanKHpxemaY2gqBmL04iAPOPRj7DxtNbiDOrJK+gdwkiNRVpCpUJYbUT+aZyemKN8brqTOxzCaG6ExRg==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz",
"integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==",
"dev": true,
"requires": {
"@babel/template": "^7.20.7",
"@babel/types": "^7.21.0"
"@babel/template": "^7.22.15",
"@babel/types": "^7.23.0"
}
},
"@babel/helper-hoist-variables": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.18.6.tgz",
"integrity": "sha512-UlJQPkFqFULIcyW5sbzgbkxn2FKRgwWiRexcuaR8RNJRy8+LLveqPjwZV/bwrLZCN0eUHD/x8D0heK1ozuoo6Q==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz",
"integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==",
"dev": true,
"requires": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.22.5"
}
},
"@babel/helper-module-imports": {
@ -6976,24 +7107,24 @@
}
},
"@babel/helper-split-export-declaration": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.18.6.tgz",
"integrity": "sha512-bde1etTx6ZyTmobl9LLMMQsaizFVZrquTEHOqKeQESMKo4PlObf+8+JA25ZsIpZhT/WEd39+vOdLXAFG/nELpA==",
"version": "7.22.6",
"resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz",
"integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==",
"dev": true,
"requires": {
"@babel/types": "^7.18.6"
"@babel/types": "^7.22.5"
}
},
"@babel/helper-string-parser": {
"version": "7.19.4",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.19.4.tgz",
"integrity": "sha512-nHtDoQcuqFmwYNYPz3Rah5ph2p8PFeFCsZk9A/48dPc/rGocJ5J3hAAZ7pb76VWX3fZKu+uEr/FhH5jLx7umrw==",
"version": "7.22.5",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.22.5.tgz",
"integrity": "sha512-mM4COjgZox8U+JcXQwPijIZLElkgEpO5rsERVDJTc2qfCDfERyob6k5WegS14SX18IIjv+XD+GrqNumY5JRCDw==",
"dev": true
},
"@babel/helper-validator-identifier": {
"version": "7.19.1",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.19.1.tgz",
"integrity": "sha512-awrNfaMtnHUr653GgGEs++LlAvW6w+DcPrOliSMXWCKo597CwL5Acf/wWdNkf/tfEQE3mjkeD1YOVZOUV/od1w==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz",
"integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==",
"dev": true
},
"@babel/helper-validator-option": {
@ -7014,13 +7145,13 @@
}
},
"@babel/highlight": {
"version": "7.18.6",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.18.6.tgz",
"integrity": "sha512-u7stbOuYjaPezCuLj29hNW1v64M2Md2qupEKP1fHc7WdOA3DgLh37suiSrZYY7haUB7iBeQZ9P1uiRF359do3g==",
"version": "7.22.20",
"resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.22.20.tgz",
"integrity": "sha512-dkdMCN3py0+ksCgYmGG8jKeGA/8Tk+gJwSYYlFGxG5lmhfKNoAy004YpLxpS1W2J8m/EK2Ew+yOs9pVRwO89mg==",
"dev": true,
"requires": {
"@babel/helper-validator-identifier": "^7.18.6",
"chalk": "^2.0.0",
"@babel/helper-validator-identifier": "^7.22.20",
"chalk": "^2.4.2",
"js-tokens": "^4.0.0"
},
"dependencies": {
@ -7083,9 +7214,9 @@
}
},
"@babel/parser": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.21.3.tgz",
"integrity": "sha512-lobG0d7aOfQRXh8AyklEAgZGvA4FShxo6xQbUrrT/cNBPUdIDojlokwJsQyCC/eKia7ifqM0yP+2DRZ4WKw2RQ==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.23.0.tgz",
"integrity": "sha512-vvPKKdMemU85V9WE/l5wZEmImpCtLqbnTvqDS2U1fJ96KrxoW7KrXhNsNCblQlg8Ck4b85yxdTyelsMUgFUXiw==",
"dev": true
},
"@babel/plugin-syntax-async-generators": {
@ -7206,30 +7337,30 @@
}
},
"@babel/template": {
"version": "7.20.7",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.20.7.tgz",
"integrity": "sha512-8SegXApWe6VoNw0r9JHpSteLKTpTiLZ4rMlGIm9JQ18KiCtyQiAMEazujAHrUS5flrcqYZa75ukev3P6QmUwUw==",
"version": "7.22.15",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.22.15.tgz",
"integrity": "sha512-QPErUVm4uyJa60rkI73qneDacvdvzxshT3kksGqlGWYdOTIUOwJ7RDUL8sGqslY1uXWSL6xMFKEXDS3ox2uF0w==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.18.6",
"@babel/parser": "^7.20.7",
"@babel/types": "^7.20.7"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.21.3.tgz",
"integrity": "sha512-XLyopNeaTancVitYZe2MlUEvgKb6YVVPXzofHgqHijCImG33b/uTurMS488ht/Hbsb2XK3U2BnSTxKVNGV3nGQ==",
"version": "7.23.2",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.23.2.tgz",
"integrity": "sha512-azpe59SQ48qG6nu2CzcMLbxUudtN+dOM9kDbUqGq3HXUJRlo7i8fvPoxQUzYgLZ4cMVmuZgm8vvBpNeRhd6XSw==",
"dev": true,
"requires": {
"@babel/code-frame": "^7.18.6",
"@babel/generator": "^7.21.3",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.21.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.21.3",
"@babel/types": "^7.21.3",
"@babel/code-frame": "^7.22.13",
"@babel/generator": "^7.23.0",
"@babel/helper-environment-visitor": "^7.22.20",
"@babel/helper-function-name": "^7.23.0",
"@babel/helper-hoist-variables": "^7.22.5",
"@babel/helper-split-export-declaration": "^7.22.6",
"@babel/parser": "^7.23.0",
"@babel/types": "^7.23.0",
"debug": "^4.1.0",
"globals": "^11.1.0"
},
@ -7243,13 +7374,13 @@
}
},
"@babel/types": {
"version": "7.21.3",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.21.3.tgz",
"integrity": "sha512-sBGdETxC+/M4o/zKC0sl6sjWv62WFR/uzxrJ6uYyMLZOUlPnwzw0tKgVHOXxaAd5l2g8pEDM5RZ495GPQI77kg==",
"version": "7.23.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.23.0.tgz",
"integrity": "sha512-0oIyUfKoI3mSqMvsxBdclDwxXKXAUA8v/apZbc+iSyARYou1o8ZGDxbUYyLFoW2arqS2jDGqJuZvv1d/io1axg==",
"dev": true,
"requires": {
"@babel/helper-string-parser": "^7.19.4",
"@babel/helper-validator-identifier": "^7.19.1",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@ -11446,9 +11577,9 @@
}
},
"tough-cookie": {
"version": "4.1.2",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.2.tgz",
"integrity": "sha512-G9fqXWoYFZgTc2z8Q5zaHy/vJMjm+WV0AkAeHxVCQiEB1b+dGvWzFW6QV07cY5jQ5gRkeid2qIkzkxUnmoQZUQ==",
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz",
"integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==",
"dev": true,
"requires": {
"psl": "^1.1.33",
@ -11839,9 +11970,9 @@
"dev": true
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.4",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.4.tgz",
"integrity": "sha512-2V81OA4ugVo5pRo46hAoD2ivUJx8jXmWXfUkY4KFNw0hEptvN0QfH3K4nHiwzGeKl5rFKedV48QVoqYavy4YpA==",
"dev": true
},
"wrap-ansi": {

View File

@ -1,7 +1,7 @@
{
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.2",
"version": "0.4.0",
"description": "Frontend library for Pixel Streaming",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4",
"version": "0.0.3",
"description": "Frontend library for Unreal Engine 5.4 Pixel Streaming",
"main": "dist/lib-pixelstreamingfrontend.js",
"module": "dist/lib-pixelstreamingfrontend.esm.js",
"types": "types/pixelstreamingfrontend.d.ts",

View File

@ -2,7 +2,7 @@
The core library for the browser/client side of Pixel Streaming experiences. **This library contains no UI.**
See [lib-pixelstreamingfrontend-ui](/Frontend/implementations/EpicGames) for an example of how to build UI on top of this library.
See [lib-pixelstreamingfrontend-ui](/Frontend/implementations/typescript) for an example of how to build UI on top of this library.
### Key features
- Create a websocket connection to communicate with the signalling server.
@ -11,5 +11,5 @@ See [lib-pixelstreamingfrontend-ui](/Frontend/implementations/EpicGames) for an
- Opens a datachannel connection sending and receiving custom data (in addition to input).
### Adding it to your project
`npm i @epicgames-ps/lib-pixelstreamingfrontend-ue5.2`
`npm i @epicgames-ps/lib-pixelstreamingfrontend-ue5.4`

View File

@ -23,7 +23,6 @@ export class Flags {
static FakeMouseWithTouches = 'FakeMouseWithTouches' as const;
static IsQualityController = 'ControlsQuality' as const;
static MatchViewportResolution = 'MatchViewportRes' as const;
static PreferSFU = 'preferSFU' as const;
static StartVideoMuted = 'StartVideoMuted' as const;
static SuppressBrowserKeys = 'SuppressBrowserKeys' as const;
static UseMic = 'UseMic' as const;
@ -32,6 +31,7 @@ export class Flags {
static TouchInput = 'TouchInput' as const;
static GamepadInput = 'GamepadInput' as const;
static XRControllerInput = 'XRControllerInput' as const;
static WaitForStreamer = "WaitForStreamer" as const;
}
export type FlagsKeys = Exclude<keyof typeof Flags, 'prototype'>;
@ -54,6 +54,7 @@ export class NumericParameters {
static WebRTCMinBitrate = 'WebRTCMinBitrate' as const;
static WebRTCMaxBitrate = 'WebRTCMaxBitrate' as const;
static MaxReconnectAttempts = 'MaxReconnectAttempts' as const;
static StreamerAutoJoinInterval = 'StreamerAutoJoinInterval' as const;
}
export type NumericParametersKeys = Exclude<
@ -155,10 +156,7 @@ export class Config {
constructor(config: ConfigParams = {}) {
const { initialSettings, useUrlParams } = config;
this._useUrlParams = !!useUrlParams;
this.populateDefaultSettings(this._useUrlParams);
if (initialSettings) {
this.setSettings(initialSettings);
}
this.populateDefaultSettings(this._useUrlParams, initialSettings);
}
/**
@ -172,7 +170,7 @@ export class Config {
/**
* Populate the default settings for a Pixel Streaming application
*/
private populateDefaultSettings(useUrlParams: boolean): void {
private populateDefaultSettings(useUrlParams: boolean, settings: Partial<AllSettings>): void {
/**
* Text Parameters
*/
@ -183,13 +181,15 @@ export class Config {
TextParameters.SignallingServerUrl,
'Signalling url',
'Url of the signalling server',
(location.protocol === 'https:' ? 'wss://' : 'ws://') +
window.location.hostname +
// for readability, we omit the port if it's 80
(window.location.port === '80' ||
window.location.port === ''
? ''
: `:${window.location.port}`),
settings && settings.hasOwnProperty(TextParameters.SignallingServerUrl) ?
settings[TextParameters.SignallingServerUrl] :
(location.protocol === 'https:' ? 'wss://' : 'ws://') +
window.location.hostname +
// for readability, we omit the port if it's 80
(window.location.port === '80' ||
window.location.port === ''
? ''
: `:${window.location.port}`),
useUrlParams
)
);
@ -200,7 +200,9 @@ export class Config {
OptionParameters.StreamerId,
'Streamer ID',
'The ID of the streamer to stream.',
'',
settings && settings.hasOwnProperty(OptionParameters.StreamerId) ?
settings[OptionParameters.StreamerId] :
'',
[],
useUrlParams
)
@ -216,29 +218,31 @@ export class Config {
'Preferred Codec',
'The preferred codec to be used during codec negotiation',
'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42e01f',
(function (): Array<string> {
const browserSupportedCodecs: Array<string> = [];
// Try get the info needed from the RTCRtpReceiver. This is only available on chrome
if (!RTCRtpReceiver.getCapabilities) {
browserSupportedCodecs.push('Only available on Chrome');
return browserSupportedCodecs;
}
const matcher = /(VP\d|H26\d|AV1).*/;
const codecs =
RTCRtpReceiver.getCapabilities('video').codecs;
codecs.forEach((codec) => {
const str =
codec.mimeType.split('/')[1] +
' ' +
(codec.sdpFmtpLine || '');
const match = matcher.exec(str);
if (match !== null) {
browserSupportedCodecs.push(str);
settings && settings.hasOwnProperty(OptionParameters.PreferredCodec) ?
[settings[OptionParameters.PreferredCodec]] :
(function (): Array<string> {
const browserSupportedCodecs: Array<string> = [];
// Try get the info needed from the RTCRtpReceiver. This is only available on chrome
if (!RTCRtpReceiver.getCapabilities) {
browserSupportedCodecs.push('Only available on Chrome');
return browserSupportedCodecs;
}
});
return browserSupportedCodecs;
})(),
const matcher = /(VP\d|H26\d|AV1).*/;
const codecs =
RTCRtpReceiver.getCapabilities('video').codecs;
codecs.forEach((codec) => {
const str =
codec.mimeType.split('/')[1] +
' ' +
(codec.sdpFmtpLine || '');
const match = matcher.exec(str);
if (match !== null) {
browserSupportedCodecs.push(str);
}
});
return browserSupportedCodecs;
})(),
useUrlParams
)
);
@ -253,7 +257,9 @@ export class Config {
Flags.AutoConnect,
'Auto connect to stream',
'Whether we should attempt to auto connect to the signalling server or show a click to start prompt.',
false,
settings && settings.hasOwnProperty(Flags.AutoConnect) ?
settings[Flags.AutoConnect] :
false,
useUrlParams
)
);
@ -264,7 +270,9 @@ export class Config {
Flags.AutoPlayVideo,
'Auto play video',
'When video is ready automatically start playing it as opposed to showing a play button.',
true,
settings && settings.hasOwnProperty(Flags.AutoPlayVideo) ?
settings[Flags.AutoPlayVideo] :
true,
useUrlParams
)
);
@ -275,7 +283,9 @@ export class Config {
Flags.BrowserSendOffer,
'Browser send offer',
'Browser will initiate the WebRTC handshake by sending the offer to the streamer',
false,
settings && settings.hasOwnProperty(Flags.BrowserSendOffer) ?
settings[Flags.BrowserSendOffer] :
false,
useUrlParams
)
);
@ -286,7 +296,9 @@ export class Config {
Flags.UseMic,
'Use microphone',
'Make browser request microphone access and open an input audio track.',
false,
settings && settings.hasOwnProperty(Flags.UseMic) ?
settings[Flags.UseMic] :
false,
useUrlParams
)
);
@ -297,7 +309,9 @@ export class Config {
Flags.StartVideoMuted,
'Start video muted',
'Video will start muted if true.',
false,
settings && settings.hasOwnProperty(Flags.StartVideoMuted) ?
settings[Flags.StartVideoMuted] :
false,
useUrlParams
)
);
@ -308,18 +322,9 @@ export class Config {
Flags.SuppressBrowserKeys,
'Suppress browser keys',
'Suppress certain browser keys that we use in UE, for example F5 to show shader complexity instead of refresh the page.',
true,
useUrlParams
)
);
this.flags.set(
Flags.PreferSFU,
new SettingFlag(
Flags.PreferSFU,
'Prefer SFU',
'Try to connect to the SFU instead of P2P.',
false,
settings && settings.hasOwnProperty(Flags.SuppressBrowserKeys) ?
settings[Flags.SuppressBrowserKeys] :
true,
useUrlParams
)
);
@ -330,7 +335,9 @@ export class Config {
Flags.IsQualityController,
'Is quality controller?',
'True if this peer controls stream quality',
true,
settings && settings.hasOwnProperty(Flags.IsQualityController) ?
settings[Flags.IsQualityController] :
true,
useUrlParams
)
);
@ -341,7 +348,9 @@ export class Config {
Flags.ForceMonoAudio,
'Force mono audio',
'Force browser to request mono audio in the SDP',
false,
settings && settings.hasOwnProperty(Flags.ForceMonoAudio) ?
settings[Flags.ForceMonoAudio] :
false,
useUrlParams
)
);
@ -352,7 +361,9 @@ export class Config {
Flags.ForceTURN,
'Force TURN',
'Only generate TURN/Relayed ICE candidates.',
false,
settings && settings.hasOwnProperty(Flags.ForceTURN) ?
settings[Flags.ForceTURN] :
false,
useUrlParams
)
);
@ -363,7 +374,9 @@ export class Config {
Flags.AFKDetection,
'AFK if idle',
'Timeout the experience if user is AFK for a period.',
false,
settings && settings.hasOwnProperty(Flags.AFKDetection) ?
settings[Flags.AFKDetection] :
false,
useUrlParams
)
);
@ -374,7 +387,9 @@ export class Config {
Flags.MatchViewportResolution,
'Match viewport resolution',
'Pixel Streaming will be instructed to dynamically resize the video stream to match the size of the video element.',
false,
settings && settings.hasOwnProperty(Flags.MatchViewportResolution) ?
settings[Flags.MatchViewportResolution] :
false,
useUrlParams
)
);
@ -385,7 +400,9 @@ export class Config {
Flags.HoveringMouseMode,
'Control Scheme: Locked Mouse',
'Either locked mouse, where the pointer is consumed by the video and locked to it, or hovering mouse, where the mouse is not consumed.',
false,
settings && settings.hasOwnProperty(Flags.HoveringMouseMode) ?
settings[Flags.HoveringMouseMode] :
false,
useUrlParams,
(isHoveringMouse: boolean, setting: SettingBase) => {
setting.label = `Control Scheme: ${isHoveringMouse ? 'Hovering' : 'Locked'} Mouse`;
@ -399,7 +416,9 @@ export class Config {
Flags.FakeMouseWithTouches,
'Fake mouse with touches',
'A single finger touch is converted into a mouse event. This allows a non-touch application to be controlled partially via a touch device.',
false,
settings && settings.hasOwnProperty(Flags.FakeMouseWithTouches) ?
settings[Flags.FakeMouseWithTouches] :
true,
useUrlParams
)
);
@ -410,7 +429,9 @@ export class Config {
Flags.KeyboardInput,
'Keyboard input',
'If enabled, send keyboard events to streamer',
true,
settings && settings.hasOwnProperty(Flags.KeyboardInput) ?
settings[Flags.KeyboardInput] :
true,
useUrlParams
)
);
@ -421,7 +442,9 @@ export class Config {
Flags.MouseInput,
'Mouse input',
'If enabled, send mouse events to streamer',
true,
settings && settings.hasOwnProperty(Flags.MouseInput) ?
settings[Flags.MouseInput] :
true,
useUrlParams
)
);
@ -432,7 +455,9 @@ export class Config {
Flags.TouchInput,
'Touch input',
'If enabled, send touch events to streamer',
true,
settings && settings.hasOwnProperty(Flags.TouchInput) ?
settings[Flags.TouchInput] :
true,
useUrlParams
)
);
@ -443,7 +468,9 @@ export class Config {
Flags.GamepadInput,
'Gamepad input',
'If enabled, send gamepad events to streamer',
true,
settings && settings.hasOwnProperty(Flags.GamepadInput) ?
settings[Flags.GamepadInput] :
true,
useUrlParams
)
);
@ -454,7 +481,22 @@ export class Config {
Flags.XRControllerInput,
'XR controller input',
'If enabled, send XR controller events to streamer',
true,
settings && settings.hasOwnProperty(Flags.XRControllerInput) ?
settings[Flags.XRControllerInput] :
true,
useUrlParams
)
);
this.flags.set(
Flags.WaitForStreamer,
new SettingFlag(
Flags.WaitForStreamer,
'Wait for streamer',
'Will continue trying to connect to the first streamer available.',
settings && settings.hasOwnProperty(Flags.WaitForStreamer) ?
settings[Flags.WaitForStreamer] :
true,
useUrlParams
)
);
@ -471,7 +513,9 @@ export class Config {
'The time (in seconds) it takes for the application to time out if AFK timeout is enabled.',
0 /*min*/,
600 /*max*/,
120 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.AFKTimeoutSecs) ?
settings[NumericParameters.AFKTimeoutSecs] :
120, /*value*/
useUrlParams
)
);
@ -484,7 +528,9 @@ export class Config {
'Maximum number of reconnects the application will attempt when a streamer disconnects.',
0 /*min*/,
999 /*max*/,
3 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.MaxReconnectAttempts) ?
settings[NumericParameters.MaxReconnectAttempts] :
3, /*value*/
useUrlParams
)
);
@ -497,7 +543,9 @@ export class Config {
'The lower bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.',
0 /*min*/,
51 /*max*/,
0 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.MinQP) ?
settings[NumericParameters.MinQP] :
0, /*value*/
useUrlParams
)
);
@ -510,7 +558,9 @@ export class Config {
'The upper bound for the quantization parameter (QP) of the encoder. 0 = Best quality, 51 = worst quality.',
0 /*min*/,
51 /*max*/,
51 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.MaxQP) ?
settings[NumericParameters.MaxQP] :
51, /*value*/
useUrlParams
)
);
@ -523,7 +573,9 @@ export class Config {
'The maximum FPS that WebRTC will try to transmit frames at.',
1 /*min*/,
999 /*max*/,
60 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.WebRTCFPS) ?
settings[NumericParameters.WebRTCFPS] :
60, /*value*/
useUrlParams
)
);
@ -536,7 +588,9 @@ export class Config {
'The minimum bitrate that WebRTC should use.',
0 /*min*/,
500000 /*max*/,
0 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.WebRTCMinBitrate) ?
settings[NumericParameters.WebRTCMinBitrate] :
0, /*value*/
useUrlParams
)
);
@ -549,7 +603,24 @@ export class Config {
'The maximum bitrate that WebRTC should use.',
0 /*min*/,
500000 /*max*/,
0 /*value*/,
settings && settings.hasOwnProperty(NumericParameters.WebRTCMaxBitrate) ?
settings[NumericParameters.WebRTCMaxBitrate] :
0, /*value*/
useUrlParams
)
);
this.numericParameters.set(
NumericParameters.StreamerAutoJoinInterval,
new SettingNumber(
NumericParameters.StreamerAutoJoinInterval,
'Streamer Auto Join Interval (ms)',
'Delay between retries when waiting for an available streamer.',
500 /*min*/,
900000 /*max*/,
settings && settings.hasOwnProperty(NumericParameters.StreamerAutoJoinInterval) ?
settings[NumericParameters.StreamerAutoJoinInterval] :
3000, /*value*/
useUrlParams
)
);
@ -728,7 +799,13 @@ export class Config {
`Cannot set text setting called ${id} - it does not exist in the Config.enumParameters map.`
);
} else {
this.optionParameters.get(id).selected = settingValue;
const optionSetting = this.optionParameters.get(id);
const existingOptions = optionSetting.options;
if (!existingOptions.includes(settingValue)) {
existingOptions.push(settingValue);
optionSetting.options = existingOptions;
}
optionSetting.selected = settingValue;
}
}
@ -748,24 +825,24 @@ export class Config {
}
}
/**
* Set a subset of all settings in one function call.
*
* @param settings A (partial) list of settings to set
*/
setSettings(settings: Partial<AllSettings>) {
for (const key of Object.keys(settings)) {
if (isFlagId(key)) {
this.setFlagEnabled(key, settings[key]);
} else if (isNumericId(key)) {
this.setNumericSetting(key, settings[key]);
} else if (isTextId(key)) {
this.setTextSetting(key, settings[key]);
} else if (isOptionId(key)) {
this.setOptionSettingValue(key, settings[key]);
/**
* Set a subset of all settings in one function call.
*
* @param settings A (partial) list of settings to set
*/
setSettings(settings: Partial<AllSettings>) {
for (const key of Object.keys(settings)) {
if (isFlagId(key)) {
this.setFlagEnabled(key, settings[key]);
} else if (isNumericId(key)) {
this.setNumericSetting(key, settings[key]);
} else if (isTextId(key)) {
this.setTextSetting(key, settings[key]);
} else if (isOptionId(key)) {
this.setOptionSettingValue(key, settings[key]);
}
}
}
}
/**
* Get all settings

View File

@ -37,7 +37,7 @@ export class SettingNumber<
if (!useUrlParams || !urlParams.has(this.id)) {
this.number = defaultNumber;
} else {
const parsedValue = Number.parseInt(urlParams.get(this.id));
const parsedValue = Number.parseFloat(urlParams.get(this.id));
this.number = Number.isNaN(parsedValue)
? defaultNumber
: parsedValue;

View File

@ -24,7 +24,7 @@ export class SettingOption<
// eslint-disable-next-line @typescript-eslint/no-empty-function
defaultOnChangeListener: (changedValue: unknown, setting: SettingBase) => void = () => { /* Do nothing, to be overridden. */ }
) {
super(id, label, description, [defaultTextValue, defaultTextValue], defaultOnChangeListener);
super(id, label, description, defaultTextValue, defaultOnChangeListener);
this.options = options;
const urlParams = new URLSearchParams(window.location.search);
@ -103,11 +103,22 @@ export class SettingOption<
public set selected(value: string) {
// A user may not specify the full possible value so we instead use the closest match.
// eg ?xxx=H264 would select 'H264 level-asymmetry-allowed=1;packetization-mode=1;profile-level-id=42001f'
const filteredList = this.options.filter(
let filteredList = this.options.filter(
(option: string) => option.indexOf(value) !== -1
);
if (filteredList.length) {
this.value = filteredList[0];
return;
}
// A user has specified a codec with a fmtp string but this codec + fmtp line isn't available.
// in that case, just use the codec
filteredList = this.options.filter(
(option: string) => option.indexOf(value.split(' ')[0]) !== -1
);
if (filteredList.length) {
this.value = filteredList[0];
return;
}
}
}

View File

@ -0,0 +1,129 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { Logger } from '../Logger/Logger';
import {
DataChannelLatencyTestRecord,
DataChannelLatencyTestRequest,
DataChannelLatencyTestResponse,
DataChannelLatencyTestResult,
DataChannelLatencyTestSeq,
DataChannelLatencyTestTimestamp
} from "./DataChannelLatencyTestResults";
export type DataChannelLatencyTestConfig = {
// test duration in milliseconds
duration: number;
//requests per second
rps: number;
//request filler size
requestSize: number;
//response filler size
responseSize: number;
}
export type DataChannelLatencyTestSink = (request: DataChannelLatencyTestRequest) => void;
export type DataChannelLatencyTestResultCallback = (result: DataChannelLatencyTestResult) => void;
export class DataChannelLatencyTestController {
startTime: DataChannelLatencyTestTimestamp;
sink: DataChannelLatencyTestSink;
callback: DataChannelLatencyTestResultCallback;
records: Map<DataChannelLatencyTestSeq, DataChannelLatencyTestRecord>;
seq: DataChannelLatencyTestSeq;
interval: NodeJS.Timer;
constructor(sink: DataChannelLatencyTestSink, callback: DataChannelLatencyTestResultCallback) {
this.sink = sink;
this.callback = callback;
this.records = new Map();
this.seq = 0;
}
start(config: DataChannelLatencyTestConfig) {
if (this.isRunning()) {
return false;
}
this.startTime = Date.now();
this.records.clear();
this.interval = setInterval((() => {
if (Date.now() - this.startTime >= config.duration) {
this.stop();
} else {
this.sendRequest(config.requestSize, config.responseSize);
}
}).bind(this), Math.floor(1000/config.rps));
return true;
}
stop() {
if (this.interval) {
clearInterval(this.interval);
this.interval = undefined;
this.callback(this.produceResult());
}
}
produceResult(): DataChannelLatencyTestResult {
const resultRecords = new Map(this.records);
return {
records: resultRecords,
dataChannelRtt: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => {
return acc + (next.playerReceivedTimestamp - next.playerSentTimestamp);
}, 0) / this.records.size),
playerToStreamerTime: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => {
return acc + (next.streamerReceivedTimestamp - next.playerSentTimestamp);
}, 0) / this.records.size),
streamerToPlayerTime: Math.ceil(Array.from(this.records.values()).reduce((acc, next) => {
return acc + (next.playerReceivedTimestamp - next.streamerSentTimestamp);
}, 0) / this.records.size),
exportLatencyAsCSV: () => {
let csv = "Timestamp;RTT;PlayerToStreamer;StreamerToPlayer;\n";
resultRecords.forEach((record) => {
csv += record.playerSentTimestamp + ";";
csv += (record.playerReceivedTimestamp - record.playerSentTimestamp) + ";";
csv += (record.streamerReceivedTimestamp - record.playerSentTimestamp) + ";";
csv += (record.playerReceivedTimestamp - record.streamerSentTimestamp) + ";";
csv += "\n";
})
return csv;
}
}
}
isRunning() {
return !!this.interval;
}
receive(response: DataChannelLatencyTestResponse) {
if (!this.isRunning()) {
return;
}
if (!response) {
Logger.Error(
Logger.GetStackTrace(),
"Undefined response from server"
);
return;
}
let record = this.records.get(response.Seq);
if (record) {
record.update(response);
}
}
sendRequest(requestSize: number, responseSize: number) {
let request = this.createRequest(requestSize, responseSize);
let record = new DataChannelLatencyTestRecord(request);
this.records.set(record.seq, record);
this.sink(request);
}
createRequest(requestSize: number, responseSize: number): DataChannelLatencyTestRequest {
return {
Seq: this.seq++,
FillResponseSize: responseSize,
Filler: requestSize ? "A".repeat(requestSize) : ""
}
}
}

View File

@ -0,0 +1,67 @@
// Copyright Epic Games, Inc. All Rights Reserved.
/**
* Data Channel Latency Test types
*/
/**
* Unix epoch
*/
export type DataChannelLatencyTestTimestamp = number;
/**
* Sequence number represented by unsigned int
*/
export type DataChannelLatencyTestSeq = number;
/**
* Request sent to Streamer
*/
export type DataChannelLatencyTestRequest = {
Seq: DataChannelLatencyTestSeq;
FillResponseSize: number;
Filler: string;
}
/**
* Response from the Streamer
*/
export type DataChannelLatencyTestResponse = {
Seq: DataChannelLatencyTestSeq;
Filler: string;
ReceivedTimestamp: DataChannelLatencyTestTimestamp;
SentTimestamp: DataChannelLatencyTestTimestamp;
}
export type DataChannelLatencyTestResult = {
records: Map<DataChannelLatencyTestSeq, DataChannelLatencyTestRecord>
dataChannelRtt: number,
playerToStreamerTime: number,
streamerToPlayerTime: number,
exportLatencyAsCSV: () => string
}
export class DataChannelLatencyTestRecord {
seq: DataChannelLatencyTestSeq;
playerSentTimestamp: DataChannelLatencyTestTimestamp;
playerReceivedTimestamp: DataChannelLatencyTestTimestamp;
streamerReceivedTimestamp: DataChannelLatencyTestTimestamp;
streamerSentTimestamp: DataChannelLatencyTestTimestamp;
requestFillerSize: number;
responseFillerSize: number;
constructor(request: DataChannelLatencyTestRequest) {
this.seq = request.Seq;
this.playerSentTimestamp = Date.now();
this.requestFillerSize = request.Filler ? request.Filler.length : 0;
}
update(response: DataChannelLatencyTestResponse) {
this.playerReceivedTimestamp = Date.now();
this.streamerReceivedTimestamp = response.ReceivedTimestamp;
this.streamerSentTimestamp = response.SentTimestamp;
this.responseFillerSize = response.Filler ? response.Filler.length : 0;
}
}

View File

@ -72,7 +72,7 @@ export class FakeTouchController implements ITouchController {
* @param touch - the activating touch event
*/
onTouchStart(touch: TouchEvent): void {
if (!this.videoElementProvider.isVideoReady()) {
if (!this.videoElementProvider.isVideoReady() || touch.target !== this.videoElementProvider.getVideoElement()) {
return;
}
if (this.fakeTouchFinger == null) {
@ -108,7 +108,7 @@ export class FakeTouchController implements ITouchController {
* @param touchEvent - the activating touch event
*/
onTouchEnd(touchEvent: TouchEvent): void {
if (!this.videoElementProvider.isVideoReady()) {
if (!this.videoElementProvider.isVideoReady() || this.fakeTouchFinger == null) {
return;
}
const videoElementParent =
@ -144,7 +144,7 @@ export class FakeTouchController implements ITouchController {
* @param touchEvent - the activating touch event
*/
onTouchMove(touchEvent: TouchEvent): void {
if (!this.videoElementProvider.isVideoReady()) {
if (!this.videoElementProvider.isVideoReady() || this.fakeTouchFinger == null) {
return;
}
const toStreamerHandlers =

View File

@ -28,6 +28,11 @@ export class GamePadController {
window.requestAnimationFrame
).bind(window);
const browserWindow = window as Window;
const onBeforeUnload = (ev: Event) =>
this.onBeforeUnload(ev);
window.addEventListener('beforeunload', onBeforeUnload);
if ('GamepadEvent' in browserWindow) {
const onGamePadConnected = (ev: GamepadEvent) =>
this.gamePadConnectHandler(ev);
@ -197,7 +202,8 @@ export class GamePadController {
} else {
toStreamerHandlers.get('GamepadButtonReleased')([
controllerIndex,
i
i,
0
]);
}
}
@ -253,6 +259,14 @@ export class GamePadController {
onGamepadDisconnected(controllerIdx: number) {
// Default Functionality: Do Nothing
}
onBeforeUnload(ev: Event) {
// When a user navigates away from the page, we need to inform UE of all the disconnecting
// controllers
for(const controller of this.controllers) {
this.onGamepadDisconnected(controller.id);
}
}
}

View File

@ -86,6 +86,7 @@ export class HoveringMouseEvents implements IMouseEvents {
if (!this.mouseController.videoElementProvider.isVideoReady()) {
return;
}
Logger.Log(Logger.GetStackTrace(), 'onMouse Up', 6);
const coord =
this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(
mouseEvent.offsetX,
@ -102,25 +103,13 @@ export class HoveringMouseEvents implements IMouseEvents {
}
/**
* Handle the mouse context menu event, sends the mouse data to the UE Instance
* Consumes the mouse context event. The UE instance has no equivalent and doesn't need to be informed.
* @param mouseEvent - Mouse Event
*/
handleContextMenu(mouseEvent: MouseEvent) {
if (!this.mouseController.videoElementProvider.isVideoReady()) {
return;
}
const coord =
this.mouseController.coordinateConverter.normalizeAndQuantizeUnsigned(
mouseEvent.offsetX,
mouseEvent.offsetY
);
const toStreamerHandlers =
this.mouseController.toStreamerMessagesProvider.toStreamerHandlers;
toStreamerHandlers.get('MouseUp')([
mouseEvent.button,
coord.x,
coord.y
]);
mouseEvent.preventDefault();
}
@ -177,6 +166,7 @@ export class HoveringMouseEvents implements IMouseEvents {
if (!this.mouseController.videoElementProvider.isVideoReady()) {
return;
}
Logger.Log(Logger.GetStackTrace(), 'onMouse press', 6);
this.mouseController.pressMouseButtons(
mouseEvent.buttons,
mouseEvent.offsetX,
@ -192,6 +182,7 @@ export class HoveringMouseEvents implements IMouseEvents {
if (!this.mouseController.videoElementProvider.isVideoReady()) {
return;
}
Logger.Log(Logger.GetStackTrace(), 'onMouse release', 6);
this.mouseController.releaseMouseButtons(
mouseEvent.buttons,
mouseEvent.offsetX,

View File

@ -150,16 +150,21 @@ export class KeyboardController {
* Registers document keyboard events with the controller
*/
registerKeyBoardEvents() {
const compositionEndHandler = (ev: CompositionEvent) => this.handleOnCompositionEnd(ev);
const keyDownHandler = (ev: KeyboardEvent) => this.handleOnKeyDown(ev);
const keyUpHandler = (ev: KeyboardEvent) => this.handleOnKeyUp(ev);
const keyPressHandler = (ev: KeyboardEvent) => this.handleOnKeyPress(ev);
document.addEventListener("compositionend", compositionEndHandler);
document.addEventListener("keydown", keyDownHandler);
document.addEventListener("keyup", keyUpHandler);
//This has been deprecated as at Jun 13 2021
document.addEventListener("keypress", keyPressHandler);
this.keyboardEventListenerTracker.addUnregisterCallback(
() => document.removeEventListener("compositionend", compositionEndHandler)
);
this.keyboardEventListenerTracker.addUnregisterCallback(
() => document.removeEventListener("keydown", keyDownHandler)
);
@ -184,7 +189,7 @@ export class KeyboardController {
*/
handleOnKeyDown(keyboardEvent: KeyboardEvent) {
const keyCode = this.getKeycode(keyboardEvent);
if (!keyCode) {
if (!keyCode || keyCode === 229) {
return;
}
@ -232,10 +237,7 @@ export class KeyboardController {
Logger.Log(Logger.GetStackTrace(), `key up ${keyCode}`, 6);
const toStreamerHandlers =
this.toStreamerMessagesProvider.toStreamerHandlers;
toStreamerHandlers.get('KeyUp')([
keyCode,
keyboardEvent.repeat ? 1 : 0
]);
toStreamerHandlers.get('KeyUp')([ keyCode ]);
if (
this.config.isFlagEnabled(Flags.SuppressBrowserKeys) &&
@ -266,6 +268,37 @@ export class KeyboardController {
toStreamerHandlers.get('KeyPress')([charCode]);
}
/**
* Handle whenever composition ends (eg chinese simplified)
* @param compositionEvent - the composition event
*/
handleOnCompositionEnd(compositionEvent: CompositionEvent) {
if (compositionEvent.data && compositionEvent.data.length) {
compositionEvent.data.split('').forEach((char) => {
// This keydown, keypress, keyup flow is required to mimic the way characters are
// normally triggered
this.handleOnKeyDown(
new KeyboardEvent('keydown', {
keyCode: char.toUpperCase().charCodeAt(0),
charCode: char.charCodeAt(0)
})
);
this.handleOnKeyPress(
new KeyboardEvent('keypress', {
keyCode: char.toUpperCase().charCodeAt(0),
charCode: char.charCodeAt(0)
})
);
this.handleOnKeyUp(
new KeyboardEvent('keyup', {
keyCode: char.toUpperCase().charCodeAt(0),
charCode: char.charCodeAt(0)
})
);
});
}
}
/**
* Gets the Keycode of the Key pressed
* @param keyboardEvent - Key board Event

View File

@ -41,9 +41,9 @@ export class TouchController implements ITouchController {
this.onTouchEnd(ev);
const ontouchmove = (ev: TouchEvent) =>
this.onTouchMove(ev);
this.videoElementParent.addEventListener('touchstart', ontouchstart, { passive: false });
this.videoElementParent.addEventListener('touchend', ontouchend, { passive: false });
this.videoElementParent.addEventListener('touchmove', ontouchmove, { passive: false });
this.videoElementParent.addEventListener('touchstart', ontouchstart);
this.videoElementParent.addEventListener('touchend', ontouchend);
this.videoElementParent.addEventListener('touchmove', ontouchmove);
this.touchEventListenerTracker.addUnregisterCallback(
() => this.videoElementParent.removeEventListener('touchstart', ontouchstart)
);
@ -59,7 +59,7 @@ export class TouchController implements ITouchController {
const preventOnTouchMove = (event: TouchEvent) => {
event.preventDefault();
};
document.addEventListener('touchmove', preventOnTouchMove, { passive: false });
document.addEventListener('touchmove', preventOnTouchMove);
this.touchEventListenerTracker.addUnregisterCallback(
() => document.removeEventListener('touchmove', preventOnTouchMove)
);
@ -152,16 +152,15 @@ export class TouchController implements ITouchController {
if (!this.videoElementProvider.isVideoReady()) {
return;
}
const videoElementParent =
this.videoElementProvider.getVideoParentElement();
const offset = this.videoElementProvider.getVideoParentElement().getBoundingClientRect();
const toStreamerHandlers =
this.toStreamerMessagesProvider.toStreamerHandlers;
for (let t = 0; t < touches.length; t++) {
const numTouches = 1; // the number of touches to be sent this message
const touch = touches[t];
const x = touch.clientX - videoElementParent.offsetLeft;
const y = touch.clientY - videoElementParent.offsetTop;
const x = touch.clientX - offset.left;
const y = touch.clientY - offset.top;
Logger.Log(
Logger.GetStackTrace(),
`F${this.fingerIds.get(touch.identifier)}=(${x}, ${y})`,
@ -179,7 +178,7 @@ export class TouchController implements ITouchController {
coord.x,
coord.y,
this.fingerIds.get(touch.identifier),
this.maxByteValue * touch.force,
this.maxByteValue * (touch.force > 0 ? touch.force : 1),
coord.inRange ? 1 : 0
]);
break;
@ -199,7 +198,7 @@ export class TouchController implements ITouchController {
coord.x,
coord.y,
this.fingerIds.get(touch.identifier),
this.maxByteValue * touch.force,
this.maxByteValue * (touch.force > 0 ? touch.force : 1),
coord.inRange ? 1 : 0
]);
break;

View File

@ -19,13 +19,13 @@ import { Logger } from '../Logger/Logger';
* The Aggregated Stats that is generated from the RTC Stats Report
*/
type RTCStatsTypePS = RTCStatsType | 'stream';
type RTCStatsTypePS = RTCStatsType | 'stream' | 'media-playout';
export class AggregatedStats {
inboundVideoStats: InboundVideoStats;
inboundAudioStats: InboundAudioStats;
lastVideoStats: InboundVideoStats;
lastAudioStats: InboundAudioStats;
candidatePair: CandidatePairStats;
candidatePairs: Array<CandidatePairStats>;
DataChannelStats: DataChannelStats;
localCandidates: Array<CandidateStat>;
remoteCandidates: Array<CandidateStat>;
@ -37,7 +37,6 @@ export class AggregatedStats {
constructor() {
this.inboundVideoStats = new InboundVideoStats();
this.inboundAudioStats = new InboundAudioStats();
this.candidatePair = new CandidatePairStats();
this.DataChannelStats = new DataChannelStats();
this.outBoundVideoStats = new OutBoundVideoStats();
this.sessionStats = new SessionStats();
@ -52,6 +51,7 @@ export class AggregatedStats {
processStats(rtcStatsReport: RTCStatsReport) {
this.localCandidates = new Array<CandidateStat>();
this.remoteCandidates = new Array<CandidateStat>();
this.candidatePairs = new Array<CandidatePairStats>();
rtcStatsReport.forEach((stat) => {
const type: RTCStatsTypePS = stat.type;
@ -76,6 +76,8 @@ export class AggregatedStats {
break;
case 'media-source':
break;
case 'media-playout':
break;
case 'outbound-rtp':
break;
case 'peer-connection':
@ -118,16 +120,10 @@ export class AggregatedStats {
* @param stat - the stats coming in from ice candidates
*/
handleCandidatePair(stat: CandidatePairStats) {
this.candidatePair.bytesReceived = stat.bytesReceived;
this.candidatePair.bytesSent = stat.bytesSent;
this.candidatePair.localCandidateId = stat.localCandidateId;
this.candidatePair.remoteCandidateId = stat.remoteCandidateId;
this.candidatePair.nominated = stat.nominated;
this.candidatePair.readable = stat.readable;
this.candidatePair.selected = stat.selected;
this.candidatePair.writable = stat.writable;
this.candidatePair.state = stat.state;
this.candidatePair.currentRoundTripTime = stat.currentRoundTripTime;
// Add the candidate pair to the candidate pair array
this.candidatePairs.push(stat)
}
/**
@ -160,6 +156,8 @@ export class AggregatedStats {
localCandidate.protocol = stat.protocol;
localCandidate.candidateType = stat.candidateType;
localCandidate.id = stat.id;
localCandidate.relayProtocol = stat.relayProtocol;
localCandidate.transportId = stat.transportId;
this.localCandidates.push(localCandidate);
}
@ -169,12 +167,14 @@ export class AggregatedStats {
*/
handleRemoteCandidate(stat: CandidateStat) {
const RemoteCandidate = new CandidateStat();
RemoteCandidate.label = 'local-candidate';
RemoteCandidate.label = 'remote-candidate';
RemoteCandidate.address = stat.address;
RemoteCandidate.port = stat.port;
RemoteCandidate.protocol = stat.protocol;
RemoteCandidate.id = stat.id;
RemoteCandidate.candidateType = stat.candidateType;
RemoteCandidate.relayProtocol = stat.relayProtocol;
RemoteCandidate.transportId = stat.transportId
this.remoteCandidates.push(RemoteCandidate);
}
@ -306,4 +306,12 @@ export class AggregatedStats {
isNumber(value: unknown): boolean {
return typeof value === 'number' && isFinite(value);
}
/**
* Helper function to return the active candidate pair
* @returns The candidate pair that is currently receiving data
*/
public getActiveCandidatePair(): CandidatePairStats | null {
return this.candidatePairs.find((candidatePair) => candidatePair.bytesReceived > 0, null)
}
}

View File

@ -6,12 +6,19 @@
export class CandidatePairStats {
bytesReceived: number;
bytesSent: number;
currentRoundTripTime: number;
id: string;
lastPacketReceivedTimestamp: number;
lastPacketSentTimestamp: number;
localCandidateId: string;
remoteCandidateId: string;
nominated: boolean;
priority: number;
readable: boolean;
writable: boolean;
remoteCandidateId: string;
selected: boolean;
state: string;
currentRoundTripTime: number;
timestamp: number;
transportId: string;
type: string;
writable: boolean;
}

View File

@ -4,10 +4,12 @@
* ICE Candidate Stat collected from the RTC Stats Report
*/
export class CandidateStat {
label: string;
id: string;
address: string;
candidateType: string;
id: string;
label: string;
port: number;
protocol: 'tcp' | 'udp';
relayProtocol: 'tcp' | 'udp' | 'tls';
transportId: string;
}

View File

@ -4,6 +4,7 @@ import { Logger } from '../Logger/Logger';
import { Config, OptionParameters, Flags } from '../Config/Config';
import { AggregatedStats } from './AggregatedStats';
import { parseRtpParameters, splitSections } from 'sdp';
import { RTCUtils } from '../Util/RTCUtils';
/**
* Handles the Peer Connection
@ -179,7 +180,7 @@ export class PeerConnectionController {
this.onVideoStats(this.aggregatedStats);
// Update the preferred codec selection based on what was actually negotiated
if (this.updateCodecSelection) {
if (this.updateCodecSelection && !!this.aggregatedStats.inboundVideoStats.codecId) {
this.config.setOptionSettingValue(
OptionParameters.PreferredCodec,
this.aggregatedStats.codecs.get(
@ -207,16 +208,13 @@ export class PeerConnectionController {
* @returns A modified Session Descriptor
*/
mungeSDP(sdp: string, useMic: boolean) {
const mungedSDP = sdp;
mungedSDP.replace(
let mungedSDP = sdp.replace(
/(a=fmtp:\d+ .*level-asymmetry-allowed=.*)\r\n/gm,
'$1;x-google-start-bitrate=10000;x-google-max-bitrate=100000\r\n'
);
let audioSDP = '';
// set max bitrate to highest bitrate Opus supports
audioSDP += 'maxaveragebitrate=510000;';
let audioSDP = 'maxaveragebitrate=510000;';
if (useMic) {
// set the max capture rate to 48khz (so we can send high quality audio from mic)
@ -232,7 +230,7 @@ export class PeerConnectionController {
audioSDP += 'useinbandfec=1';
// We use the line 'useinbandfec=1' (which Opus uses) to set our Opus specific audio parameters.
mungedSDP.replace('useinbandfec=1', audioSDP);
mungedSDP = mungedSDP.replace('useinbandfec=1', audioSDP);
return mungedSDP;
}
@ -375,7 +373,9 @@ export class PeerConnectionController {
transceiver &&
transceiver.receiver &&
transceiver.receiver.track &&
transceiver.receiver.track.kind === 'video'
transceiver.receiver.track.kind === 'video' &&
// As of 06/2023, FireFox has added RTCRtpReceiver.getCapabilities, but hasn't added the ability to set codec preferences
transceiver.setCodecPreferences
) {
const preferredRTPCodec = this.preferredCodec.split(' ');
const codecs = [
@ -426,18 +426,16 @@ export class PeerConnectionController {
});
} else {
// set the audio options based on mic usage
const audioOptions = useMic
? {
autoGainControl: false,
channelCount: 1,
echoCancellation: false,
latency: 0,
noiseSuppression: false,
sampleRate: 48000,
sampleSize: 16,
volume: 1.0
}
: false;
const audioOptions = {
autoGainControl: false,
channelCount: 1,
echoCancellation: false,
latency: 0,
noiseSuppression: false,
sampleRate: 48000,
sampleSize: 16,
volume: 1.0
}
// set the media send options
const mediaSendOptions: MediaStreamConstraints = {
@ -452,12 +450,7 @@ export class PeerConnectionController {
if (stream) {
if (hasTransceivers) {
for (const transceiver of this.peerConnection?.getTransceivers() ?? []) {
if (
transceiver &&
transceiver.receiver &&
transceiver.receiver.track &&
transceiver.receiver.track.kind === 'audio'
) {
if (RTCUtils.canTransceiverReceiveAudio(transceiver)) {
for (const track of stream.getTracks()) {
if (track.kind && track.kind == 'audio') {
transceiver.sender.replaceTrack(track);

View File

@ -209,7 +209,7 @@ describe('PixelStreaming', () => {
expect(webSocketSpyFunctions.constructorSpy).toHaveBeenCalledTimes(1);
expect(webSocketSpyFunctions.closeSpy).not.toHaveBeenCalled();
pixelStreaming.disconnect();
pixelStreaming.webSocketController.close();
expect(webSocketSpyFunctions.closeSpy).toHaveBeenCalled();
@ -274,7 +274,8 @@ describe('PixelStreaming', () => {
type: MessageRecvTypes.STREAMER_LIST,
ids: streamerIdList
}),
autoSelectedStreamerId: streamerId
autoSelectedStreamerId: streamerId,
wantedStreamerId: null
}));
expect(webSocketSpyFunctions.sendSpy).toHaveBeenCalledWith(
expect.stringMatching(/"type":"subscribe".*MOCK_PIXEL_STREAMING/)
@ -298,7 +299,8 @@ describe('PixelStreaming', () => {
type: MessageRecvTypes.STREAMER_LIST,
ids: extendedStreamerIdList
}),
autoSelectedStreamerId: null
autoSelectedStreamerId: null,
wantedStreamerId: null
}));
expect(webSocketSpyFunctions.sendSpy).not.toHaveBeenCalledWith(
expect.stringMatching(/"type":"subscribe"/)
@ -396,9 +398,9 @@ describe('PixelStreaming', () => {
expect.objectContaining({
data: {
aggregatedStats: expect.objectContaining({
candidatePair: expect.objectContaining({
bytesReceived: 123
}),
candidatePairs: [
expect.objectContaining({ bytesReceived: 123 })
],
localCandidates: [
expect.objectContaining({ address: 'mock-address' })
]
@ -572,4 +574,51 @@ describe('PixelStreaming', () => {
expect(responseListenerSpy).toHaveBeenCalledWith(testMessageContents);
});
it('should emit StreamConnectEvent when streamer connects', () => {
const config = new Config({ initialSettings: {ss: mockSignallingUrl}});
const streamConnectSpy = jest.fn();
const pixelStreaming = new PixelStreaming(config);
pixelStreaming.addEventListener("streamConnect", streamConnectSpy);
pixelStreaming.connect();
establishMockedPixelStreamingConnection();
expect(streamConnectSpy).toHaveBeenCalled();
});
it('should emit StreamDisconnectEvent when streamer disconnects', () => {
const config = new Config({ initialSettings: {ss: mockSignallingUrl}});
const streamDisconnectSpy = jest.fn();
const pixelStreaming = new PixelStreaming(config);
pixelStreaming.addEventListener("streamDisconnect", streamDisconnectSpy);
pixelStreaming.connect();
establishMockedPixelStreamingConnection();
expect(streamDisconnectSpy).not.toHaveBeenCalled();
pixelStreaming.disconnect();
expect(streamDisconnectSpy).toHaveBeenCalled();
});
it('should emit StreamReconnectEvent when streamer reconnects', () => {
const config = new Config({ initialSettings: {ss: mockSignallingUrl}});
const streamReconnectSpy = jest.fn();
const pixelStreaming = new PixelStreaming(config);
pixelStreaming.addEventListener("streamReconnect", streamReconnectSpy);
pixelStreaming.connect();
establishMockedPixelStreamingConnection();
expect(streamReconnectSpy).not.toHaveBeenCalled();
pixelStreaming.reconnect();
expect(streamReconnectSpy).toHaveBeenCalled();
pixelStreaming.disconnect();
expect(streamReconnectSpy).toHaveBeenCalledTimes(1);
});
});

View File

@ -15,6 +15,9 @@ import {
PixelStreamingEvent,
StatsReceivedEvent,
StreamLoadingEvent,
StreamPreConnectEvent,
StreamReconnectEvent,
StreamPreDisconnectEvent,
VideoEncoderAvgQPEvent,
VideoInitializedEvent,
WebRtcAutoConnectEvent,
@ -22,10 +25,25 @@ import {
WebRtcConnectingEvent,
WebRtcDisconnectedEvent,
WebRtcFailedEvent,
WebRtcSdpEvent
WebRtcSdpEvent,
DataChannelLatencyTestResponseEvent,
DataChannelLatencyTestResultEvent,
PlayerCountEvent,
WebRtcTCPRelayDetectedEvent
} from '../Util/EventEmitter';
import { MessageOnScreenKeyboard } from '../WebSockets/MessageReceive';
import { WebXRController } from '../WebXR/WebXRController';
import { MessageDirection } from '../UeInstanceMessage/StreamMessageController';
import {
DataChannelLatencyTestConfig,
DataChannelLatencyTestController
} from "../DataChannel/DataChannelLatencyTestController";
import {
DataChannelLatencyTestResponse,
DataChannelLatencyTestResult
} from "../DataChannel/DataChannelLatencyTestResults";
import { RTCUtils } from '../Util/RTCUtils';
export interface PixelStreamingOverrides {
/** The DOM elment where Pixel Streaming video and user input event handlers are attached to.
@ -42,8 +60,10 @@ export interface PixelStreamingOverrides {
* this will likely be the core of your Pixel Streaming experience in terms of functionality.
*/
export class PixelStreaming {
private _webRtcController: WebRtcPlayerController;
private _webXrController: WebXRController;
protected _webRtcController: WebRtcPlayerController;
protected _webXrController: WebXRController;
protected _dataChannelLatencyTestController: DataChannelLatencyTestController;
/**
* Configuration object. You can read or modify config through this object. Whenever
* the configuration is changed, the library will emit a `settingsChanged` event.
@ -52,7 +72,6 @@ export class PixelStreaming {
private _videoElementParent: HTMLElement;
_showActionOrErrorOnDisconnect = true;
private allowConsoleCommands = false;
private onScreenKeyboardHelper: OnScreenKeyboard;
@ -99,6 +118,15 @@ export class PixelStreaming {
this.onScreenKeyboardHelper.showOnScreenKeyboard(command);
this._webXrController = new WebXRController(this._webRtcController);
this._setupWebRtcTCPRelayDetection = this._setupWebRtcTCPRelayDetection.bind(this)
// Add event listener for the webRtcConnected event
this._eventEmitter.addEventListener("webRtcConnected", (webRtcConnectedEvent: WebRtcConnectedEvent) => {
// Bind to the stats received event
this._eventEmitter.addEventListener("statsReceived", this._setupWebRtcTCPRelayDetection);
});
}
/**
@ -325,6 +353,7 @@ export class PixelStreaming {
* Connect to signaling server.
*/
public connect() {
this._eventEmitter.dispatchEvent(new StreamPreConnectEvent());
this._webRtcController.connectToSignallingServer();
}
@ -333,13 +362,15 @@ export class PixelStreaming {
* before establishing a new connection
*/
public reconnect() {
this._webRtcController.restartStreamAutomatically();
this._eventEmitter.dispatchEvent(new StreamReconnectEvent());
this._webRtcController.tryReconnect("Reconnecting...");
}
/**
* Disconnect from the signaling server and close open peer connections.
*/
public disconnect() {
this._eventEmitter.dispatchEvent(new StreamPreDisconnectEvent());
this._webRtcController.close();
}
@ -363,12 +394,62 @@ export class PixelStreaming {
}
}
/**
* Will unmute the microphone track which is sent to Unreal Engine.
* By default, will only unmute an existing mic track.
*
* @param forceEnable Can be used for cases when this object wasn't initialized with a mic track.
* If this parameter is true, the connection will be restarted with a microphone.
* Warning: this takes some time, as a full renegotiation and reconnection will happen.
*/
public unmuteMicrophone(forceEnable = false) : void {
// If there's an existing mic track, we just set muted state
if (this.config.isFlagEnabled('UseMic')) {
this.setMicrophoneMuted(false);
return;
}
// If there's no pre-existing mic track, and caller is ok with full reset, we enable and reset
if (forceEnable) {
this.config.setFlagEnabled("UseMic", true);
this.reconnect();
return;
}
// If we prefer not to force a reconnection, just warn the user that this operation didn't happen
Logger.Warning(
Logger.GetStackTrace(),
'Trying to unmute mic, but PixelStreaming was initialized with no microphone track. Call with forceEnable == true to re-connect with a mic track.'
);
}
public muteMicrophone() : void {
if (this.config.isFlagEnabled('UseMic')) {
this.setMicrophoneMuted(true);
return;
}
// If there wasn't a mic track, just let user know there's nothing to mute
Logger.Info(
Logger.GetStackTrace(),
'Trying to mute mic, but PixelStreaming has no microphone track, so sending sound is already disabled.'
);
}
private setMicrophoneMuted(mute: boolean) : void
{
for (const transceiver of this._webRtcController?.peerConnectionController?.peerConnection?.getTransceivers() ?? []) {
if (RTCUtils.canTransceiverSendAudio(transceiver)) {
transceiver.sender.track.enabled = !mute;
}
}
}
/**
* Emit an event on auto connecting
*/
_onWebRtcAutoConnect() {
this._eventEmitter.dispatchEvent(new WebRtcAutoConnectEvent());
this._showActionOrErrorOnDisconnect = true;
}
/**
@ -388,30 +469,16 @@ export class PixelStreaming {
/**
* Event fired when the video is disconnected - emits given eventString or an override
* message from webRtcController if one has been set
* @param eventString - the event text that will be emitted
* @param eventString - a string describing why the connection closed
* @param allowClickToReconnect - true if we want to allow the user to retry the connection with a click
*/
_onDisconnect(eventString: string) {
// if we have overridden the default disconnection message, assign the new value here
if (
this._webRtcController.getDisconnectMessageOverride() != '' &&
this._webRtcController.getDisconnectMessageOverride() !==
undefined &&
this._webRtcController.getDisconnectMessageOverride() != null
) {
eventString = this._webRtcController.getDisconnectMessageOverride();
this._webRtcController.setDisconnectMessageOverride('');
}
_onDisconnect(eventString: string, allowClickToReconnect: boolean) {
this._eventEmitter.dispatchEvent(
new WebRtcDisconnectedEvent({
eventString,
showActionOrErrorOnDisconnect:
this._showActionOrErrorOnDisconnect
eventString: eventString,
allowClickToReconnect: allowClickToReconnect
})
);
if (this._showActionOrErrorOnDisconnect == false) {
this._showActionOrErrorOnDisconnect = true;
}
}
/**
@ -453,6 +520,12 @@ export class PixelStreaming {
);
}
_onDataChannelLatencyTestResponse(response: DataChannelLatencyTestResponse) {
this._eventEmitter.dispatchEvent(
new DataChannelLatencyTestResponseEvent({ response })
);
}
/**
* Set up functionality to happen when receiving video statistics
* @param videoStats - video statistics as a aggregate stats object
@ -504,12 +577,16 @@ export class PixelStreaming {
const useUrlParams = this.config.useUrlParams;
const urlParams = new URLSearchParams(window.location.search);
Logger.Info(
Logger.GetStackTrace(),
`using URL parameters ${useUrlParams}`
);
if (settings.EncoderSettings) {
this.config.setNumericSetting(
NumericParameters.MinQP,
// If a setting is set in the URL, make sure we respect that value as opposed to what the application sends us
(useUrlParams && urlParams.has(NumericParameters.MinQP))
? Number.parseInt(urlParams.get(NumericParameters.MinQP))
? Number.parseFloat(urlParams.get(NumericParameters.MinQP))
: settings.EncoderSettings.MinQP
);
@ -517,7 +594,7 @@ export class PixelStreaming {
this.config.setNumericSetting(
NumericParameters.MaxQP,
(useUrlParams && urlParams.has(NumericParameters.MaxQP))
? Number.parseInt(urlParams.get(NumericParameters.MaxQP))
? Number.parseFloat(urlParams.get(NumericParameters.MaxQP))
: settings.EncoderSettings.MaxQP
);
}
@ -525,20 +602,20 @@ export class PixelStreaming {
this.config.setNumericSetting(
NumericParameters.WebRTCMinBitrate,
(useUrlParams && urlParams.has(NumericParameters.WebRTCMinBitrate))
? Number.parseInt(urlParams.get(NumericParameters.WebRTCMinBitrate)) / 1000 /* bps to kbps */
: settings.WebRTCSettings.MinBitrate / 1000 /* bps to kbps */
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCMinBitrate))
: (settings.WebRTCSettings.MinBitrate / 1000) /* bps to kbps */
);
this.config.setNumericSetting(
NumericParameters.WebRTCMaxBitrate,
(useUrlParams && urlParams.has(NumericParameters.WebRTCMaxBitrate))
? Number.parseInt(urlParams.get(NumericParameters.WebRTCMaxBitrate)) / 1000 /* bps to kbps */
: settings.WebRTCSettings.MaxBitrate / 1000 /* bps to kbps */
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCMaxBitrate))
: (settings.WebRTCSettings.MaxBitrate / 1000) /* bps to kbps */
);
this.config.setNumericSetting(
NumericParameters.WebRTCFPS,
(useUrlParams && urlParams.has(NumericParameters.WebRTCFPS))
? Number.parseInt(urlParams.get(NumericParameters.WebRTCFPS))
? Number.parseFloat(urlParams.get(NumericParameters.WebRTCFPS))
: settings.WebRTCSettings.FPS
);
}
@ -555,6 +632,34 @@ export class PixelStreaming {
);
}
_onPlayerCount(playerCount: number) {
this._eventEmitter.dispatchEvent(
new PlayerCountEvent({ count: playerCount })
);
}
// Sets up to emit the webrtc tcp relay detect event
_setupWebRtcTCPRelayDetection(statsReceivedEvent: StatsReceivedEvent) {
// Get the active candidate pair
let activeCandidatePair = statsReceivedEvent.data.aggregatedStats.getActiveCandidatePair();
// Check if the active candidate pair is not null
if (activeCandidatePair != null) {
// Get the local candidate assigned to the active candidate pair
let localCandidate = statsReceivedEvent.data.aggregatedStats.localCandidates.find((candidate) => candidate.id == activeCandidatePair.localCandidateId, null)
// Check if the local candidate is not null, candidate type is relay and the relay protocol is tcp
if (localCandidate != null && localCandidate.candidateType == 'relay' && localCandidate.relayProtocol == 'tcp') {
// Send the web rtc tcp relay detected event
this._eventEmitter.dispatchEvent(new WebRtcTCPRelayDetectedEvent());
}
// The check is completed and the stats listen event can be removed
this._eventEmitter.removeEventListener("statsReceived", this._setupWebRtcTCPRelayDetection);
}
}
/**
* Request a connection latency test.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
@ -568,6 +673,30 @@ export class PixelStreaming {
return true;
}
/**
* Request a data channel latency test.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
*/
public requestDataChannelLatencyTest(config: DataChannelLatencyTestConfig) {
if (!this._webRtcController.videoPlayer.isVideoReady()) {
return false;
}
if (!this._dataChannelLatencyTestController) {
this._dataChannelLatencyTestController = new DataChannelLatencyTestController(
this._webRtcController.sendDataChannelLatencyTest.bind(this._webRtcController),
(result: DataChannelLatencyTestResult) => {
this._eventEmitter.dispatchEvent(new DataChannelLatencyTestResultEvent( { result }))
});
this.addEventListener(
"dataChannelLatencyTestResponse",
({data: {response} }) => {
this._dataChannelLatencyTestController.receive(response);
}
)
}
return this._dataChannelLatencyTestController.start(config);
}
/**
* Request for the UE application to show FPS counter.
* NOTE: There are plans to refactor all request* functions. Expect changes if you use this!
@ -719,4 +848,37 @@ export class PixelStreaming {
public get webXrController() {
return this._webXrController;
}
public registerMessageHandler(name: string, direction: MessageDirection, handler?: (data: ArrayBuffer | Array<number | string>) => void) {
if(direction === MessageDirection.FromStreamer && typeof handler === 'undefined') {
Logger.Warning(Logger.GetStackTrace(), `Unable to register an undefined handler for ${name}`)
return;
}
if(direction === MessageDirection.ToStreamer && typeof handler === 'undefined') {
this._webRtcController.streamMessageController.registerMessageHandler(
direction,
name,
(data: Array<number | string>) =>
this._webRtcController.sendMessageController.sendMessageToStreamer(
name,
data
)
);
} else {
this._webRtcController.streamMessageController.registerMessageHandler(
direction,
name,
(data: ArrayBuffer) => handler(data)
);
}
}
public get toStreamerHandlers() {
return this._webRtcController.streamMessageController.toStreamerHandlers;
}
public isReconnecting() {
return this._webRtcController.isReconnecting;
}
}

View File

@ -1,87 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { DataChannelSender } from '../DataChannel/DataChannelSender';
import { Logger } from '../Logger/Logger';
import { StreamMessageController } from './StreamMessageController';
export class SendDescriptorController {
toStreamerMessagesMapProvider: StreamMessageController;
dataChannelSender: DataChannelSender;
constructor(
dataChannelSender: DataChannelSender,
toStreamerMessagesMapProvider: StreamMessageController
) {
this.dataChannelSender = dataChannelSender;
this.toStreamerMessagesMapProvider = toStreamerMessagesMapProvider;
}
/**
* Send a Latency Test to the UE Instance
* @param descriptor - the descriptor for a latency test
*/
sendLatencyTest(descriptor: object) {
this.sendDescriptor('LatencyTest', descriptor);
}
/**
* Send a Latency Test to the UE Instance
* @param descriptor - the descriptor for a command
*/
emitCommand(descriptor: object) {
this.sendDescriptor('Command', descriptor);
}
/**
* Send a Latency Test to the UE Instance
* @param descriptor - the descriptor for a UI Interaction
*/
emitUIInteraction(descriptor: object | string) {
this.sendDescriptor('UIInteraction', descriptor);
}
/**
* Send a Descriptor to the UE Instances
* @param messageType - UE Message Type
* @param descriptor - Descriptor Message as JSON
*/
sendDescriptor(messageType: string, descriptor: object | string) {
// Convert the descriptor object into a JSON string.
const descriptorAsString = JSON.stringify(descriptor);
const toStreamerMessages =
this.toStreamerMessagesMapProvider.toStreamerMessages;
const messageFormat = toStreamerMessages.getFromKey(messageType);
if (messageFormat === undefined) {
Logger.Error(
Logger.GetStackTrace(),
`Attempted to emit descriptor with message type: ${messageType}, but the frontend hasn't been configured to send such a message. Check you've added the message type in your cpp`
);
}
Logger.Log(Logger.GetStackTrace(), 'Sending: ' + descriptor, 6);
// Add the UTF-16 JSON string to the array byte buffer, going two bytes at
// a time.
const data = new DataView(
new ArrayBuffer(1 + 2 + 2 * descriptorAsString.length)
);
let byteIdx = 0;
data.setUint8(byteIdx, messageFormat.id);
byteIdx++;
data.setUint16(byteIdx, descriptorAsString.length, true);
byteIdx += 2;
for (let i = 0; i < descriptorAsString.length; i++) {
data.setUint16(byteIdx, descriptorAsString.charCodeAt(i), true);
byteIdx += 2;
}
if (!this.dataChannelSender.canSend()) {
Logger.Info(
Logger.GetStackTrace(),
`Data channel cannot send yet, skipping sending descriptor message: ${messageType} - ${descriptorAsString}`
);
return;
}
this.dataChannelSender.sendData(data.buffer);
}
}

View File

@ -26,14 +26,14 @@ export class SendMessageController {
* @param messageData - the message data we are sending over the data channel
* @returns - nil
*/
sendMessageToStreamer(messageType: string, messageData?: Array<number>) {
sendMessageToStreamer(messageType: string, messageData?: Array<number | string>) {
if (messageData === undefined) {
messageData = [];
}
const toStreamerMessages =
this.toStreamerMessagesMapProvider.toStreamerMessages;
const messageFormat = toStreamerMessages.getFromKey(messageType);
const messageFormat = toStreamerMessages.get(messageType);
if (messageFormat === undefined) {
Logger.Error(
Logger.GetStackTrace(),
@ -42,39 +42,100 @@ export class SendMessageController {
return;
}
const data = new DataView(
new ArrayBuffer(messageFormat.byteLength + 1)
);
data.setUint8(0, messageFormat.id);
let byteOffset = 1;
if(messageFormat.structure && messageData && messageFormat.structure.length !== messageData.length) {
Logger.Error(
Logger.GetStackTrace(),
`Provided message data doesn't match expected layout. Expected [ ${messageFormat.structure.map((element: string) => {
switch (element) {
case 'uint8':
case 'uint16':
case 'int16':
case 'float':
case 'double':
return 'number';
case 'string':
return 'string';
}
}).toString() } ] but received [ ${messageData.map((element: number | string) => typeof element).toString()} ]`
);
return;
}
messageData.forEach((element: number, idx: number) => {
let byteLength = 0;
const textEncoder = new TextEncoder();
// One loop to calculate the length in bytes of all of the provided data
messageData.forEach((element: number | string, idx: number) => {
const type = messageFormat.structure[idx];
switch (type) {
case 'uint8':
data.setUint8(byteOffset, element);
byteLength += 1;
break;
case 'uint16':
byteLength += 2;
break;
case 'int16':
byteLength += 2;
break;
case 'float':
byteLength += 4;
break;
case 'double':
byteLength += 8;
break;
case 'string':
// 2 bytes for string length
byteLength += 2;
// 2 bytes per characters
byteLength += 2 * textEncoder.encode(element as string).length;
break;
}
});
const data = new DataView(new ArrayBuffer(byteLength + 1));
data.setUint8(0, messageFormat.id);
let byteOffset = 1;
messageData.forEach((element: number | string, idx: number) => {
const type = messageFormat.structure[idx];
switch (type) {
case 'uint8':
data.setUint8(byteOffset, element as number);
byteOffset += 1;
break;
case 'uint16':
data.setUint16(byteOffset, element, true);
data.setUint16(byteOffset, element as number, true);
byteOffset += 2;
break;
case 'int16':
data.setInt16(byteOffset, element, true);
data.setInt16(byteOffset, element as number, true);
byteOffset += 2;
break;
case 'float':
data.setFloat32(byteOffset, element, true);
data.setFloat32(byteOffset, element as number, true);
byteOffset += 4;
break;
case 'double':
data.setFloat64(byteOffset, element, true);
data.setFloat64(byteOffset, element as number, true);
byteOffset += 8;
break;
case 'string':
data.setUint16(byteOffset, (element as string).length, true);
byteOffset += 2;
for (let i = 0; i < (element as string).length; i++) {
data.setUint16(byteOffset, (element as string).charCodeAt(i), true);
byteOffset += 2;
}
break;
}
});
@ -86,8 +147,8 @@ export class SendMessageController {
)}`
);
return;
} else {
this.dataChannelSender.sendData(data.buffer);
}
this.dataChannelSender.sendData(data.buffer);
}
}

View File

@ -1,33 +1,31 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { TwoWayMap } from './TwoWayMap';
import { Logger } from '../Logger/Logger';
export class ToStreamerMessage {
id: number;
byteLength: number;
structure?: Array<string>;
}
export class StreamMessageController {
toStreamerHandlers: Map<
string,
(messageData?: Array<number> | undefined) => void
(messageData?: Array<number | string> | undefined) => void
>;
fromStreamerHandlers: Map<
string,
(messageType: string, messageData?: ArrayBuffer | undefined) => void
>;
// Type Format
toStreamerMessages: TwoWayMap<string, ToStreamerMessage>;
// Type ID
fromStreamerMessages: TwoWayMap<string, number>;
// Type Format
toStreamerMessages: Map<string, ToStreamerMessage>;
// ID Type
fromStreamerMessages: Map<number, string>;
constructor() {
this.toStreamerHandlers = new Map();
this.fromStreamerHandlers = new Map();
this.toStreamerMessages = new TwoWayMap();
this.fromStreamerMessages = new TwoWayMap();
this.toStreamerMessages = new Map();
this.fromStreamerMessages = new Map();
}
/**
@ -37,190 +35,166 @@ export class StreamMessageController {
/*
* Control Messages. Range = 0..49.
*/
this.toStreamerMessages.add('IFrameRequest', {
this.toStreamerMessages.set('IFrameRequest', {
id: 0,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('RequestQualityControl', {
this.toStreamerMessages.set('RequestQualityControl', {
id: 1,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('FpsRequest', {
this.toStreamerMessages.set('FpsRequest', {
id: 2,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('AverageBitrateRequest', {
this.toStreamerMessages.set('AverageBitrateRequest', {
id: 3,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('StartStreaming', {
this.toStreamerMessages.set('StartStreaming', {
id: 4,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('StopStreaming', {
this.toStreamerMessages.set('StopStreaming', {
id: 5,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('LatencyTest', {
this.toStreamerMessages.set('LatencyTest', {
id: 6,
byteLength: 0,
structure: []
structure: ['string']
});
this.toStreamerMessages.add('RequestInitialSettings', {
this.toStreamerMessages.set('RequestInitialSettings', {
id: 7,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('TestEcho', {
this.toStreamerMessages.set('TestEcho', {
id: 8,
byteLength: 0,
structure: []
});
this.toStreamerMessages.set('DataChannelLatencyTest', {
id: 9,
structure: []
});
/*
* Input Messages. Range = 50..89.
*/
// Generic Input Messages. Range = 50..59.
this.toStreamerMessages.add('UIInteraction', {
this.toStreamerMessages.set('UIInteraction', {
id: 50,
byteLength: 0,
structure: []
structure: ['string']
});
this.toStreamerMessages.add('Command', {
this.toStreamerMessages.set('Command', {
id: 51,
byteLength: 0,
structure: []
structure: ['string']
});
// Keyboard Input Message. Range = 60..69.
this.toStreamerMessages.add('KeyDown', {
this.toStreamerMessages.set('KeyDown', {
id: 60,
byteLength: 2,
// keyCode isRepeat
structure: ['uint8', 'uint8']
});
this.toStreamerMessages.add('KeyUp', {
this.toStreamerMessages.set('KeyUp', {
id: 61,
byteLength: 1,
// keyCode
structure: ['uint8']
});
this.toStreamerMessages.add('KeyPress', {
this.toStreamerMessages.set('KeyPress', {
id: 62,
byteLength: 2,
// charcode
structure: ['uint16']
});
// Mouse Input Messages. Range = 70..79.
this.toStreamerMessages.add('MouseEnter', {
this.toStreamerMessages.set('MouseEnter', {
id: 70,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('MouseLeave', {
this.toStreamerMessages.set('MouseLeave', {
id: 71,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('MouseDown', {
this.toStreamerMessages.set('MouseDown', {
id: 72,
byteLength: 5,
// button x y
structure: ['uint8', 'uint16', 'uint16']
});
this.toStreamerMessages.add('MouseUp', {
this.toStreamerMessages.set('MouseUp', {
id: 73,
byteLength: 5,
// button x y
structure: ['uint8', 'uint16', 'uint16']
});
this.toStreamerMessages.add('MouseMove', {
this.toStreamerMessages.set('MouseMove', {
id: 74,
byteLength: 8,
// x y deltaX deltaY
structure: ['uint16', 'uint16', 'int16', 'int16']
});
this.toStreamerMessages.add('MouseWheel', {
this.toStreamerMessages.set('MouseWheel', {
id: 75,
byteLength: 6,
// delta x y
structure: ['int16', 'uint16', 'uint16']
});
this.toStreamerMessages.add('MouseDouble', {
this.toStreamerMessages.set('MouseDouble', {
id: 76,
byteLength: 5,
// button x y
structure: ['uint8', 'uint16', 'uint16']
});
// Touch Input Messages. Range = 80..89.
this.toStreamerMessages.add('TouchStart', {
this.toStreamerMessages.set('TouchStart', {
id: 80,
byteLength: 8,
// numtouches(1) x y idx force valid
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
});
this.toStreamerMessages.add('TouchEnd', {
this.toStreamerMessages.set('TouchEnd', {
id: 81,
byteLength: 8,
// numtouches(1) x y idx force valid
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
});
this.toStreamerMessages.add('TouchMove', {
this.toStreamerMessages.set('TouchMove', {
id: 82,
byteLength: 8,
// numtouches(1) x y idx force valid
structure: ['uint8', 'uint16', 'uint16', 'uint8', 'uint8', 'uint8']
});
// Gamepad Input Messages. Range = 90..99
this.toStreamerMessages.add('GamepadConnected', {
this.toStreamerMessages.set('GamepadConnected', {
id: 93,
byteLength: 0,
structure: []
});
this.toStreamerMessages.add('GamepadButtonPressed', {
this.toStreamerMessages.set('GamepadButtonPressed', {
id: 90,
byteLength: 3,
// ctrlerId button isRepeat
// ctrlerId button isRepeat
structure: ['uint8', 'uint8', 'uint8']
});
this.toStreamerMessages.add('GamepadButtonReleased', {
this.toStreamerMessages.set('GamepadButtonReleased', {
id: 91,
byteLength: 3,
// ctrlerId button isRepeat(0)
// ctrlerId button isRepeat(0)
structure: ['uint8', 'uint8', 'uint8']
});
this.toStreamerMessages.add('GamepadAnalog', {
this.toStreamerMessages.set('GamepadAnalog', {
id: 92,
byteLength: 10,
// ctrlerId button analogValue
// ctrlerId button analogValue
structure: ['uint8', 'uint8', 'double']
});
this.toStreamerMessages.add('GamepadDisconnected', {
this.toStreamerMessages.set('GamepadDisconnected', {
id: 94,
byteLength: 1,
// ctrlerId
structure: ['uint8']
});
this.fromStreamerMessages.add('QualityControlOwnership', 0);
this.fromStreamerMessages.add('Response', 1);
this.fromStreamerMessages.add('Command', 2);
this.fromStreamerMessages.add('FreezeFrame', 3);
this.fromStreamerMessages.add('UnfreezeFrame', 4);
this.fromStreamerMessages.add('VideoEncoderAvgQP', 5);
this.fromStreamerMessages.add('LatencyTest', 6);
this.fromStreamerMessages.add('InitialSettings', 7);
this.fromStreamerMessages.add('FileExtension', 8);
this.fromStreamerMessages.add('FileMimeType', 9);
this.fromStreamerMessages.add('FileContents', 10);
this.fromStreamerMessages.add('TestEcho', 11);
this.fromStreamerMessages.add('InputControlOwnership', 12);
this.fromStreamerMessages.add('GamepadResponse', 13);
this.fromStreamerMessages.add('Protocol', 255);
this.fromStreamerMessages.set(0, 'QualityControlOwnership');
this.fromStreamerMessages.set(1, 'Response');
this.fromStreamerMessages.set(2, 'Command');
this.fromStreamerMessages.set(3, 'FreezeFrame');
this.fromStreamerMessages.set(4, 'UnfreezeFrame');
this.fromStreamerMessages.set(5, 'VideoEncoderAvgQP');
this.fromStreamerMessages.set(6, 'LatencyTest');
this.fromStreamerMessages.set(7, 'InitialSettings');
this.fromStreamerMessages.set(8, 'FileExtension');
this.fromStreamerMessages.set(9, 'FileMimeType');
this.fromStreamerMessages.set(10, 'FileContents');
this.fromStreamerMessages.set(11, 'TestEcho');
this.fromStreamerMessages.set(12, 'InputControlOwnership');
this.fromStreamerMessages.set(13, 'GamepadResponse');
this.fromStreamerMessages.set(14, 'DataChannelLatencyTest');
this.fromStreamerMessages.set(255, 'Protocol');
}
/**

View File

@ -1,52 +0,0 @@
// Copyright Epic Games, Inc. All Rights Reserved.
export class TwoWayMap<KeyType, ValueType> {
map: Map<KeyType, ValueType>;
reverseMap: Map<ValueType, KeyType>;
/**
* @param map - an optional map of parameters
*/
constructor() {
this.map = new Map();
this.reverseMap = new Map();
}
/**
* Get the value from the map by key
* @param key - the key we are searching by
* @returns - the value associated with the key
*/
getFromKey(key: KeyType) {
return this.map.get(key);
}
/**
* Get the reverse key from the map by searching by value
* @param value - the key we are searching by
* @returns - they key associated with the value
*/
getFromValue(value: ValueType) {
return this.reverseMap.get(value);
}
/**
* Add a key and value to both the map and reverse map
* @param key - the indexing key
* @param value - the value associated with the key
*/
add(key: KeyType, value: ValueType) {
this.map.set(key, value);
this.reverseMap.set(value, key);
}
/**
* Remove a key and value from both the map and reverse map
* @param key - the indexing key
* @param value - the value associated with the key
*/
remove(key: KeyType, value: ValueType) {
this.map.delete(key);
this.reverseMap.delete(value);
}
}

View File

@ -12,6 +12,10 @@ import { SettingFlag } from '../Config/SettingFlag';
import { SettingNumber } from '../Config/SettingNumber';
import { SettingText } from '../Config/SettingText';
import { SettingOption } from '../Config/SettingOption';
import {
DataChannelLatencyTestResponse,
DataChannelLatencyTestResult
} from "../DataChannel/DataChannelLatencyTestResults";
/**
* An event that is emitted when AFK disconnect is about to happen.
@ -140,7 +144,7 @@ export class WebRtcDisconnectedEvent extends Event {
/** Message describing the disconnect reason */
eventString: string;
/** true if the user is able to reconnect, false if disconnected because of unrecoverable reasons like not able to connect to the signaling server */
showActionOrErrorOnDisconnect: boolean;
allowClickToReconnect: boolean;
};
constructor(data: WebRtcDisconnectedEvent['data']) {
super('webRtcDisconnected');
@ -219,6 +223,36 @@ export class StreamLoadingEvent extends Event {
}
}
/**
* An event that is emitted when video stream loading has finished.
*/
export class StreamPreConnectEvent extends Event {
readonly type: 'streamConnect';
constructor() {
super('streamConnect');
}
}
/**
* An event that is emitted when video stream has stopped.
*/
export class StreamPreDisconnectEvent extends Event {
readonly type: 'streamDisconnect';
constructor() {
super('streamDisconnect');
}
}
/**
* An event that is emitted when video stream is reconnecting.
*/
export class StreamReconnectEvent extends Event {
readonly type: 'streamReconnect';
constructor() {
super('streamReconnect');
}
}
/**
* An event that is emitted if there are errors loading the video stream.
*/
@ -313,7 +347,9 @@ export class StreamerListMessageEvent extends Event {
/** Streamer list message containing an array of streamer ids */
messageStreamerList: MessageStreamerList;
/** Auto-selected streamer from the list, or null if unable to auto-select and user should be prompted to select */
autoSelectedStreamerId: string | null;
autoSelectedStreamerId: string;
/** Wanted streamer id from various configurations. */
wantedStreamerId: string;
};
constructor(data: StreamerListMessageEvent['data']) {
super('streamerListMessage');
@ -321,6 +357,21 @@ export class StreamerListMessageEvent extends Event {
}
}
/**
* An event that is emitted when a subscribed to streamer's id changes.
*/
export class StreamerIDChangedMessageEvent extends Event {
readonly type: 'streamerIDChangedMessage';
readonly data: {
/** The new ID of the streamer. */
newID: string;
};
constructor(data: StreamerIDChangedMessageEvent['data']) {
super('StreamerIDChangedMessage');
this.data = data;
}
}
/**
* An event that is emitted when receiving latency test results.
*/
@ -336,6 +387,37 @@ export class LatencyTestResultEvent extends Event {
}
}
/**
* An event that is emitted when receiving data channel latency test response from server.
* This event is handled by DataChannelLatencyTestController
*/
export class DataChannelLatencyTestResponseEvent extends Event {
readonly type: 'dataChannelLatencyTestResponse';
readonly data: {
/** Latency test result object */
response: DataChannelLatencyTestResponse
};
constructor(data: DataChannelLatencyTestResponseEvent['data']) {
super('dataChannelLatencyTestResponse');
this.data = data;
}
}
/**
* An event that is emitted when data channel latency test results are ready.
*/
export class DataChannelLatencyTestResultEvent extends Event {
readonly type: 'dataChannelLatencyTestResult';
readonly data: {
/** Latency test result object */
result: DataChannelLatencyTestResult
};
constructor(data: DataChannelLatencyTestResultEvent['data']) {
super('dataChannelLatencyTestResult');
this.data = data;
}
}
/**
* An event that is emitted when receiving initial settings from UE.
*/
@ -440,6 +522,31 @@ export class XrFrameEvent extends Event {
}
}
/**
* An event that is emitted when receiving a player count from the signalling server
*/
export class PlayerCountEvent extends Event {
readonly type: 'playerCount';
readonly data: {
/** count object */
count: number
};
constructor(data: PlayerCountEvent['data']) {
super('playerCount');
this.data = data;
}
}
/**
* An event that is emitted when the webRTC connections is relayed over TCP.
*/
export class WebRtcTCPRelayDetectedEvent extends Event {
readonly type: 'webRtcTCPRelayDetected';
constructor() {
super('webRtcTCPRelayDetected');
}
}
export type PixelStreamingEvent =
| AfkWarningActivateEvent
| AfkWarningUpdateEvent
@ -457,6 +564,9 @@ export type PixelStreamingEvent =
| DataChannelErrorEvent
| VideoInitializedEvent
| StreamLoadingEvent
| StreamPreConnectEvent
| StreamReconnectEvent
| StreamPreDisconnectEvent
| PlayStreamErrorEvent
| PlayStreamEvent
| PlayStreamRejectedEvent
@ -464,12 +574,17 @@ export type PixelStreamingEvent =
| HideFreezeFrameEvent
| StatsReceivedEvent
| StreamerListMessageEvent
| StreamerIDChangedMessageEvent
| LatencyTestResultEvent
| DataChannelLatencyTestResponseEvent
| DataChannelLatencyTestResultEvent
| InitialSettingsEvent
| SettingsChangedEvent
| XrSessionStartedEvent
| XrSessionEndedEvent
| XrFrameEvent;
| XrFrameEvent
| PlayerCountEvent
| WebRtcTCPRelayDetectedEvent;
export class EventEmitter extends EventTarget {
/**

View File

@ -0,0 +1,41 @@
export class RTCUtils {
static isVideoTransciever(transceiver : RTCRtpTransceiver | undefined) : boolean {
return this.canTransceiverReceiveVideo(transceiver) || this.canTransceiverSendVideo(transceiver);
}
static canTransceiverReceiveVideo(transceiver : RTCRtpTransceiver | undefined) : boolean {
return !!transceiver &&
(transceiver.direction === 'sendrecv' || transceiver.direction === 'recvonly') &&
transceiver.receiver &&
transceiver.receiver.track &&
transceiver.receiver.track.kind === 'video';
}
static canTransceiverSendVideo(transceiver : RTCRtpTransceiver | undefined) : boolean {
return !!transceiver &&
(transceiver.direction === 'sendrecv' || transceiver.direction === 'sendonly') &&
transceiver.sender &&
transceiver.sender.track &&
transceiver.sender.track.kind === 'video';
}
static isAudioTransciever(transceiver : RTCRtpTransceiver | undefined) : boolean {
return this.canTransceiverReceiveAudio(transceiver) || this.canTransceiverSendAudio(transceiver);
}
static canTransceiverReceiveAudio(transceiver : RTCRtpTransceiver | undefined) : boolean {
return !!transceiver &&
(transceiver.direction === 'sendrecv' || transceiver.direction === 'recvonly') &&
transceiver.receiver &&
transceiver.receiver.track &&
transceiver.receiver.track.kind === 'audio';
}
static canTransceiverSendAudio(transceiver : RTCRtpTransceiver | undefined) : boolean {
return !!transceiver &&
(transceiver.direction === 'sendrecv' || transceiver.direction === 'sendonly') &&
transceiver.sender &&
transceiver.sender.track &&
transceiver.sender.track.kind === 'audio';
}
}

View File

@ -18,6 +18,7 @@ export class StreamController {
constructor(videoElementProvider: VideoPlayer) {
this.videoElementProvider = videoElementProvider;
this.audioElement = document.createElement('Audio') as HTMLAudioElement;
this.videoElementProvider.setAudioElement(this.audioElement);
}
/**

View File

@ -18,6 +18,7 @@ declare global {
export class VideoPlayer {
private config: Config;
private videoElement: HTMLVideoElement;
private audioElement?: HTMLAudioElement;
private orientationChangeTimeout: number;
private lastTimeResized = new Date().getTime();
@ -52,8 +53,11 @@ export class VideoPlayer {
);
};
// set play for video
// set play for video (and audio)
this.videoElement.onclick = () => {
if (this.audioElement != undefined && this.audioElement.paused) {
this.audioElement.play();
}
if (this.videoElement.paused) {
this.videoElement.play();
}
@ -70,6 +74,10 @@ export class VideoPlayer {
);
}
public setAudioElement(audioElement: HTMLAudioElement) : void {
this.audioElement = audioElement;
}
/**
* Sets up the video element with any application config and plays the video element.
* @returns A promise for if playing the video was successful or not.
@ -210,7 +218,7 @@ export class VideoPlayer {
}
const now = new Date().getTime();
if (now - this.lastTimeResized > 1000) {
if (now - this.lastTimeResized > 300) {
const videoElementParent = this.getVideoParentElement();
if (!videoElementParent) {
return;
@ -230,8 +238,8 @@ export class VideoPlayer {
);
clearTimeout(this.resizeTimeoutHandle);
this.resizeTimeoutHandle = window.setTimeout(
() => this.updateVideoStreamSize,
1000
() => this.updateVideoStreamSize(),
100
);
}
}

File diff suppressed because it is too large Load Diff

View File

@ -6,6 +6,7 @@
export enum MessageRecvTypes {
CONFIG = 'config',
STREAMER_LIST = 'streamerList',
STREAMER_ID_CHANGED = 'streamerIDChanged',
PLAYER_COUNT = 'playerCount',
OFFER = 'offer',
ANSWER = 'answer',
@ -42,6 +43,13 @@ export class MessageStreamerList extends MessageRecv {
ids: string[];
}
/**
* Streamer ID Changed Message Wrapper
*/
export class MessageStreamerIDChanged extends MessageRecv {
newID: string;
}
/**
* Player Count Message wrapper
*/

View File

@ -24,6 +24,20 @@ export class MessageSend implements Send {
type: string;
peerConnectionOptions: object;
/**
* A filter for controlling what parameters to actually send.
* Good for excluding default values or hidden internals.
* Example for including everything but zero bitrate fields...
* sendFilter(key: string, value: any) {
* if ((key == "minBitrate" || key == "maxBitrate") && value <= 0) return undefined;
* return value;
* }
* Return undefined to exclude the property completely.
*/
sendFilter(key: string, value: any) {
return value;
}
/**
* Turns the wrapper into a JSON String
* @returns - JSON String of the Message to send
@ -31,10 +45,10 @@ export class MessageSend implements Send {
payload() {
Logger.Log(
Logger.GetStackTrace(),
'Sending => \n' + JSON.stringify(this, undefined, 4),
'Sending => \n' + JSON.stringify(this, this.sendFilter, 4),
6
);
return JSON.stringify(this);
return JSON.stringify(this, this.sendFilter);
}
}
@ -83,24 +97,45 @@ export class MessagePong extends MessageSend {
}
}
export type ExtraOfferParameters = {
minBitrateBps: number;
maxBitrateBps: number;
}
/**
* Web RTC Offer message wrapper
*/
export class MessageWebRTCOffer extends MessageSend {
sdp: string;
minBitrate: number;
maxBitrate: number;
/**
* @param offer - Generated Web RTC Offer
*/
constructor(offer?: RTCSessionDescriptionInit) {
constructor(offer: RTCSessionDescriptionInit, extraParams: ExtraOfferParameters) {
super();
this.type = MessageSendTypes.OFFER;
this.minBitrate = 0;
this.maxBitrate = 0;
if (offer) {
this.type = offer.type as MessageSendTypes;
this.sdp = offer.sdp;
this.minBitrate = extraParams.minBitrateBps;
this.maxBitrate = extraParams.maxBitrateBps;
}
}
sendFilter(key: string, value: any) {
if ((key == "minBitrate" || key == "maxBitrate") && value <= 0) return undefined;
return value;
}
}
export type ExtraAnswerParameters = {
minBitrateBps: number;
maxBitrateBps: number;
}
/**
@ -108,19 +143,30 @@ export class MessageWebRTCOffer extends MessageSend {
*/
export class MessageWebRTCAnswer extends MessageSend {
sdp: string;
minBitrate: number;
maxBitrate: number;
/**
* @param answer - Generated Web RTC Offer
*/
constructor(answer?: RTCSessionDescriptionInit) {
constructor(answer: RTCSessionDescriptionInit, extraParams: ExtraAnswerParameters) {
super();
this.type = MessageSendTypes.ANSWER;
this.minBitrate = 0;
this.maxBitrate = 0;
if (answer) {
this.type = answer.type as MessageSendTypes;
this.sdp = answer.sdp;
this.minBitrate = extraParams.minBitrateBps;
this.maxBitrate = extraParams.maxBitrateBps;
}
}
sendFilter(key: string, value: any) {
if ((key == "minBitrate" || key == "maxBitrate") && value <= 0) return undefined;
return value;
}
}
/**

View File

@ -6,6 +6,7 @@ import {
MessageRecvTypes,
MessageConfig,
MessageStreamerList,
MessageStreamerIDChanged,
MessagePlayerCount,
MessageAnswer,
MessageOffer,
@ -92,6 +93,21 @@ export class SignallingProtocol {
}
);
// STREAMER_ID_CHANGED
websocketController.signallingProtocol.addMessageHandler(
MessageRecvTypes.STREAMER_ID_CHANGED,
(idPayload: string) => {
Logger.Log(
Logger.GetStackTrace(),
MessageRecvTypes.STREAMER_ID_CHANGED,
6
);
const streamerIdMessage: MessageStreamerIDChanged =
JSON.parse(idPayload);
websocketController.onStreamerIDChanged(streamerIdMessage);
}
);
// PLAYER_COUNT
websocketController.signallingProtocol.addMessageHandler(
MessageRecvTypes.PLAYER_COUNT,
@ -108,6 +124,7 @@ export class SignallingProtocol {
'Player Count: ' + playerCount.count,
6
);
websocketController.onPlayerCount(playerCount)
}
);

View File

@ -134,7 +134,6 @@ export class WebSocketController {
* @param event - Close Event
*/
handleOnClose(event: CloseEvent) {
this.onWebSocketOncloseOverlayMessage(event);
Logger.Log(
Logger.GetStackTrace(),
'Disconnected to the signalling server via WebSocket: ' +
@ -142,7 +141,7 @@ export class WebSocketController {
' - ' +
event.reason
);
this.onClose.dispatchEvent(new Event('close'));
this.onClose.dispatchEvent(new CustomEvent('close', { 'detail': event }));
}
requestStreamerList() {
@ -160,13 +159,13 @@ export class WebSocketController {
this.webSocket.send(payload.payload());
}
sendWebRtcOffer(offer: RTCSessionDescriptionInit) {
const payload = new MessageSend.MessageWebRTCOffer(offer);
sendWebRtcOffer(offer: RTCSessionDescriptionInit, extraParams: MessageSend.ExtraOfferParameters) {
const payload = new MessageSend.MessageWebRTCOffer(offer, extraParams);
this.webSocket.send(payload.payload());
}
sendWebRtcAnswer(answer: RTCSessionDescriptionInit) {
const payload = new MessageSend.MessageWebRTCAnswer(answer);
sendWebRtcAnswer(answer: RTCSessionDescriptionInit, extraParams: MessageSend.ExtraAnswerParameters) {
const payload = new MessageSend.MessageWebRTCAnswer(answer, extraParams);
this.webSocket.send(payload.payload());
}
@ -204,10 +203,6 @@ export class WebSocketController {
this.webSocket?.close();
}
/** Event used for Displaying websocket closed messages */
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
onWebSocketOncloseOverlayMessage(event: CloseEvent) {}
/**
* The Message Contains the payload of the peer connection options used for the RTC Peer hand shake
* @param messageConfig - Config Message received from he signaling server
@ -216,12 +211,19 @@ export class WebSocketController {
onConfig(messageConfig: MessageReceive.MessageConfig) {}
/**
* The Message Contains the payload of the peer connection options used for the RTC Peer hand shake
* @param messageConfig - Config Message received from he signaling server
* The Message contains all the ids of streamers available on the server.
* @param messageStreamerList - The message with the list of the available streamer ids.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
onStreamerList(messageStreamerList: MessageReceive.MessageStreamerList) {}
/**
* The Message contains the new id of a subscribed to streamer.
* @param message - Message conaining the new id of the streamer.
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
onStreamerIDChanged(message: MessageReceive.MessageStreamerIDChanged) {}
/**
* @param iceCandidate - Ice Candidate sent from the Signaling server server's RTC hand shake
*/
@ -247,7 +249,12 @@ export class WebSocketController {
* @param messageDataChannels - The data channels details
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
onWebRtcPeerDataChannels(
messageDataChannels: MessageReceive.MessagePeerDataChannels
) {}
onWebRtcPeerDataChannels(messageDataChannels: MessageReceive.MessagePeerDataChannels) {}
/**
* Event is fired when the websocket receives the an updated player count from cirrus
* @param MessagePlayerCount - The new player count
*/
// eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function
onPlayerCount(playerCount: MessageReceive.MessagePlayerCount) {}
}

View File

@ -33,6 +33,7 @@ export {
export { AggregatedStats } from './PeerConnectionController/AggregatedStats';
export { Logger } from './Logger/Logger';
export { UnquantizedDenormalizedUnsignedCoord as UnquantizedAndDenormalizeUnsigned } from './Util/CoordinateConverter';
export { MessageDirection } from './UeInstanceMessage/StreamMessageController';
export { MessageSend } from './WebSockets/MessageSend';
export { MessageRecv, MessageStreamerList } from './WebSockets/MessageReceive';
export { WebSocketController } from './WebSockets/WebSocketController';

View File

@ -1,12 +1,12 @@
{
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2",
"version": "0.3.0",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4",
"version": "0.0.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2",
"version": "0.3.0",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4",
"version": "0.0.3",
"license": "MIT",
"dependencies": {
"jss": "^10.9.2",
@ -14,7 +14,7 @@
"jss-plugin-global": "^10.9.2"
},
"devDependencies": {
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": "^0.4.0",
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.3",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"cspell": "^4.1.0",
@ -27,7 +27,7 @@
"webpack-cli": "^5.0.1"
},
"peerDependencies": {
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": "^0.4.0"
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.3"
}
},
"node_modules/@babel/runtime": {
@ -248,10 +248,10 @@
"node": ">=10.0.0"
}
},
"node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.2/-/lib-pixelstreamingfrontend-ue5.2-0.4.0.tgz",
"integrity": "sha512-mMiTQOCtWV6+f/O5LLseccLPSQAuRivY97m6tRWs6TpmCeqY+vbowHGgxqxRJNzZsj+f0U1kXB/CB69h72raXQ==",
"node_modules/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4/-/lib-pixelstreamingfrontend-ue5.4-0.0.3.tgz",
"integrity": "sha512-Llp6aQHjQYg6eYlf8GBB60uQJ+/ueVCPrFnR7SP5muqjXKdBJPXn5hiZpG6tR9Z/soHCyxrudXtGhrObcbsSVg==",
"dev": true,
"dependencies": {
"sdp": "^3.1.0"
@ -3531,9 +3531,9 @@
"dev": true
},
"node_modules/word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true,
"engines": {
"node": ">=0.10.0"
@ -3798,10 +3798,10 @@
"integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==",
"dev": true
},
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": {
"version": "0.4.0",
"resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.2/-/lib-pixelstreamingfrontend-ue5.2-0.4.0.tgz",
"integrity": "sha512-mMiTQOCtWV6+f/O5LLseccLPSQAuRivY97m6tRWs6TpmCeqY+vbowHGgxqxRJNzZsj+f0U1kXB/CB69h72raXQ==",
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": {
"version": "0.0.3",
"resolved": "https://registry.npmjs.org/@epicgames-ps/lib-pixelstreamingfrontend-ue5.4/-/lib-pixelstreamingfrontend-ue5.4-0.0.3.tgz",
"integrity": "sha512-Llp6aQHjQYg6eYlf8GBB60uQJ+/ueVCPrFnR7SP5muqjXKdBJPXn5hiZpG6tR9Z/soHCyxrudXtGhrObcbsSVg==",
"dev": true,
"requires": {
"sdp": "^3.1.0"
@ -6195,9 +6195,9 @@
"dev": true
},
"word-wrap": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
"integrity": "sha512-Hz/mrNwitNRh/HUAtM/VT/5VH+ygD6DV7mYKZAtHOrbs8U7lvPS6xf7EJKMF0uW1KJCl0H701g3ZGus+muE5vQ==",
"version": "1.2.5",
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.5.tgz",
"integrity": "sha512-BN22B5eaMMI9UMtjrGd5g5eCYPpCPDUy0FJXbYsaT5zYxjFOckS53SQDE3pWkVoWpHXVb3BrYcEN4Twa55B5cA==",
"dev": true
},
"wrappy": {

View File

@ -1,7 +1,7 @@
{
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.2",
"version": "0.3.0",
"description": "Reference frontend UI library for Pixel Streaming - gives the stock look and feel. ",
"name": "@epicgames-ps/lib-pixelstreamingfrontend-ui-ue5.4",
"version": "0.0.3",
"description": "Reference frontend UI library for Unreal Engine 5.4 Pixel Streaming - gives the stock look and feel.",
"main": "dist/lib-pixelstreamingfrontend-ui.js",
"module": "dist/lib-pixelstreamingfrontend-ui.esm.js",
"types": "types/pixelstreamingfrontend-ui.d.ts",
@ -16,7 +16,7 @@
"spellcheck": "cspell \"{README.md,.github/*.md,src/**/*.ts}\""
},
"devDependencies": {
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": "^0.4.0",
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.3",
"@typescript-eslint/eslint-plugin": "^5.16.0",
"@typescript-eslint/parser": "^5.16.0",
"cspell": "^4.1.0",
@ -34,7 +34,7 @@
"jss-plugin-global": "^10.9.2"
},
"peerDependencies": {
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.2": "^0.4.0"
"@epicgames-ps/lib-pixelstreamingfrontend-ue5.4": "^0.0.3"
},
"repository": {
"type": "git",

View File

@ -8,7 +8,7 @@ import {
LatencyTestResults,
InitialSettings,
MessageStreamerList
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { OverlayBase } from '../Overlay/BaseOverlay';
import { ActionOverlay } from '../Overlay/ActionOverlay';
import { TextOverlay } from '../Overlay/TextOverlay';
@ -31,6 +31,9 @@ import {
UIElementConfig
} from '../UI/UIConfigurationTypes'
import { FullScreenIconBase, FullScreenIconExternal } from '../UI/FullscreenIcon';
import {
DataChannelLatencyTestResult
} from "@epicgames-ps/lib-pixelstreamingfrontend-ue5.4/types/DataChannel/DataChannelLatencyTestResults";
/**
@ -194,7 +197,9 @@ export class Application {
? new FullScreenIconExternal(this._options.fullScreenControlsConfig.customElement)
// Or use the one created by the Controls initializer earlier
: controls.fullscreenIcon;
if (fullScreenButton) fullScreenButton.fullscreenElement = this.rootElement;
if (fullScreenButton) {
fullScreenButton.fullscreenElement = /iPad|iPhone|iPod/.test(navigator.userAgent) ? this.stream.videoElementParent.getElementsByTagName("video")[0] : this.rootElement;
}
// Add settings button to controls
const settingsButton : HTMLElement | undefined =
@ -319,8 +324,8 @@ export class Application {
);
this.stream.addEventListener(
'webRtcDisconnected',
({ data: { eventString, showActionOrErrorOnDisconnect } }) =>
this.onDisconnect(eventString, showActionOrErrorOnDisconnect)
({ data: { eventString, allowClickToReconnect } }) =>
this.onDisconnect(eventString, allowClickToReconnect)
);
this.stream.addEventListener('videoInitialized', () =>
this.onVideoInitialized()
@ -354,15 +359,33 @@ export class Application {
({ data: { latencyTimings } }) =>
this.onLatencyTestResults(latencyTimings)
);
this.stream.addEventListener(
'dataChannelLatencyTestResult',
({data: { result } }) =>
this.onDataChannelLatencyTestResults(result)
)
this.stream.addEventListener(
'streamerListMessage',
({ data: { messageStreamerList, autoSelectedStreamerId } }) =>
this.handleStreamerListMessage(messageStreamerList, autoSelectedStreamerId)
({ data: { messageStreamerList, autoSelectedStreamerId, wantedStreamerId } }) =>
this.handleStreamerListMessage(messageStreamerList, autoSelectedStreamerId, wantedStreamerId)
);
this.stream.addEventListener(
'settingsChanged',
(event) => this.configUI.onSettingsChanged(event)
);
this.stream.addEventListener(
'playerCount',
({ data: { count }}) =>
this.onPlayerCount(count)
);
this.stream.addEventListener(
'webRtcTCPRelayDetected',
({}) =>
Logger.Warning(
Logger.GetStackTrace(),
`Stream quailty degraded due to network enviroment, stream is relayed over TCP.`
)
);
}
/**
@ -472,7 +495,7 @@ export class Application {
* Shows or hides the settings panel if clicked
*/
settingsClicked() {
this.statsPanel.hide();
this.statsPanel?.hide();
this.settingsPanel.toggleVisibility();
}
@ -480,7 +503,7 @@ export class Application {
* Shows or hides the stats panel if clicked
*/
statsClicked() {
this.settingsPanel.hide();
this.settingsPanel?.hide();
this.statsPanel.toggleVisibility();
}
@ -558,19 +581,17 @@ export class Application {
/**
* Event fired when the video is disconnected - displays the error overlay and resets the buttons stream tools upon disconnect
* @param eventString - the event text that will be shown in the overlay
* @param allowClickToReconnect - true if we want to allow the user to click to reconnect. Otherwise it's just a message.
*/
onDisconnect(eventString: string, showActionOrErrorOnDisconnect: boolean) {
if (showActionOrErrorOnDisconnect == false) {
this.showErrorOverlay(`Disconnected: ${eventString}`);
onDisconnect(eventString: string, allowClickToReconnect: boolean) {
const overlayMessage = 'Disconnected' + (eventString ? `: ${eventString}` : '');
if (allowClickToReconnect) {
this.showDisconnectOverlay(`${overlayMessage} Click To Restart.`);
} else {
this.showDisconnectOverlay(
`Disconnected: ${eventString} <div class="clickableState">Click To Restart</div>`
);
this.showErrorOverlay(overlayMessage);
}
// disable starting a latency check
this.statsPanel.latencyTest.latencyTestButton.onclick = () => {
// do nothing
};
// disable starting a latency checks
this.statsPanel?.onDisconnect();
}
/**
@ -617,11 +638,7 @@ export class Application {
if (!this.stream.config.isFlagEnabled(Flags.AutoPlayVideo)) {
this.showPlayOverlay();
}
// starting a latency check
this.statsPanel.latencyTest.latencyTestButton.onclick = () => {
this.stream.requestLatencyTest();
};
this.statsPanel?.onVideoInitialized(this.stream);
}
/**
@ -637,39 +654,62 @@ export class Application {
onInitialSettings(settings: InitialSettings) {
if (settings.PixelStreamingSettings) {
const disableLatencyTest =
settings.PixelStreamingSettings.DisableLatencyTest;
if (disableLatencyTest) {
this.statsPanel.latencyTest.latencyTestButton.disabled = true;
this.statsPanel.latencyTest.latencyTestButton.title =
'Disabled by -PixelStreamingDisableLatencyTester=true';
Logger.Info(
Logger.GetStackTrace(),
'-PixelStreamingDisableLatencyTester=true, requesting latency report from the the browser to UE is disabled.'
);
}
this.statsPanel?.configure(settings.PixelStreamingSettings);
}
}
onStatsReceived(aggregatedStats: AggregatedStats) {
// Grab all stats we can off the aggregated stats
this.statsPanel.handleStats(aggregatedStats);
this.statsPanel?.handleStats(aggregatedStats);
}
onLatencyTestResults(latencyTimings: LatencyTestResults) {
this.statsPanel.latencyTest.handleTestResult(latencyTimings);
this.statsPanel?.latencyTest.handleTestResult(latencyTimings);
}
handleStreamerListMessage(messageStreamingList: MessageStreamerList, autoSelectedStreamerId: string | null) {
if (autoSelectedStreamerId === null) {
if(messageStreamingList.ids.length === 0) {
this.showDisconnectOverlay(
'No streamers connected. <div class="clickableState">Click To Restart</div>'
);
onDataChannelLatencyTestResults(result: DataChannelLatencyTestResult) {
this.statsPanel?.dataChannelLatencyTest.handleTestResult(result);
}
onPlayerCount(playerCount: number) {
this.statsPanel?.handlePlayerCount(playerCount);
}
handleStreamerListMessage(messageStreamingList: MessageStreamerList, autoSelectedStreamerId: string, wantedStreamerId: string) {
const waitForStreamer = this.stream.config.isFlagEnabled(Flags.WaitForStreamer);
const isReconnecting = this.stream.isReconnecting();
let message: string = null;
let allowRestart: boolean = true;
if (!autoSelectedStreamerId) {
if (waitForStreamer && wantedStreamerId) {
if (isReconnecting) {
message = `Waiting for ${wantedStreamerId} to become available.`;
allowRestart = false;
} else {
message = `Gave up waiting for ${wantedStreamerId} to become available. Click to try again`;
if (messageStreamingList.ids.length > 0) {
message += ` or select a streamer from the settings menu.`;
}
allowRestart = true;
}
} else if (messageStreamingList.ids.length == 0) {
if (isReconnecting) {
message = `Waiting for a streamer to become available.`;
allowRestart = false;
} else {
message = `No streamers available. Click to try again.`;
allowRestart = true;
}
} else {
this.showTextOverlay(
'Multiple streamers detected. Use the dropdown in the settings menu to select the streamer'
);
message = `Multiple streamers available. Select one from the settings menu.`;
allowRestart = false;
}
if (allowRestart) {
this.showDisconnectOverlay(message);
} else {
this.showTextOverlay(message);
}
}
}

View File

@ -17,7 +17,7 @@ import {
SettingOption,
Logger,
SettingBase
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { SettingUIFlag } from './SettingUIFlag';
import { SettingUINumber } from './SettingUINumber';
import { SettingUIText } from './SettingUIText';
@ -174,10 +174,6 @@ export class ConfigUI {
psSettingsSection,
this.flagsUi.get(Flags.StartVideoMuted)
);
this.addSettingFlag(
psSettingsSection,
this.flagsUi.get(Flags.PreferSFU)
);
this.addSettingFlag(
psSettingsSection,
this.flagsUi.get(Flags.IsQualityController)
@ -198,6 +194,10 @@ export class ConfigUI {
psSettingsSection,
this.flagsUi.get(Flags.AFKDetection)
);
this.addSettingFlag(
psSettingsSection,
this.flagsUi.get(Flags.WaitForStreamer)
);
this.addSettingNumeric(
psSettingsSection,
this.numericParametersUi.get(NumericParameters.AFKTimeoutSecs)
@ -206,6 +206,10 @@ export class ConfigUI {
psSettingsSection,
this.numericParametersUi.get(NumericParameters.MaxReconnectAttempts)
);
this.addSettingNumeric(
psSettingsSection,
this.numericParametersUi.get(NumericParameters.StreamerAutoJoinInterval)
);
/* Setup all view/ui related settings under this section */
const viewSettingsSection = this.buildSectionWithHeading(

View File

@ -1,6 +1,6 @@
// Copyright Epic Games, Inc. All Rights Reserved.
import { SettingBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { SettingBase } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
/**
* Base class for a setting that has a text label, an arbitrary setting value it stores, an a HTML element that represents this setting.

View File

@ -3,7 +3,7 @@
import type {
FlagsIds,
SettingFlag
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { SettingUIBase } from './SettingUIBase';
export class SettingUIFlag<

View File

@ -3,8 +3,8 @@
import type {
NumericParametersIds,
SettingNumber
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
import { Logger } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { Logger } from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { SettingUIBase } from './SettingUIBase';
/**
@ -77,7 +77,7 @@ export class SettingUINumber<
this.spinner.onchange = (event: Event) => {
const inputElem = event.target as HTMLInputElement;
const parsedValue = Number.parseInt(inputElem.value);
const parsedValue = Number.parseFloat(inputElem.value);
if (Number.isNaN(parsedValue)) {
Logger.Warning(

View File

@ -3,7 +3,7 @@
import type {
OptionParametersIds,
SettingOption
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { SettingUIBase } from './SettingUIBase';
export class SettingUIOption<

View File

@ -3,7 +3,7 @@
import type {
SettingText,
TextParametersIds
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.2';
} from '@epicgames-ps/lib-pixelstreamingfrontend-ue5.4';
import { SettingUIBase } from './SettingUIBase';
export class SettingUIText<

Some files were not shown because too many files have changed in this diff Show More