Compare commits

...

132 Commits

Author SHA1 Message Date
RoxanneCor d4e8dc834f
Merge pull request #1037 from Unity-Technologies/remove-emojione
Remove EmojiOne assets
2025-10-23 15:35:07 -04:00
sourcegraph-commit-signing-unity[bot] 130daa99a0
Remove EmojiOne assets 2025-10-23 19:27:47 +00:00
sindharta-tanuwijaya 001942b055
release: 3.1.0-exp.9 (#1025)
* update package.json
* update changelog
2024-12-17 12:11:35 +09:00
sindharta-tanuwijaya 09e1ec4aeb
revert: "chore: remove CI tests against Unity 2020 (#1014)" (#1027)
This reverts commit 09bc00b76b.
2024-12-16 15:18:17 +09:00
sindharta-tanuwijaya 01b9c19b81
deps: use com.unity.webrtc@3.0.0-pre.8 (#1026) 2024-12-13 23:08:53 +09:00
Toru Nayuki e144df7c70
Merge pull request #1021 from Unity-Technologies/dqw2024-audiostreamreceiver
doc: improve the API documentation of AudioStreamReceiver
2024-12-07 11:51:06 +09:00
Toru Nayuki 80b891393a
Merge pull request #1024 from Unity-Technologies/dqw2024-signalingmanager
doc: improve the API documentation of SignalingManager
2024-12-07 10:10:12 +09:00
Toru Nayuki 03dbf2e2d4
Merge pull request #1022 from Unity-Technologies/dqw2024-inputsender
doc: improve the API documentation of InputSender
2024-12-06 21:51:13 +09:00
Toru Nayuki e22b1ffcb0
Merge pull request #1020 from Unity-Technologies/dqw2024-audiostreamsender
doc: improve the API documentation of AudioStreamSender
2024-12-06 21:48:06 +09:00
Toru Nayuki 05ef07db93
Merge pull request #1016 from Unity-Technologies/dqw2024-videostreamsender
doc: improve the API documentation of VideoStreamSender
2024-12-06 19:44:48 +09:00
Toru Nayuki 5ba8d712f9 doc: add see also 2024-12-06 19:13:58 +09:00
Toru Nayuki 866a74e333 doc: add see also 2024-12-06 19:11:56 +09:00
Toru Nayuki 7b4c9ebba3 doc: add see also 2024-12-06 19:10:01 +09:00
Toru Nayuki f96a0fee44
Merge pull request #1023 from Unity-Technologies/dqw2024-inputreceiver
doc: improve the API documentation of InputReceiver
2024-12-06 19:07:18 +09:00
Toru Nayuki 2e239ad871 doc: improve the API documentation of SignalingManager 2024-12-06 18:30:21 +09:00
Toru Nayuki d7a81ac4a4
Update com.unity.renderstreaming/Runtime/Scripts/VideoStreamSender.cs
Co-authored-by: chrstphrsxtn <74899224+chrstphrsxtn@users.noreply.github.com>
2024-12-06 17:51:07 +09:00
Toru Nayuki 0a4a409553
Update com.unity.renderstreaming/Runtime/Scripts/VideoStreamSender.cs
Co-authored-by: chrstphrsxtn <74899224+chrstphrsxtn@users.noreply.github.com>
2024-12-06 17:50:53 +09:00
Toru Nayuki 4f1aaabadf
Update com.unity.renderstreaming/Runtime/Scripts/VideoStreamSender.cs
Co-authored-by: chrstphrsxtn <74899224+chrstphrsxtn@users.noreply.github.com>
2024-12-06 17:50:46 +09:00
Toru Nayuki e9a2e59fe3
Merge pull request #1019 from Unity-Technologies/dqw2024-videostreamreceiver
doc: improve the API documentation of VideoStreamReceiver
2024-12-06 17:31:00 +09:00
Toru Nayuki 5d28e64cd4
Merge pull request #1018 from Unity-Technologies/dqw2024-audiocodecinfo
doc: improve the API documentation of AudioCodecInfo
2024-12-06 17:30:37 +09:00
Toru Nayuki c9a9a180d0
Merge pull request #1017 from Unity-Technologies/dqw2024-videocodecinfo
doc: improve the API documentation of VideoCodecInfo
2024-12-06 17:30:13 +09:00
Toru Nayuki 632583462d doc: improve the API documentation of InputReceiver 2024-12-06 13:29:15 +09:00
sindharta-tanuwijaya 09bc00b76b
chore: remove CI tests against Unity 2020 (#1014) 2024-12-06 11:02:43 +09:00
Toru Nayuki 01ce850c1b doc: improve the API documentation of InputSender 2024-12-05 18:44:09 +09:00
Toru Nayuki 4aaafed025 doc: improve the API documentation of AudioStreamReceiver 2024-12-05 17:26:18 +09:00
Toru Nayuki b554210266 doc: improve the API documentation of AudioStreamSender 2024-12-05 16:50:10 +09:00
Toru Nayuki 844d634cf2 doc: improve the API documentation of VideoStreamReceiver 2024-12-03 17:04:53 +09:00
Toru Nayuki 16ae1feb54 doc: improve the API documentation of VideoStreamSender 2024-12-03 16:07:26 +09:00
Toru Nayuki aee157eed6 doc: improve the API documentation of AudioCodecInfo 2024-12-03 14:40:44 +09:00
Toru Nayuki ca1643f2ec doc: improve the API documentation of VideoCodecInfo 2024-12-03 14:13:31 +09:00
Kazuki Matsumoto 37d49b5266
fix: Remove polyfill (#999) 2024-07-26 10:30:01 +09:00
Brian Harrison 5f331f414b
fix: Fix disconnecting on first time PeerConnection state changes to disconnected, and instead rely on failed. (#976) 2024-01-29 16:56:40 +09:00
Brian Harrison 2b353b579e
fix: fix command line arguments incorrectly replacing ice-candidates with null values leading to a crash (#975) 2024-01-29 15:25:23 +09:00
Kazuki Matsumoto 88af8ff46f
chore: Upgrade bokken image for windows (#977) 2024-01-29 11:21:47 +09:00
dependabot[bot] d1b75694e7
chore: bump tough-cookie and newman in /WebApp (#957)
Removes [tough-cookie](https://github.com/salesforce/tough-cookie). It's no longer used after updating ancestor dependency [newman](https://github.com/postmanlabs/newman). These dependencies need to be updated together.


Removes `tough-cookie`

Updates `newman` from 5.3.2 to 6.0.0
- [Changelog](https://github.com/postmanlabs/newman/blob/develop/CHANGELOG.yaml)
- [Commits](https://github.com/postmanlabs/newman/compare/v5.3.2...v6.0.0)

---
updated-dependencies:
- dependency-name: tough-cookie
  dependency-type: indirect
- dependency-name: newman
  dependency-type: direct:development
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-11-21 09:49:38 +09:00
dependabot[bot] ac89655e3d
chore: bump @babel/traverse from 7.18.2 to 7.23.2 in /WebApp (#954)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.18.2 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-11-21 09:49:20 +09:00
Kazuki Matsumoto c3a29d1d91
fix: Upgrade WebRTC package 3.0.0-pre.7 (#953)
* fix

* fix

* Upgrade package version

* fix

* add post process to build iOS runtime

* fix

* postprocess for ios

* fix
2023-11-21 09:48:51 +09:00
dependabot[bot] 985a0c04d2
chore: bump @babel/traverse from 7.19.0 to 7.23.2 in /WebApp/client (#955)
Bumps [@babel/traverse](https://github.com/babel/babel/tree/HEAD/packages/babel-traverse) from 7.19.0 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-11-01 17:08:24 +09:00
Kazuki Matsumoto 9200063d64
fix: Fix inputfield when using textmeshpro (#945)
* fix inputfield when using textmeshpro

* Update EmulateInputFieldEvent.cs
2023-08-28 10:18:59 +09:00
Kazuki Matsumoto d6e6249765
fix: Add tooltips for Render Streaming Settings in Project Settings Window (#937) 2023-08-04 15:37:16 +09:00
Kazuki Matsumoto 6538f64b7d
fix: Fix NullReferenceException when disabling a flag on SignalingManager inspector (#935)
* fix

* fix
2023-08-03 19:42:22 +09:00
Kazuki Matsumoto 8289073020
fix: Ice servers settings doesn't affecte when runOnAwake is enabled (#934) 2023-08-03 11:39:48 +09:00
Takashi Kannan 0e46feeced
fix: Re-save Bidirectional sample scene in 2020.3 (#933) 2023-08-02 15:29:00 +09:00
Kazuki Matsumoto 4af125703d
test: Change test Unity version 2022.2 to 2022.3 (#932)
* update 2022.2 to 2022.3

* add test

* add test

* fix

* format
2023-08-01 12:34:12 +09:00
Dong 8feaeaae38
fix: Fix WebApp devDependencies conflict issue (#931) 2023-07-31 10:35:27 +09:00
Brian Harrison e24eb78092
fix: DataChannel closing all connections (#925)
* fix: Fix closing all data channels when one client disconnects

* fix: Fix an exception from processing input after removing data channel.

* test: Add test for DataChannel disconnecting with multiple connections.
2023-07-26 12:20:57 +09:00
Kazuki Matsumoto 46a045c485
doc: Update change log for 3.1.0-exp.6 (#928) 2023-07-26 12:19:06 +09:00
Takashi Kannan d65cd0b95e
doc: Add doc audio loopback (#927) 2023-07-25 15:28:43 +09:00
Kazuki Matsumoto 80892ce7d0
fix: Remove Furioos integration (#926) 2023-07-25 14:03:09 +09:00
Kazuki Matsumoto cef8d001ad
fix: Fix thte issue that ICE server configuration are not changed (#923)
* Fix script error

* Add ICE settings Web UI

* fix default settings

* fix

* format
2023-07-25 09:24:17 +09:00
Takashi Kannan 008b81dc70
fix: Error on http signaling using short interval (#919)
* add timestamp on getall response

* use timestamp

* remove unused code

* fix newman test

* update package lock

* use same datetime and include sametime by fromtime

* permit change interval on signaling class

* fix test

* fix
2023-07-24 17:21:59 +09:00
Kazuki Matsumoto 65a7747d33
refactor: Refactor editor script (#922)
* recactor

* refactor
2023-07-24 09:35:39 +09:00
Kazuki Matsumoto e592a60a44
fix: Add workaround to fix InputField that not receiving input event (#920)
* workaround: InputField

* fix

* fix test

* fix

* format

* fix
2023-07-24 09:35:15 +09:00
codec-abc e5f1430219
fix: Recompute video player position each time (#915)
* Recompute video player position each time

* fix testcase

---------

Co-authored-by: kazuki <karasusan@gmail.com>
2023-07-19 18:34:38 +09:00
dependabot[bot] ba102703fd
chore: bump word-wrap from 1.2.3 to 1.2.4 in /WebApp/client (#917)
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-19 16:14:13 +09:00
Kazuki Matsumoto 616f04efd3
refactor: Install managed code formatter (#913)
* code format

* format

* fix
2023-07-19 15:57:29 +09:00
Brian Harrison e9d5c694b2
feat: Add configurable logger (#910) 2023-07-19 13:52:03 +09:00
Takashi Kannan 3820af30c8
feat: Add loopback flag on audio stream sender (#916)
* add loopback flag on audio stream sender

* add test

* add component property
2023-07-19 10:26:07 +09:00
Kazuki Matsumoto d6b0abc2f9
chore: Update package version 3.1.0-exp.7 (#911)
* Update package version

* fix changelog
2023-07-13 15:58:10 +09:00
dependabot[bot] ac9c780d34
chore: bump tough-cookie from 4.1.2 to 4.1.3 in /WebApp/client (#908)
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-12 17:47:51 +09:00
Kazuki Matsumoto 87f560a7fb
fix: Update package dependencies (#896) 2023-05-16 14:33:23 +09:00
Brian Harrison 6522cfcee0
fix: Fix timed out sessions collecting in signaling server (#893)
* fix: Fix timed out sessions collecting in signaling server

* chore: Fix irregular whitespace

* test: Add test for stopping signaling and checking for timed out sessions

* chore: fix build error

* test: Fix breaks due to changing mock signaling

* test: Fix test failiure
2023-04-20 13:09:35 +09:00
Takashi Kannan 1712bca887
fix: Stream AudioStreamTrack APIOnly (#892)
* fix audio stream source return track

* fix
2023-04-05 16:40:43 +09:00
acarrere184 8d621e6274
feat: Adding CORS support to streaming server (#890) 2023-03-08 17:00:48 +09:00
Kazuki Matsumoto cdf3a00253
chore: Change the CI image for testing iOS mobile device (#889)
(cherry picked from commit 961c9f2a058bf2f5e16a78bb058d3609c788f486)
2023-02-24 10:06:24 +09:00
Kazuki Matsumoto 5b155ccc68
chore: Upgrade macos image for CI pipeline (#888) 2023-02-22 18:31:23 +09:00
Takashi Kannan 08123b386a
fix: Add warning about conflict signaling URL (#887)
* add warning about conflict signaling settings

* Revert "add warning about conflict signaling settings"

This reverts commit 6fbbc71d35.

* add warning when same url signaling instance
2023-02-21 22:20:58 +09:00
Kazuki Matsumoto b16408251a
fix: Fix SetTextureSize when using VideoSourceType.Texture (#885)
* fix SetTextureSize when using VideoSourceType.Texture

* fix

* fix

* fix
2023-02-21 19:07:13 +09:00
Kazuki Matsumoto 0bebc23cf0
fix: Fix issue when using AudioSourceType.Microphone (#883) 2023-02-20 17:02:08 +09:00
Takashi Kannan 709176bb38
fix: Create input settings from wizard (#880)
* create input settings from wizard

* add depend tester

* fix typo
2023-02-17 17:39:19 +09:00
Kazuki Matsumoto baad23fabd
fix: Fix webserver help command (#878) 2023-02-16 10:07:35 +09:00
Takashi Kannan 59880141f2
Fix: fix the version of Serialized Reference Object by URP/HDRP scene (#877)
* fix reference object version

* change settings
2023-02-15 15:59:35 +09:00
Kazuki Matsumoto dec9148ab3
fix: Fix commandline argument parser (#875)
* fix commandline argument parser

(cherry picked from commit 0f4db549d72050cdf8a32dfb295d78875c0e92c9)

* fix test
2023-02-15 14:04:01 +09:00
Kazuki Matsumoto 8412c11e7d
doc: Fix typo (#876) 2023-02-15 11:47:33 +09:00
Takashi Kannan da7de69803
Fix: fix get URL about Web App source code (#872) 2023-02-14 19:01:42 +09:00
Kazuki Matsumoto 85eeae6762
fix: Fix RenderPipeline sample scene (#874) 2023-02-14 19:01:20 +09:00
Kazuki Matsumoto 043835d4af
fix: Add Unity 2022.2 support (#873)
* Unity 2022.2 support

* fix documents
2023-02-14 17:01:26 +09:00
Takashi Kannan 1817738725
fix: Fix update input settings by wizard (#870)
* fix update input settings by wizard

* use set dirty on change
2023-02-14 09:47:33 +09:00
Kazuki Matsumoto 555026b987
fix: Fix primary touch position on iPa (#867) 2023-02-13 10:24:44 +09:00
Kazuki Matsumoto 3dbcc541ab
doc: Update package documents for 3.1.0-exp.6 (#866)
* create docs

* revert

* revert

* fix

* fix

* fix

* fix

* fix

* fix

* fix changelog

* fix list number

* fix

* Apply suggestions from code review

Co-authored-by: Takashi Kannan <26959415+kannan-xiao4@users.noreply.github.com>

* fix

* fix

* revert

* fix

---------

Co-authored-by: Takashi Kannan <26959415+kannan-xiao4@users.noreply.github.com>
2023-02-10 19:17:40 +09:00
Takashi Kannan 8d1277e3b1
feat: Notify dialog on import sample. (#860)
* add settings for sample

* add popup prefab

* add popup each sample scene

* add automatic streaming toggle on menu

* remove popup on runtime

* add setup dialog

* sample setup

* delete settings when delete samplesetup.cs

* add set editor class

* change settings  from sample dialog

* fix review
2023-02-10 15:26:06 +09:00
Takashi Kannan b584a4cc6c
test: Fix test of SignalingManager run synchronously (#861) 2023-02-09 16:35:37 +09:00
Kazuki Matsumoto a920648bcc
fix: Fix the list of SignalingHandlerBase in SignalingManager is not applied (#863) 2023-02-09 11:07:25 +09:00
Kazuki Matsumoto f996875333
refactor: Move asset file under test folder (#862) 2023-02-09 10:18:42 +09:00
dependabot[bot] 4aeb53a4d7
chore: bump @sideway/formula from 3.0.0 to 3.0.1 in /WebApp/client (#864)
Bumps [@sideway/formula](https://github.com/sideway/formula) from 3.0.0 to 3.0.1.
- [Release notes](https://github.com/sideway/formula/releases)
- [Commits](https://github.com/sideway/formula/compare/v3.0.0...v3.0.1)

---
updated-dependencies:
- dependency-name: "@sideway/formula"
  dependency-type: indirect
...

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-02-09 10:18:17 +09:00
Kazuki Matsumoto dfe82dee43
feat: Add command line option for stanadlone app (#851)
* commandline arguments support

* fix

* fix bug

* refactor

* test

* fix
2023-02-08 13:00:46 +09:00
Kazuki Matsumoto cfd7b7252b
fix: Fix namespace of editor scripts (#858) 2023-02-08 12:38:15 +09:00
Takashi Kannan cf76f13df2
feat: Render Streaming Wizard (#857)
* create render streaming wizard

* wip

* fix review

* increment counter

* fix

* rename folder

* add icon

* fix

* fix

* update ui

* add wizard open behavior

* update project settings

* check package version

* add download behavior

* add webapp group

* create toggle from script

* remove renderstreaming menu item

* delete unused

* migrate uss

* fix

* update error message

* fix

* add buildtarget and graphics api check

* add current settings

* fix uss style name

* fix android sdk validation

* fix

* add server build check

* fix graphics api settings correcter
2023-02-07 17:22:14 +09:00
Kazuki Matsumoto 48ab2b6eb2
feat: Define SignalingSettings asset to make portable signaling configurations (#854)
* Fix SignalingManager inspector

* fix bugs

* fix

* fix

* fix

* fix

* fix
2023-02-03 18:05:04 +09:00
Takashi Kannan 973f8acba5
feat: Create Render Streaming Project Window (#855)
* create renderstreamingsettingseditor

* use drawer on project settings

* formatted

* change to popup for settings select ui

* if can't get settings from config, set default settings

* check update settings view

* fix test

* open SaveFilePanel on create settings

* rename

* fix test

* show path on settings select

* fix

* use utf8 slash

* fix review

---------

Co-authored-by: kazuki <karasusan@gmail.com>
2023-02-02 14:16:10 +09:00
Kazuki Matsumoto 7aa362a028
refactor: Devide files for classes what inherits SignalingSettings class (#853)
* Refactor SignalingSettings

* revert

* remove file

* revert
2023-01-31 17:33:47 +09:00
Kazuki Matsumoto ee88e26987
refactor: Rename RenderStreamingHandler class (#852) 2023-01-30 15:55:58 +09:00
Takashi Kannan d0c74e3e32
feat: Load Render Streaming settings (#849)
* render streaming setting sregister preload asset

* add default streaming settings asset

* load default settings

* change running flag

* add object field ui

* fix

* when change settings add config object

* fix settings asset

* add public settings property

* fix review

* add setting load test

* fix test

* fix create automatic streaming object

* fix rebase

* fix rebase

* add default

* recreate settings on unity 2020

* fix test build setup

* fix test seup

* workaround audio replace track
2023-01-30 14:50:22 +09:00
Takashi Kannan 9ab26c4b9c
feat: Custom signaling settings editor (#847)
* custom signaling settings editor

* ISignalingSettingEditor

* add test

* wip

* wip

* fix

* fix

* refactor

* fix

* wip

* fix

* fix

* fix

* fix

Co-authored-by: kazuki <karasusan@gmail.com>
2023-01-27 15:55:52 +09:00
Kazuki Matsumoto 8a70507a73
feat: Define IceServer class to control signaling settings with APIs (#848)
* fix

(cherry picked from commit 72834442a85fd3952bf2751cd1a47dd1dabd017d)

* fix

* fix

* fix

* fix

* workaround

* workaround

* workaround
2023-01-26 14:16:22 +09:00
Takashi Kannan 623c7cb61b
feat: Implement Automatic Streaming component (#844)
* rename renderstreaming handler

* create skeleton about renderstreaming settings class

* add websocket signaling settings class

* signaling handler can add/remove at runtime

* implement automatic streaming

* run on initialize automatic

* avoid exception

* set false for not run automatic streaming

* rename

* add test

* fix test

* dont provide renderstreaming setting overwrite method

* add handler test

* fix review

* replace propety signaling settings

* [skip ci] comment

* fix signaling interval propety

* revert comment out

* fix render streaming handler editor
2023-01-24 17:28:11 +09:00
Kazuki Matsumoto 32b881b96a
fix: Remove method calling Unity API to avoid UnityException (#846) 2023-01-24 10:02:43 +09:00
Kazuki Matsumoto 90c705f9cd
chore: Upgrade package version 3.1.0-exp.6 (#845) 2023-01-24 10:02:22 +09:00
Kazuki Matsumoto 838fe095a1
fix: Add AudioStreamSender.SetData method to set any audio buffer (#840) 2023-01-23 14:33:43 +09:00
Kazuki Matsumoto f8b2222cd6
refactor: Rename class to RenderStreamingHandlerTest (#843)
* rename

* add class
2023-01-20 16:00:29 +09:00
Takashi Kannan f06b37a91c
feat: Create skeleton about Render Streaming Settings class (#842)
* rename renderstreaming handler

* create skeleton about renderstreaming settings class

* fix review
2023-01-20 14:18:05 +09:00
Kazuki Matsumoto ba9c3ddc86
fix: Make available to change properties of VideoStreamsender and AudioStreamSender while streaming (#839)
* wip

* fix

* wip

* Add VideoStreamSource dropdown in Broadcast sample

* fix scene

* fix

* wip

(cherry picked from commit 83b800497ee5050540cb575c153c07d1a61363f9)

* fix

* fix

* workaround
2023-01-19 17:57:34 +09:00
Kazuki Matsumoto d1fbce348a fix: websocket is in default as a signaling protocol (#836)
* set websocket default

* fix

* fix

* fix

* fix

Co-authored-by: Takashi KANNAN <takashi.kannan@unity3d.com>
2023-01-19 10:32:59 +09:00
Kazuki Matsumoto 06f100928d
chore: Update WebRTC package version 3.0.0-pre.4 (#837)
* fix docs

* fix for tutorial

(cherry picked from commit 727cc6956fb1ab1ea10d950cc3a3c5da7817772a)

* upgrade WebRTC package version 3.0.0-pre.4

* update unity project

* workaround

* workaround

* workaround

* workaround

* fix

* workaround
2023-01-18 18:27:21 +09:00
Kazuki Matsumoto 7ef33dc19f
doc: Remove unused document (#835)
* [skipci] ci: fix condition of auto trigger

* fix

* [skipci] fix

* remove tutorial doc

* fix

* fix
2023-01-12 09:31:09 +09:00
Kazuki Matsumoto 579f88d4e7
fix: Add autocomplete attribute into input elements to avoid issue of "disabled" attribute on Firefox (#834)
* wip

(cherry picked from commit f73792b9c689bac448c1a85ce4db2b21ccdf5187)

* set autocomplete attribute for firefox

* add null check

* fix
2023-01-12 09:30:48 +09:00
Kazuki Matsumoto d0930e3880
fix: Fix TypeError in Bidirectional sample on Firefox (#832)
* Fix TypeError in Bidirectional sample on Firefox 108

* fix

* fix

* fix
2023-01-10 18:31:15 +09:00
Kazuki Matsumoto 22a662dee7
fix NullReferenceException in InputRemoting (#831) 2023-01-10 18:31:00 +09:00
dependabot[bot] 7c29abb4f5
chore: bump json5 from 2.2.1 to 2.2.3 in /WebApp/client (#828)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 15:17:42 +09:00
Kazuki Matsumoto 6e046135ec
fix: Avoid assertion from Input System package when using Android device (#827)
* workaround: avoid assertion `Could not find active control after binding resolution.` in InputActionState class.

(cherry picked from commit 89c50f8f05076928ebb45976dd0e83d55847a624)

* fix

* revert

* wip

* fix

* fix issue
2023-01-10 10:57:33 +09:00
dependabot[bot] d874de464f
chore: bump json5 from 2.2.1 to 2.2.3 in /WebApp (#829)
Bumps [json5](https://github.com/json5/json5) from 2.2.1 to 2.2.3.
- [Release notes](https://github.com/json5/json5/releases)
- [Changelog](https://github.com/json5/json5/blob/main/CHANGELOG.md)
- [Commits](https://github.com/json5/json5/compare/v2.2.1...v2.2.3)

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

Signed-off-by: dependabot[bot] <support@github.com>

Signed-off-by: dependabot[bot] <support@github.com>
Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com>
2023-01-10 10:51:53 +09:00
Kazuki Matsumoto b6fb8dfeb3
fix: Add timeout for waiting RTCRtpReceiver.GetStats coroutine (#825) 2023-01-10 10:15:42 +09:00
Takashi Kannan b2d600be62
fix: Migrate renderpipeline and broadcast sample scripts (#826)
* migrate renderpipeline sample scripts

* chagne light intensity for hdrp

Co-authored-by: kazuki <karasusan@gmail.com>
2023-01-06 17:17:56 +09:00
Kazuki Matsumoto 33cec295fd
fix: Fix exceptions in Broadcast sample scene (#822)
* fix exceptions

* fix

* fix bugs
2023-01-06 10:03:43 +09:00
Cova8bitdots 2a0b9de442
fix: Fix AFoundationSample when disable script (#821) 2022-12-23 14:57:48 +09:00
Kazuki Matsumoto af278a497e
fix: Fix option title of av1 video codec on inspector window (#820) 2022-12-22 18:05:07 +09:00
Brian Harrison c62166cd3e
fix: Fix sessions lingering after they were timed out (#819)
For checkSessionId, there was a bug where it wasn't using the map syntax for setting the value.
Due to this, _checkDeletedSession wouldn't check if sessions were timedout.

In addition, posting offers after a connection was established would replace the connectionPair.
When the connectionPair is replaced, the code that checks for deleted sessions would no longer be checking the timedout session.
Resending offers occur if a PeerConnection goes into the disconnected state.
2022-12-22 10:04:45 +09:00
Kazuki Matsumoto af7df8044a
chore: Fix package description (#818) 2022-12-19 11:23:00 +09:00
Kazuki Matsumoto 2dd1d8bcb5
ci: Add CI jobs which is package isolation test for detecting issues (#806)
* Enable testing in true isolation

We are experiencing a hang in our repo where we are building API Validation assemblies in which we take your latest promoted package `com.unity.renderstreaming@3.1.0-exp.4` (not happening with `3.1.0-exp.3`). The script imports the package with the Windows Unity Editor for the version you have specified in the `unity` field of your package (i.e. `2020.3`).

We think it's because the use of `SynchronizationContext` are not properly cleaned up after and Unity still waits for them. Unfortunately this doesn't reproduce when we run the same commands on the command line but this PR should, in theory, reproduce the same hang on your repo as well.

Enabling testing in true isolation is considered a good practice since this way you should be able to spot also missing dependencies since we are loading the package in a empty project and it should compile without errors.

We were also wondering the reason you added that huge --timeout arg to utr if it's related to this issue but we were unable to find any job that exceeded reasonable timings.

* add job for testing on Windows without GPU

* hopefully this will reproduce the issue

(cherry picked from commit 2583fbf5f484f734eb316c8758dbd38c96233ffd)

* add job

* fix

* add dependencies

* fix

* fix

* fix

* fix bug

* fix

* fix issues

* update dependency

Co-authored-by: Mihai Popescu <57262907+mihai-unity@users.noreply.github.com>
2022-12-16 17:21:29 +09:00
Kazuki Matsumoto e1444d478a
ci: Refactor script for CI jobs (#817)
* refactor

(cherry picked from commit b3229b12d883c708bdea1c639630245ca1f29495)

* fix

* fix

* wip

* fix

* fix

* fix

* revert

* change coverage package version
2022-12-16 10:20:53 +09:00
Kazuki Matsumoto c64b1b07bc
doc: Fix documents for 3.1.0-exp.5 (#816) 2022-12-15 10:44:36 +09:00
Kazuki Matsumoto c9955ddb48
chore: Update WebRTC package 3.0.0-pre.2 (#814)
* Remove DomainLOad and DomainUnload

* update dependencies

* fix bug

* fix test error

* changed pull request branch to main
2022-12-13 09:20:18 +09:00
Kazuki Matsumoto 0410dff10a
chore: Upgrade package version 3.1.0-exp.5 (#815) 2022-12-13 09:16:13 +09:00
Brian Harrison 9de88a5dda
fix: Fix offers being resent indeffinitely when PeerConnection is in failed state (#810)
* fix: Fix offers being resent indeffinitely when PeerConnection is in the failed state

* fix: Remove PeerConnections that are failed even if they aren't currently waiting for an Answer

* test: Add test for deleting failed PeerConnections

* test: fix test to allow for running in both public & private mode
2022-12-01 09:31:57 +09:00
Kazuki Matsumoto 53ff13db46
fix: Recalculate input region to correct pointer position from mouse/touchscreen (#800) 2022-11-01 17:33:38 +09:00
Kazuki Matsumoto afeac3f58d
test: Add test cases to increase test coverage for public APIs (#798)
* wip

* move WebBrowserInputChannelReceiver

* add test for InputSender and InputReceiver

* move namespace

* wip

* fix

* fix test

* wip

* addtests

* revert

* fix test error

* ignore test
2022-11-01 10:56:26 +09:00
Kazuki Matsumoto 05d2edd5cd
fix: Fixed missing files to make the packing process for webapp (#801) 2022-11-01 10:53:57 +09:00
Kazuki Matsumoto 1165e0f743
chore: Exclude tests for Unity 2022.1 on Android device (#793)
* exclude test

* fix

* fix
2022-10-07 17:10:11 +09:00
Kazuki Matsumoto 2080d509b7
chore: Changed CI image for testing with Android device (#792) 2022-10-07 15:06:22 +09:00
Kazuki Matsumoto 5c88b8c51f
fix: Fix build IL2CPP error Unity2021.3 on all platforms (#791) 2022-10-07 10:07:13 +09:00
Kazuki Matsumoto 5f2f36c79f
fix: Fix build IL2CPP error Unity2021.3 on macOS (#790) 2022-10-06 16:49:25 +09:00
Kazuki Matsumoto c139b86d26
doc: Update CHANGELOG (#789) 2022-10-06 07:45:56 +09:00
328 changed files with 22445 additions and 12950 deletions

View File

@ -27,6 +27,10 @@ body:
What version of the package are you using?
You can check the Unity version in Package Manager Window. See [manual](https://docs.unity3d.com/Manual/upm-ui.html).
options:
- 3.1.0-exp.8
- 3.1.0-exp.7
- 3.1.0-exp.6
- 3.1.0-exp.5
- 3.1.0-exp.4
- 3.1.0-exp.3
- 3.1.0-exp.2

View File

@ -0,0 +1,49 @@
compile_test_for_package_version:
name: Compilation Test for Package Version
agent:
type: Unity::VM
flavor: b1.large
image: package-ci/win10:v4
variables:
VERSION: 3.1.0-exp.7
commands:
# When unity-config will be part of the image, this will turn into a no-op
- |
where /q unity-config
if ERRORLEVEL 1 (
%GSUDO% choco install unity-config -y -s https://artifactory.prd.it.unity3d.com/artifactory/api/nuget/unity-choco-local
)
- unity-downloader-cli -c editor -u 2020.3 --wait
- .Editor\Unity.exe -createProject CompilationTestProject -logFile logs\CreateProject.log -batchmode -quit
- |
unity-config project set registry --project-path CompilationTestProject candidates
unity-config project add dependency --project-path CompilationTestProject com.unity.renderstreaming@%VERSION%
- .Editor\Unity.exe -projectPath CompilationTestProject -logFile logs\CompilePackage.log -batchmode -quit
artifacts:
logs:
paths:
- logs/*
compile_test_for_local_path:
name: Compilation Test for Local Path
agent:
type: Unity::VM
flavor: b1.large
image: package-ci/win10:v4
commands:
# When unity-config will be part of the image, this will turn into a no-op
- |
where /q unity-config
if ERRORLEVEL 1 (
%GSUDO% choco install unity-config -y -s https://artifactory.prd.it.unity3d.com/artifactory/api/nuget/unity-choco-local
)
- unity-downloader-cli -c editor -u 2020.3 --wait
- .Editor\Unity.exe -createProject CompilationTestProject -logFile logs\CreateProject.log -batchmode -quit
- |
unity-config project set registry --project-path CompilationTestProject candidates
unity-config project add dependency --project-path CompilationTestProject .\com.unity.renderstreaming
- .Editor\Unity.exe -projectPath CompilationTestProject -logFile logs\CompilePackage.log -batchmode -quit
artifacts:
logs:
paths:
- logs/*

38
.yamato/coverage.yml Normal file
View File

@ -0,0 +1,38 @@
{% metadata_file .yamato/package.metafile %}
# todo(kazuki): Use old version because Code Coverage 1.2.2 has some issues.
coverage_pkg_version: 1.1.1
---
{% for platform in platforms %}
{% if platform.name != "macos" and platform.name != "macos-m1" %}
{% for editor in editors %}
codecoverage_{{ packagename }}_{{ platform.name }}_{{ editor.version }}:
name: Code coverage {{ package_displayname }} {{ platform.name }} {{ editor.version }}
agent:
type: {{ platform.type }}
image: {{ platform.image }}
flavor: {{ platform.flavor }}
commands:
- pip config set global.index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
{% if platform.name == "win" %}
- |
set WEBAPP_PATH=%cd%\Webapp\bin~\{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --extra-utr-arg=--coverage-pkg-version={{ coverage_pkg_version }} --package-path {{ packagename }} --enable-code-coverage --code-coverage-options "generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:-UnityEngine.*,+Unity.RenderStreaming"
{% else %}
- |
export WEBAPP_PATH=$(pwd)/WebApp/bin~/{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --extra-utr-arg=--coverage-pkg-version={{ coverage_pkg_version }} --package-path {{ packagename }} --enable-code-coverage --code-coverage-options "generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:-UnityEngine.*,+Unity.RenderStreaming"
{% endif %}
artifacts:
{{ packagename }}_{{ editor.version }}_{{ platform.name }}_coverage_results:
paths:
- "upm-ci~/test-results/**"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% endfor %}
{% endif %}
{% endfor %}

15
.yamato/format.yml Normal file
View File

@ -0,0 +1,15 @@
# Check formatting using dotnet-format tool.
check_formatting_dotnet-format:
name: Checking codes formatting using dotnet-format tool
agent:
type: Unity::VM::osx
image: package-ci/macos-12:v4
flavor: b1.large
commands:
- dotnet tool install --tool-path tools dotnet-format || echo dotnet format already installed
- tools/dotnet-format --check --exclude RenderStreaming~ -f . 1>formatting.log 2>formatting_errors.log
artifacts:
logs:
paths:
- formatting.log
- formatting_errors.log

View File

@ -2,13 +2,16 @@ upm:
registry_url: https://artifactory.prd.cds.internal.unity3d.com/artifactory/api/npm/upm-npm
package_version: stable
intra_pypi_url: https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
packagename: com.unity.renderstreaming
package_displayname: Render Streaming
editors:
- version: 2020.3
- version: 2021.3
- version: 2022.1
- version: 2022.3
- version: 2023.1
- version: trunk
platforms:
- name: win
- name: win-gpu
type: Unity::VM::GPU
image: renderstreaming/win10:v0.3.13-1084240
flavor: b1.large
@ -27,9 +30,24 @@ platforms:
platform: standalone
- backend: il2cpp
platform: standalone
- name: win
type: Unity::VM
image: renderstreaming/win10:v0.3.13-1084239
flavor: b1.large
packed_webapp_name: webserver.exe
packed_webapp_platform: win
test_params:
- backend: mono
platform: editmode
- backend: mono
platform: playmode
- backend: mono
platform: standalone
- backend: il2cpp
platform: standalone
- name: macos
type: Unity::metal::macmini
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: m1.mac
architecture: x64
packed_webapp_name: webserver_mac
@ -49,7 +67,7 @@ platforms:
platform: standalone
- name: macos-m1
type: Unity::metal::devkit
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: m1.mac
architecture: arm64
packed_webapp_name: webserver_mac
@ -68,7 +86,7 @@ platforms:
# - backend: il2cpp
# additional_component_arg: StandaloneSupport-IL2CPP
# platform: standalone
- name: linux
- name: linux-gpu
type: Unity::VM::GPU
image: renderstreaming/ubuntu:v0.2.4-1104053
flavor: b1.large

View File

@ -1,16 +1,12 @@
{% metadata_file .yamato/meta/environments.yml %}
{% metadata_file .yamato/package.metafile %}
test_platforms:
- name: win
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
packages:
- name: renderstreaming
packagename: com.unity.renderstreaming
---
{% for package in packages %}
{% for editor in editors %}
{% for platform in test_platforms %}
promotion_test_{{ platform.name }}_{{ editor.version }}:
@ -23,13 +19,13 @@ promotion_test_{{ platform.name }}_{{ editor.version }}:
UPMCI_PROMOTION: 1
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- upm-ci package test --unity-version {{ editor.version }} --package-path {{ package.packagename }} --platform editmode --backend mono
- upm-ci package test --unity-version {{ editor.version }} --package-path {{ packagename }} --platform editmode --backend mono
artifacts:
logs:
paths:
- "upm-ci~/test-results/**/*"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
{% endfor %}
{% endfor %}
@ -37,13 +33,13 @@ promote_dry_run:
name: Promote Dry Run to Production
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
variables:
UPMCI_PROMOTION: 1
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- upm-ci package promote --dry-run --package-path {{ package.packagename }}
- upm-ci package promote --dry-run --package-path {{ packagename }}
triggers:
tags:
only:
@ -53,7 +49,7 @@ promote_dry_run:
paths:
- "upm-ci~/packages/*.tgz"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
{% for editor in editors %}
{% if editor.version != "trunk" -%} # exclude trunk to test
{% for platform in test_platforms %}
@ -66,13 +62,13 @@ promote:
name: Promote to Production
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
variables:
UPMCI_PROMOTION: 1
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- upm-ci package promote --package-path {{ package.packagename }}
- upm-ci package promote --package-path {{ packagename }}
triggers:
tags:
only:
@ -82,7 +78,7 @@ promote:
paths:
- "upm-ci~/packages/*.tgz"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
{% for editor in editors %}
{% if editor.version != "trunk" -%} # exclude trunk to test
{% for platform in test_platforms %}
@ -90,5 +86,3 @@ promote:
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

View File

@ -1,5 +1,4 @@
# .yamato/upm-ci-publish-github-release.yml
{% metadata_file .yamato/meta/environments.yml %}
{% metadata_file .yamato/package.metafile %}
webapp-platforms:
- name: win

View File

@ -1,12 +1,9 @@
{% metadata_file .yamato/meta/environments.yml %}
{% metadata_file .yamato/package.metafile %}
packages:
- name: renderstreaming
packagename: com.unity.renderstreaming
---
{% for package in packages %}
pack_{{ package.name }}:
name: Pack {{ package.packagename }}
pack:
name: Pack {{ package_displayname }}
agent:
type: Unity::VM
image: package-ci/ubuntu-20:v1.4.0-1081009
@ -14,18 +11,18 @@ pack_{{ package.name }}:
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- find ./{{ project.packagename }} -type l -exec bash -c 'sh BuildScripts~/convert_symlinks.sh "$0"' {} \;
- upm-ci package pack --package-path {{ package.packagename }}
- upm-ci package pack --package-path {{ packagename }}
artifacts:
{{ package.name }}_package:
{{ packagename }}_package:
paths:
- "upm-ci~/packages/**/*"
{% for editor in editors %}
build_{{ package.name }}_{{ editor.version }}_ios:
name : Build {{ package.packagename }} with {{ editor.version }} for ios device
build_{{ editor.version }}_ios:
name : Build {{ package_displayname }} with {{ editor.version }} for ios device
agent:
type: Unity::VM::osx
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: b1.large
commands:
- find upm-ci~/packages/ -name "*.tgz" | xargs -I file tar xvf file -C upm-ci~
@ -42,13 +39,14 @@ build_{{ package.name }}_{{ editor.version }}_ios:
paths:
- "build/logs/**"
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
test_{{ package.name }}_{{ editor.version }}_ios:
name: Test {{ package.packagename }} with {{ editor.version }} on ios device
test_{{ packagename }}_{{ editor.version }}_ios:
name: Test {{ package_displayname }} with {{ editor.version }} on ios device
agent:
type: Unity::mobile::iPhone
image: mobile/macos-10.15-testing:v0.0.7-909915
image: package-ci/macos-12:v4.10.0-1271191
model: SE
flavor: b1.medium
skip_checkout: true
commands:
@ -63,22 +61,22 @@ test_{{ package.name }}_{{ editor.version }}_ios:
paths:
- "build/test-results/**"
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#build_{{ package.name }}_{{ editor.version }}_ios
- .yamato/upm-ci-renderstreaming-packages.yml#build_{{ editor.version }}_ios
{% for target in test_targets_android %}
build_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}:
name : Build {{ package.packagename }} with {{ editor.version }} for android device {{ target.name }}
build_{{ editor.version }}_android_{{ target.name }}:
name : Build {{ package_displayname }} with {{ editor.version }} for android device {{ target.name }}
agent:
type: Unity::VM::osx
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: b1.xlarge
commands:
- |
find upm-ci~/packages/ -name "*.tgz" | xargs -I file tar xvf file -C upm-ci~
cp -rf upm-ci~/package/Runtime/Plugins Runtime/
{% if target.name == "vulkan" -%}
{% if target.name == "vulkan" %}
cp -f TestProjects/Empty/ProjectSettings/ProjectSettings-android-vulkan.asset TestProjects/Empty/ProjectSettings/ProjectSettings.asset
{% endif -%}
{% endif %}
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- unity-downloader-cli -c Editor -c Android -u {{ editor.version }} --fast -w
- curl -s https://artifactory.prd.it.unity3d.com/artifactory/unity-tools/utr-standalone/utr --output utr
@ -92,17 +90,17 @@ build_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}:
paths:
- "build/logs/**"
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
test_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}:
name: Test {{ package.packagename }} with {{ editor.version }} on android device {{ target.name }}
test_{{ packagename }}_{{ editor.version }}_android_{{ target.name }}:
name: Test {{ package_displayname }} with {{ editor.version }} on android device {{ target.name }}
agent:
type: Unity::mobile::shield
image: mobile/android-execution-base:v0.0.2-791667
image: mobile/android-package-ci-win:v0.1.4-1212670
flavor: b1.medium
skip_checkout: true
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#build_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#build_{{ editor.version }}_android_{{ target.name }}
commands:
- wget http://artifactory-slo.bf.unity3d.com/artifactory/mobile-generic/android/ADBKeys.zip!/adbkey.pub -O %USERPROFILE%/.android/adbkey.pub
- wget http://artifactory-slo.bf.unity3d.com/artifactory/mobile-generic/android/ADBKeys.zip!/adbkey -O %USERPROFILE%/.android/adbkey
@ -126,8 +124,8 @@ test_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}:
{% for platform in platforms %}
{% if platform.name != "macos" and platform.name != "macos-m1" %}
{% for param in platform.test_params %}
test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package.packagename }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
test_{{ packagename }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package_displayname }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
agent:
type: {{ platform.type }}
image: {{ platform.image }}
@ -139,21 +137,21 @@ test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
- pip config set global.index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
{% if platform.name == "win" %}
{% if platform.name == "win" or platform.name == "win-gpu" %}
- |
set WEBAPP_PATH=%cd%\Webapp\bin~\{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --package-path {{ package.packagename }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--timeout=3000"
upm-ci package test -u {{ editor.version }} --package-path {{ packagename }} --platform {{ param.platform }} --backend {{ param.backend }} --enable-load-and-test-isolation
{% else %}
- |
export WEBAPP_PATH=$(pwd)/WebApp/bin~/{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --package-path {{ package.packagename }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--timeout=3000 --testfilter=!HttpSignaling"
upm-ci package test -u {{ editor.version }} --package-path {{ packagename }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--testfilter=!HttpSignaling" --enable-load-and-test-isolation
{% endif %}
artifacts:
{{ package.name }}_{{ editor.version }}_{{ platform.name }}_test_results:
{{ packagename }}_{{ editor.version }}_{{ platform.name }}_test_results:
paths:
- "upm-ci~/test-results/**/*"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% for project in test_projects %}
@ -170,21 +168,21 @@ test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
- pip config set global.index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
{% if platform.name != "win" %}
- find ./{{ package.packagename }} -type l -exec bash -c 'sh BuildScripts~/convert_symlinks.sh "$0"' {} \;
{% if platform.name != "win" and platform.name != "win-gpu" %}
- find ./{{ packagename }} -type l -exec bash -c 'sh BuildScripts~/convert_symlinks.sh "$0"' {} \;
{% endif %}
- upm-ci project pack --project-path {{ project.path }}
{% if platform.name == "win" %}
{% if platform.name == "win" or platform.name == "win-gpu" %}
- |
set WEBAPP_PATH=%cd%\Webapp\bin~\{{ platform.packed_webapp_name }}
upm-ci project test -u {{ editor.version }} --project-path {{ project.path }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--timeout=3000"
upm-ci project test -u {{ editor.version }} --project-path {{ project.path }} --platform {{ param.platform }} --backend {{ param.backend }}
{% else %}
- |
export WEBAPP_PATH=$(pwd)/WebApp/bin~/{{ platform.packed_webapp_name }}
upm-ci project test -u {{ editor.version }} --project-path {{ project.path }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--timeout=3000 --testfilter=!HttpSignaling"
upm-ci project test -u {{ editor.version }} --project-path {{ project.path }} --platform {{ param.platform }} --backend {{ param.backend }} --extra-utr-arg="--testfilter=!HttpSignaling"
{% endif %}
artifacts:
{{ package.name }}_{{ editor.version }}_{{ platform.name }}_test_results:
{{ packagename }}_{{ editor.version }}_{{ platform.name }}_test_results:
paths:
- "upm-ci~/test-results/**/*"
dependencies:
@ -197,11 +195,11 @@ test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
{% if param.platform == "standalone" %} # platform.name == "macos" or platform.name == "macos-m1" and param.platform == "standalone"
build_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Build {{ package.packagename }} with {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
build_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Build {{ package_displayname }} with {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
agent:
type: Unity::VM::osx
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: m1.mac
commands:
- |
@ -210,7 +208,7 @@ build_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.na
- unity-downloader-cli -c Editor -c {{ param.additional_component_arg }} -u {{ editor.version }} --fast -w
- curl -s https://artifactory.prd.it.unity3d.com/artifactory/unity-tools/utr-standalone/utr --output utr
- chmod +x ./utr
- ./utr --suite=playmode --platform=StandaloneOSX --editor-location=.Editor --testproject=TestProjects/Empty --player-save-path=build/players --architecture=x64 --artifacts_path=build/logs --scripting-backend={{ param.backend }} --build-only --timeout=3000 --testfilter=!HttpSignaling
- ./utr --suite=playmode --platform=StandaloneOSX --editor-location=.Editor --testproject=TestProjects/Empty --player-save-path=build/players --architecture=x64 --artifacts_path=build/logs --scripting-backend={{ param.backend }} --build-only --testfilter=!HttpSignaling
artifacts:
players:
paths:
@ -219,10 +217,10 @@ build_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.na
paths:
- "build/logs/**"
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package.packagename }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
test_{{ packagename }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package_displayname }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
agent:
type: {{ platform.type }}
image: {{ platform.image }}
@ -242,17 +240,17 @@ test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
commands:
- BuildScripts~/test_package_mac.sh
artifacts:
{{ package.name }}_{{ param.backend }}_{{ editor.version }}_{{ platform.name }}_test_results:
{{ packagename }}_{{ param.backend }}_{{ editor.version }}_{{ platform.name }}_test_results:
paths:
- "upm-ci~/test-results/**"
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#build_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#build_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% else %} # platform.name == "macos" or platform.name == "macos-m1" and param.platform != "standalone"
test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package.packagename }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
test_{{ packagename }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ package_displayname }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
agent:
type: {{ platform.type }}
image: {{ platform.image }}
@ -269,16 +267,16 @@ test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
TEST_ARCHITECTURE: {{ platform.architecture }}
SCRIPTING_BACKEND: {{ param.backend }}
EDITOR_VERSION: {{ editor.version }}
EXTRA_UTR_ARG: --timeout=3000 --testfilter=!HttpSignaling
EXTRA_UTR_ARG: --testfilter=!HttpSignaling
commands:
- find upm-ci~/packages/ -name "*.tgz" | xargs -I file tar xvf file -C upm-ci~
- BuildScripts~/test_package_mac.sh
artifacts:
{{ package.name }}_{{ param.backend }}_{{ editor.version }}_{{ platform.name }}_test_results:
{{ packagename }}_{{ param.backend }}_{{ editor.version }}_{{ platform.name }}_test_results:
paths:
- "upm-ci~/test-results/**"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% endif %}
@ -301,33 +299,34 @@ test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
TEST_PLATFORM: {{ param.platform }}
SCRIPTING_BACKEND: {{ param.backend }}
EDITOR_VERSION: {{ editor.version }}
EXTRA_UTR_ARG: --timeout=3000 --testfilter=!HttpSignaling
EXTRA_UTR_ARG: --testfilter=!HttpSignaling
commands:
- find ./{{ package.packagename }} -type l -exec bash -c 'sh BuildScripts~/convert_symlinks.sh "$0"' {} \;
- find ./{{ packagename }} -type l -exec bash -c 'sh BuildScripts~/convert_symlinks.sh "$0"' {} \;
- BuildScripts~/test_package_mac.sh
artifacts:
{{ package.name }}_{{ editor.version }}_{{ platform.name }}_test_results:
{{ packagename }}_{{ editor.version }}_{{ platform.name }}_test_results:
paths:
- "upm-ci~/test-results/**"
dependencies:
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% endfor %}
{% endfor %}
{% endif -%}
{% endif %}
{% endfor %}
trigger_test_{{ package.name }}_{{ editor.version }}:
name : Trigger test {{ package.packagename }} {{ editor.version }} all platforms
trigger_test_{{ packagename }}_{{ editor.version }}:
name : Trigger test {{ package_displayname }} {{ editor.version }} all platforms
dependencies:
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ package.name }}_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_{{ editor.version }}
{% if editor.version == "2020.3" -%}
triggers:
expression: pull_request.target eq "develop"
{% endif -%}
expression: pull_request.target eq "main"
{% endif %}
test_{{ package.name }}_{{ editor.version }}:
name : Test {{ package.packagename }} {{ editor.version }} all platforms
test_{{ packagename }}_{{ editor.version }}:
name : Test {{ package_displayname }} {{ editor.version }} all platforms
dependencies:
- .yamato/format.yml#check_formatting_dotnet-format
{% for platform in platforms %}
{% for param in platform.test_params %}
# todo(kazuki) :
@ -335,113 +334,78 @@ test_{{ package.name }}_{{ editor.version }}:
# XCode command line tools has not installed on m1 mac device (Standalone test don't need to install them)
{% if platform.name == "macos-m1" %}
{% if param.platform == "standalone" %}
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
{% endif %}
{% else %}
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ package.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
{% endif %}
{% endfor %}
{% endfor %}
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ package.name }}_{{ editor.version }}_ios
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_{{ editor.version }}_ios
{% for target in test_targets_android %}
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ package.name }}_{{ editor.version }}_android_{{ target.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_{{ editor.version }}_android_{{ target.name }}
{% endfor %}
test_renderpipeline_{{ package.name }}_{{ editor.version }}:
name : test {{ package.packagename }} {{ editor.version }} all RenderPipeline
test_renderpipeline_{{ packagename }}_{{ editor.version }}:
name : Test {{ package_displayname }} {{ editor.version }} all RenderPipeline
dependencies:
{% for platform in platforms %}
{% for param in platform.test_params %}
{% for project in test_projects %}
- .yamato/upm-ci-{{ package.name }}-packages.yml#test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
{% endfor %}
{% endfor %}
{% endfor %}
{% endfor %}
publish_dry_run_{{ package.name }}:
name: Publish Dry Run {{ package.packagename }}
publish_dry_run_{{ packagename }}:
name: Publish Dry Run {{ package_displayname }}
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- upm-ci package publish --dry-run --package-path {{ package.packagename }}
- upm-ci package publish --dry-run --package-path {{ packagename }}
triggers:
tags:
only:
- /^(r|R)(c|C)-\d+\.\d+\.\d+(-preview(\.\d+)?)?$/
artifacts:
{{ package.name }}_artifacts.zip:
{{ packagename }}_artifacts.zip:
paths:
- "upm-ci~/packages/*.tgz"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
{% for editor in editors %}
{% if editor.version != "trunk" -%} # exclude trunk to test
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ package.name }}_editmode_mono_win_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ package.name }}_editmode_mono_macos_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ package.name }}_editmode_mono_linux_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_editmode_mono_win-gpu_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_editmode_mono_macos_{{ editor.version }}
- .yamato/upm-ci-renderstreaming-packages.yml#test_{{ packagename }}_editmode_mono_linux-gpu_{{ editor.version }}
{% endif %}
{% endfor %}
publish_{{ package.name }}:
name: Publish {{ package.packagename }}
publish_{{ packagename }}:
name: Publish {{ package_displayname }}
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
- upm-ci package publish --package-path {{ package.packagename }}
- upm-ci package publish --package-path {{ packagename }}
triggers:
tags:
only:
- /^(r|R)(c|C)-\d+\.\d+\.\d+(-preview(\.\d+)?)?$/
artifacts:
{{ package.name }}_artifacts.zip:
{{ packagename }}_artifacts.zip:
paths:
- "upm-ci~/packages/*.tgz"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-renderstreaming-packages.yml#pack
{% for editor in editors %}
{% if editor.version != "trunk" -%} # exclude trunk to test
- .yamato/upm-ci-renderstreaming-packages.yml#trigger_test_{{ package.name }}_{{ editor.version }}
{% if editor.version != "trunk" %} # exclude trunk to test
- .yamato/upm-ci-renderstreaming-packages.yml#trigger_test_{{ packagename }}_{{ editor.version }}
{% endif %}
{% endfor %}
{% for platform in platforms %}
{% if platform.name != "macos" and platform.name != "macos-m1" %}
{% for editor in editors %}
codecoverage_{{ package.packagename }}_{{ platform.name }}_{{ editor.version }}:
name: Code coverage {{ package.packagename }} {{ platform.name }} {{ editor.version }}
agent:
type: {{ platform.type }}
image: {{ platform.image }}
flavor: {{ platform.flavor }}
commands:
- pip config set global.index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- pip install unity-downloader-cli --index-url https://artifactory.prd.it.unity3d.com/artifactory/api/pypi/pypi/simple
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
{% if platform.name == "win" %}
- |
set WEBAPP_PATH=%cd%\Webapp\bin~\{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --package-path {{ package.packagename }} --enable-code-coverage --code-coverage-options "generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:-UnityEngine.*,+Unity.RenderStreaming" --extra-utr-arg="--timeout=3000"
{% else %}
- |
export WEBAPP_PATH=$(pwd)/WebApp/bin~/{{ platform.packed_webapp_name }}
upm-ci package test -u {{ editor.version }} --package-path {{ package.packagename }} --enable-code-coverage --code-coverage-options "generateAdditionalMetrics;generateHtmlReport;generateBadgeReport;assemblyFilters:-UnityEngine.*,+Unity.RenderStreaming" --extra-utr-arg="--timeout=3000"
{% endif %}
artifacts:
{{ package.name }}_{{ editor.version }}_{{ platform.name }}_coverage_results:
paths:
- "upm-ci~/test-results/**"
dependencies:
- .yamato/upm-ci-renderstreaming-packages.yml#pack_{{ package.name }}
- .yamato/upm-ci-webapp.yml#pack_{{ platform.packed_webapp_platform }}
{% endfor %}
{% endif %}
{% endfor %}
{% endfor %}

View File

@ -1,17 +1,17 @@
# .yamato/upm-ci-template.yml
{% metadata_file .yamato/meta/environments.yml %}
{% metadata_file .yamato/package.metafile %}
---
{% for project in template_projects %}
{% for editor in editors %}
{% if editor.version == "2020.3" -%}
{% if editor.version == "2020.3" %}
prepack_{{ project.name }}_{{ editor.version }}:
name: Pre-Pack {{ project.packagename }} {{ editor.version }} - Primed Artifacts
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
commands:
- pip install unity-downloader-cli --index-url {{ intra_pypi_url }} --upgrade
@ -44,7 +44,7 @@ pack_{{ project.name }}_{{ editor.version }}:
- "upm-ci~/**/*"
{% for platform in platforms %}
{% if platform.name == "win" -%}
{% if platform.name == "win" or platform.name == "win-gpu" %}
{% for param in platform.test_params %}
test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ project.packagename }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
@ -66,9 +66,9 @@ test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
- .yamato/upm-ci-template.yml#pack_{{ project.name }}_{{ editor.version }}
- .yamato/upm-ci-webapp.yml#pack_{{ platform.name }}
{% endfor %}
{% else -%}
{% else %}
{% for param in platform.test_params %}
{% if project.name != "renderstreaming-rtx" -%}
{% if project.name != "renderstreaming-rtx" %}
test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}:
name : Test {{ project.packagename }} {{ param.platform }} {{ param.backend }} {{ editor.version }} on {{ platform.name }}
agent:
@ -85,36 +85,36 @@ test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.nam
dependencies:
- .yamato/upm-ci-template.yml#pack_{{ project.name }}_{{ editor.version }}
- .yamato/upm-ci-webapp.yml#pack_{{ platform.name }}
{% endif -%}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}
{% endfor %}
trigger_template_test_{{ project.name }}_{{ editor.version }}:
name : Trigger all Template test {{ project.packagename }} {{ editor.version }}
dependencies:
{% for platform in platforms %}
{% if platform.name == "win" -%}
{% if platform.name == "win" or platform.name == "win-gpu" %}
{% for param in platform.test_params %}
- .yamato/upm-ci-template.yml#test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
{% endfor %}
{% else -%}
{% else %}
{% if project.name != "renderstreaming-rtx" %}
{% for param in platform.test_params %}
- .yamato/upm-ci-template.yml#test_{{ project.name }}_{{ param.platform }}_{{ param.backend }}_{{ platform.name }}_{{ editor.version }}
{% endfor %}
{% endif %}
{% endif -%}
{% endif %}
{% endfor %}
{% endif -%}
{% endif %}
{% endfor %}
publish_{{ project.name }}:
name: Publish {{ project.packagename }}
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}
@ -143,7 +143,7 @@ publish_dryrun_{{ project.name }}:
name: Publish Dry Run {{ project.packagename }}
agent:
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.large
commands:
- npm install upm-ci-utils@{{ upm.package_version }} -g --registry {{ upm.registry_url }}

View File

@ -1,14 +1,14 @@
platforms:
- name: win
type: Unity::VM
image: package-ci/win10:v1.21.0-1103459
image: package-ci/win10:v4
flavor: b1.xlarge
pack_command: pack_webapp.cmd
test_command: test_webapp.cmd
client_test_command: test_webapp_client.cmd
- name: macos
type: Unity::VM::osx
image: package-ci/mac:v1.20.0-1079282
image: package-ci/macos-12:v4.10.0-1271191
flavor: m1.mac
pack_command: ./pack_webapp.sh
test_command: ./test_webapp.sh
@ -77,11 +77,11 @@ test_client_{{ platform.name }}:
trigger_webapp_test_{{ project.name }}:
name : Trigger all WebApp test {{ project.packagename }}
triggers:
expression: pull_request.target eq "develop"
expression: pull_request.target eq "main"
dependencies:
{% for platform in platforms %}
- .yamato/upm-ci-webapp.yml#test_{{ platform.name }}
- .yamato/upm-ci-webapp.yml#test_client_{{ platform.name }}
{% endfor %}
{% endfor %}
{% endfor %}

View File

@ -2,7 +2,7 @@
<img src="https://img.shields.io/badge/unity-2020.3-green.svg?style=flat-square" alt="unity 2020.3">
<img src="https://img.shields.io/badge/unity-2021.3-green.svg?style=flat-square" alt="unity 2021.3">
<img src="https://img.shields.io/badge/unity-2022.1-green.svg?style=flat-square" alt="unity 2022.1">
<img src="https://img.shields.io/badge/unity-2022.2-green.svg?style=flat-square" alt="unity 2022.3">
**Unity Render Streaming** is a solution that provides Unity's high quality rendering abilities via browser. It's designed to meet the needs of tasks like viewing car configurators or architectural models on mobile devices.
This solution's streaming technology takes advantage of [WebRTC](https://webrtc.org/), and developers can even use the [WebRTC package](https://docs.unity3d.com/Packages/com.unity.webrtc@latest) to create their own unique solutions.
@ -13,13 +13,6 @@ This solution's streaming technology takes advantage of [WebRTC](https://webrtc.
Please see [Requirements](com.unity.renderstreaming/Documentation~/index.md#requirements) section.
### Furioos compatibility
**Unity Render Streaming** is also supported natively by **Furioos** platform https://www.furioos.com/ .
That means that you can easily build a Unity application, upload it on **Furioos** and enjoy all the features of **Unity Render Streaming** without worrying about the deployment and scalability issues of your project.
Please see [Furioos Tutorial](com.unity.renderstreaming/Documentation~/deploy-to-furioos) section to find out how it works.
### License
- `com.unity.renderstreaming` - [LICENSE.md](com.unity.renderstreaming/LICENSE.md)
@ -54,8 +47,11 @@ Please see [Furioos Tutorial](com.unity.renderstreaming/Documentation~/deploy-to
| `3.1.0-exp.1` | - Android platform support | Jun 2021 |
| `3.1.0-exp.2` | - Audio Renderer support <br/> - Multiplay sample <br/> - M1 Mac support | Dec 2021 |
| `3.1.0-exp.3` | - Fix bugs | Feb 2022 |
| `3.1.0-exp.4` | - Streaming settings API <br/> - *Unity 2022.1* support <br/> - Remove *Unity 2019.4* from support list | Sep 2022 |
| `3.1.0-exp.5` | | Nov 2022 |
| `3.1.0-exp.4` | - Streaming settings API <br/> - *Unity 2022.1* support <br/> - Remove *Unity 2019.4* from support list | Oct 2022 |
| `3.1.0-exp.5` | - Fix bugs | Jan 2023 |
| `3.1.0-exp.6` | - Streaming Settings Window <br/> - Auto Configuration <br/> - Command line option | Feb 2023 |
| `3.1.0-exp.7` | - Fix bugs | Jul 2023 |
| `3.1.0-exp.8` | - Fix bugs | Nov 2023 |
## FAQ

View File

@ -1,14 +1,15 @@
{
"dependencies": {
"com.unity.ide.rider": "3.0.15",
"com.unity.ide.visualstudio": "2.0.16",
"com.unity.ide.rider": "3.0.24",
"com.unity.ide.visualstudio": "2.0.18",
"com.unity.ide.vscode": "1.2.5",
"com.unity.test-framework": "1.1.33",
"com.unity.testtools.codecoverage": "1.2.0-exp.7",
"com.unity.testtools.codecoverage": "1.2.4",
"com.unity.ugui": "1.0.0",
"com.unity.xr.arcore": "4.2.3",
"com.unity.xr.arfoundation": "4.2.3",
"com.unity.xr.arkit": "4.2.3",
"com.unity.xr.arcore": "5.0.6",
"com.unity.xr.arfoundation": "5.0.6",
"com.unity.xr.arkit": "5.0.6",
"com.unity.xr.management": "4.3.3",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.animation": "1.0.0",
"com.unity.modules.audio": "1.0.0",
@ -16,10 +17,6 @@
"com.unity.modules.physics": "1.0.0",
"com.unity.modules.screencapture": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.uielements": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
},
"testables": [
"com.unity.inputsystem"
]
"com.unity.modules.uielements": "1.0.0"
}
}

View File

@ -15,7 +15,7 @@
"url": "https://packages.unity.com"
},
"com.unity.ide.rider": {
"version": "3.0.15",
"version": "3.0.24",
"depth": 0,
"source": "registry",
"dependencies": {
@ -24,7 +24,7 @@
"url": "https://packages.unity.com"
},
"com.unity.ide.visualstudio": {
"version": "2.0.16",
"version": "2.0.18",
"depth": 0,
"source": "registry",
"dependencies": {
@ -40,7 +40,7 @@
"url": "https://packages.unity.com"
},
"com.unity.inputsystem": {
"version": "1.4.2",
"version": "1.7.0",
"depth": 1,
"source": "registry",
"dependencies": {
@ -48,13 +48,22 @@
},
"url": "https://packages.unity.com"
},
"com.unity.mathematics": {
"version": "1.2.6",
"depth": 1,
"source": "registry",
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.renderstreaming": {
"version": "file:com.unity.renderstreaming",
"depth": 0,
"source": "embedded",
"dependencies": {
"com.unity.webrtc": "2.4.0-exp.11",
"com.unity.inputsystem": "1.4.1"
"com.unity.webrtc": "3.0.0-pre.7",
"com.unity.inputsystem": "1.5.1",
"com.unity.ugui": "1.0.0",
"com.unity.modules.screencapture": "1.0.0"
}
},
"com.unity.settings-manager": {
@ -64,15 +73,6 @@
"dependencies": {},
"url": "https://packages.unity.com"
},
"com.unity.subsystemregistration": {
"version": "1.1.0",
"depth": 2,
"source": "registry",
"dependencies": {
"com.unity.modules.subsystems": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.test-framework": {
"version": "1.1.33",
"depth": 0,
@ -85,7 +85,7 @@
"url": "https://packages.unity.com"
},
"com.unity.testtools.codecoverage": {
"version": "1.2.0-exp.7",
"version": "1.2.4",
"depth": 0,
"source": "registry",
"dependencies": {
@ -104,21 +104,23 @@
}
},
"com.unity.webrtc": {
"version": "2.4.0-exp.11",
"version": "3.0.0-pre.7",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.editorcoroutines": "1.0.0"
"com.unity.editorcoroutines": "1.0.0",
"com.unity.modules.audio": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.xr.arcore": {
"version": "4.2.3",
"version": "5.0.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.xr.arsubsystems": "4.2.3",
"com.unity.xr.arfoundation": "5.0.6",
"com.unity.xr.core-utils": "2.1.0",
"com.unity.xr.management": "4.0.1",
"com.unity.modules.androidjni": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
@ -126,40 +128,46 @@
"url": "https://packages.unity.com"
},
"com.unity.xr.arfoundation": {
"version": "4.2.3",
"version": "5.0.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.xr.arsubsystems": "4.2.3",
"com.unity.inputsystem": "1.3.0",
"com.unity.xr.core-utils": "2.1.0",
"com.unity.xr.management": "4.0.1",
"com.unity.modules.particlesystem": "1.0.0"
"com.unity.ugui": "1.0.0",
"com.unity.mathematics": "1.2.5",
"com.unity.modules.particlesystem": "1.0.0",
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.unityanalytics": "1.0.0",
"com.unity.modules.unitywebrequest": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.xr.arkit": {
"version": "4.2.3",
"version": "5.0.6",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.editorcoroutines": "1.0.0",
"com.unity.xr.arsubsystems": "4.2.3",
"com.unity.xr.arfoundation": "5.0.6",
"com.unity.xr.core-utils": "2.1.0",
"com.unity.xr.management": "4.0.1"
},
"url": "https://packages.unity.com"
},
"com.unity.xr.arsubsystems": {
"version": "4.2.3",
"com.unity.xr.core-utils": {
"version": "2.2.3",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.subsystemregistration": "1.1.0",
"com.unity.xr.management": "4.0.1"
"com.unity.modules.xr": "1.0.0"
},
"url": "https://packages.unity.com"
},
"com.unity.xr.legacyinputhelpers": {
"version": "2.1.10",
"depth": 2,
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.vr": "1.0.0",
@ -168,15 +176,14 @@
"url": "https://packages.unity.com"
},
"com.unity.xr.management": {
"version": "4.2.0",
"depth": 1,
"version": "4.3.3",
"depth": 0,
"source": "registry",
"dependencies": {
"com.unity.modules.subsystems": "1.0.0",
"com.unity.modules.vr": "1.0.0",
"com.unity.modules.xr": "1.0.0",
"com.unity.xr.legacyinputhelpers": "2.1.7",
"com.unity.subsystemregistration": "1.0.6"
"com.unity.xr.legacyinputhelpers": "2.1.7"
},
"url": "https://packages.unity.com"
},
@ -238,7 +245,7 @@
},
"com.unity.modules.subsystems": {
"version": "1.0.0",
"depth": 2,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0"
@ -271,15 +278,24 @@
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.unityanalytics": {
"version": "1.0.0",
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.unitywebrequest": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0"
}
},
"com.unity.modules.unitywebrequest": {
"version": "1.0.0",
"depth": 0,
"depth": 1,
"source": "builtin",
"dependencies": {}
},
"com.unity.modules.vr": {
"version": "1.0.0",
"depth": 2,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0",
@ -289,7 +305,7 @@
},
"com.unity.modules.xr": {
"version": "1.0.0",
"depth": 2,
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.physics": "1.0.0",

View File

@ -42,5 +42,9 @@ EditorBuildSettings:
type: 2}
com.unity.input.settings: {fileID: 11400000, guid: 9d3afefa5e1574ee38fb1d298122dbc7,
type: 2}
com.unity.renderstreaming.settings: {fileID: 11400000, guid: 039337c008e9a5c44a60f957eae3e450,
type: 2}
com.unity.xr.arfoundation.simulation_settings: {fileID: 11400000, guid: 0ec671069889a6541b317d5976884498,
type: 2}
com.unity.xr.management.loader_settings: {fileID: 11400000, guid: 66105b57eda77e74db55e7eb2b532054,
type: 2}

View File

@ -149,7 +149,6 @@ PlayerSettings:
enable360StereoCapture: 0
isWsaHolographicRemotingEnabled: 0
enableFrameTimingStats: 0
enableOpenGLProfilerGPURecorders: 1
useHDRDisplay: 0
D3DHDRBitDepth: 0
m_ColorGamuts: 00000000
@ -175,7 +174,7 @@ PlayerSettings:
stripEngineCode: 0
iPhoneStrippingLevel: 0
iPhoneScriptCallOptimization: 0
ForceInternetPermission: 0
ForceInternetPermission: 1
ForceSDCardPermission: 0
CreateWallpaper: 0
APKExpansionFiles: 0
@ -224,7 +223,6 @@ PlayerSettings:
iOSLaunchScreeniPadCustomStoryboardPath:
iOSDeviceRequirements: []
iOSURLSchemes: []
macOSURLSchemes: []
iOSBackgroundModes: 0
iOSMetalForceHardShadows: 0
metalEditorSupport: 1
@ -449,7 +447,6 @@ PlayerSettings:
m_BuildTargetGroupLightmapEncodingQuality: []
m_BuildTargetGroupLightmapSettings: []
m_BuildTargetNormalMapEncoding: []
m_BuildTargetDefaultTextureCompressionFormat: []
playModeTestRunnerEnabled: 0
runPlayModeTestAsEditModeTest: 0
actionOnDotNetUnhandledException: 1
@ -468,7 +465,6 @@ PlayerSettings:
switchScreenResolutionBehavior: 2
switchUseCPUProfiler: 0
switchUseGOLDLinker: 0
switchLTOSetting: 0
switchApplicationID: 0x01004b9000490000
switchNSODependencies:
switchTitleNames_0:
@ -598,6 +594,7 @@ PlayerSettings:
switchNetworkInterfaceManagerInitializeEnabled: 1
switchPlayerConnectionEnabled: 1
switchUseNewStyleFilepaths: 0
switchUseLegacyFmodPriorities: 1
switchUseMicroSleepForYield: 1
switchEnableRamDiskSupport: 0
switchMicroSleepForYieldTime: 25
@ -708,6 +705,7 @@ PlayerSettings:
suppressCommonWarnings: 1
allowUnsafeCode: 0
useDeterministicCompilation: 1
useReferenceAssemblies: 1
enableRoslynAnalyzers: 1
additionalIl2CppArgs:
scriptingRuntimeVersion: 1
@ -788,6 +786,7 @@ PlayerSettings:
m_VersionName:
apiCompatibilityLevel: 6
activeInputHandler: 1
windowsGamepadBackendHint: 0
cloudProjectId:
framebufferDepthMemorylessMode: 0
qualitySettingsNames: []
@ -795,6 +794,4 @@ PlayerSettings:
organizationId:
cloudEnabled: 0
legacyClampBlendShapeWeights: 0
playerDataPath:
forceSRGBBlit: 1
virtualTexturingSupportEnabled: 0

View File

@ -1,2 +1,2 @@
m_EditorVersion: 2021.3.11f1
m_EditorVersionWithRevision: 2021.3.11f1 (0a5ca18544bf)
m_EditorVersion: 2021.3.31f1
m_EditorVersionWithRevision: 2021.3.31f1 (3409e2af086f)

View File

@ -0,0 +1,16 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!114 &1
MonoBehaviour:
m_ObjectHideFlags: 61
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: b4f5b5e9819c4eafb84bd87d1c2f266f, type: 3}
m_Name:
m_EditorClassIdentifier:
m_WizardPopupAtStart: 0
m_WizardPopupAlreadyShownOnce: 1

View File

@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ff4235c650c6444a9bfcdff2322a547a
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@ -0,0 +1,40 @@
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
#if UNITY_IOS
using UnityEditor.iOS.Xcode;
#endif
class PostProcess : IPostprocessBuildWithReport
{
public int callbackOrder { get { return 0; } }
public void OnPostprocessBuild(BuildReport report)
{
#if UNITY_IOS
if (report.summary.platform == BuildTarget.iOS)
{
string projectPath = report.summary.outputPath + "/Unity-iPhone.xcodeproj/project.pbxproj";
PBXProject pbxProject = new PBXProject();
pbxProject.ReadFromFile(projectPath);
//Disabling Bitcode on all targets
//Main
string target = pbxProject.GetUnityMainTargetGuid();
pbxProject.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
//Unity Tests
target = pbxProject.TargetGuidByName(PBXProject.GetUnityTestTargetName());
pbxProject.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
//Unity Framework
target = pbxProject.GetUnityFrameworkTargetGuid();
pbxProject.SetBuildProperty(target, "ENABLE_BITCODE", "NO");
pbxProject.WriteToFile(projectPath);
}
#endif
}
}

View File

@ -1,5 +1,5 @@
fileFormatVersion: 2
guid: 12f537a158c855d4fa65dd091ad15a7e
guid: 40f483dfdb21e42c697cf1fd36e61c0c
MonoImporter:
externalObjects: {}
serializedVersion: 2

View File

@ -1,9 +1,9 @@
{
"dependencies": {
"com.unity.renderstreaming": "file:../../../com.unity.renderstreaming",
"com.unity.test-framework": "1.1.31",
"com.unity.test-framework": "1.1.33",
"com.unity.textmeshpro": "3.0.6",
"com.unity.timeline": "1.6.4",
"com.unity.timeline": "1.7.5",
"com.unity.ugui": "1.0.0",
"com.unity.modules.ai": "1.0.0",
"com.unity.modules.androidjni": "1.0.0",

View File

@ -15,7 +15,7 @@
"url": "https://packages.unity.com"
},
"com.unity.inputsystem": {
"version": "1.4.2",
"version": "1.7.0",
"depth": 1,
"source": "registry",
"dependencies": {
@ -28,12 +28,14 @@
"depth": 0,
"source": "local",
"dependencies": {
"com.unity.webrtc": "2.4.0-exp.11",
"com.unity.inputsystem": "1.4.1"
"com.unity.webrtc": "3.0.0-pre.7",
"com.unity.inputsystem": "1.5.1",
"com.unity.ugui": "1.0.0",
"com.unity.modules.screencapture": "1.0.0"
}
},
"com.unity.test-framework": {
"version": "1.1.31",
"version": "1.1.33",
"depth": 0,
"source": "registry",
"dependencies": {
@ -53,7 +55,7 @@
"url": "https://packages.unity.com"
},
"com.unity.timeline": {
"version": "1.6.4",
"version": "1.7.5",
"depth": 0,
"source": "registry",
"dependencies": {
@ -74,12 +76,13 @@
}
},
"com.unity.webrtc": {
"version": "2.4.0-exp.11",
"version": "3.0.0-pre.7",
"depth": 1,
"source": "registry",
"dependencies": {
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.editorcoroutines": "1.0.0"
"com.unity.editorcoroutines": "1.0.0",
"com.unity.modules.audio": "1.0.0"
},
"url": "https://packages.unity.com"
},
@ -215,17 +218,6 @@
"version": "1.0.0",
"depth": 0,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",
"com.unity.modules.jsonserialize": "1.0.0",
"com.unity.modules.uielementsnative": "1.0.0"
}
},
"com.unity.modules.uielementsnative": {
"version": "1.0.0",
"depth": 1,
"source": "builtin",
"dependencies": {
"com.unity.modules.ui": "1.0.0",
"com.unity.modules.imgui": "1.0.0",

View File

@ -1,2 +1,2 @@
m_EditorVersion: 2021.3.11f1
m_EditorVersionWithRevision: 2021.3.11f1 (0a5ca18544bf)
m_EditorVersion: 2021.3.16f1
m_EditorVersionWithRevision: 2021.3.16f1 (4016570cf34f)

View File

@ -30,17 +30,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.19.0",
"resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.19.0.tgz",
@ -90,13 +162,14 @@
}
},
"node_modules/@babel/generator": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz",
"integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==",
"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.19.0",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
},
"engines": {
@ -145,34 +218,34 @@
}
},
"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.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"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.18.10",
"@babel/types": "^7.19.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"
@ -231,30 +304,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.18.10",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
"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.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
"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"
@ -284,13 +357,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": {
@ -369,9 +442,9 @@
}
},
"node_modules/@babel/parser": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz",
"integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==",
"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"
@ -558,33 +631,33 @@
}
},
"node_modules/@babel/template": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
"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.18.10",
"@babel/types": "^7.18.10"
"@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.19.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz",
"integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==",
"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.19.0",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.19.0",
"@babel/types": "^7.19.0",
"@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"
},
@ -602,13 +675,13 @@
}
},
"node_modules/@babel/types": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz",
"integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==",
"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.18.10",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
},
"engines": {
@ -1127,13 +1200,13 @@
"dev": true
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.15",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
"dev": true,
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"node_modules/@nodelib/fs.scandir": {
@ -1181,9 +1254,9 @@
}
},
"node_modules/@sideway/formula": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
"dev": true
},
"node_modules/@sideway/pinpoint": {
@ -4032,9 +4105,9 @@
"dev": true
},
"node_modules/json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"bin": {
"json5": "lib/cli.js"
@ -5157,9 +5230,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",
@ -5445,9 +5518,9 @@
}
},
"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"
@ -5592,12 +5665,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": {
@ -5638,13 +5770,14 @@
}
},
"@babel/generator": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.19.0.tgz",
"integrity": "sha512-S1ahxf1gZ2dpoiFgA+ohK9DIpz50bJ0CWs7Zlzb54Z4sG8qmdIrGrVqmy1sAtTVRb+9CU6U8VqT9L0Zj7hxHVg==",
"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.19.0",
"@babel/types": "^7.23.0",
"@jridgewell/gen-mapping": "^0.3.2",
"@jridgewell/trace-mapping": "^0.3.17",
"jsesc": "^2.5.1"
},
"dependencies": {
@ -5682,28 +5815,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.19.0",
"resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.19.0.tgz",
"integrity": "sha512-WAwHBINyrpqywkUH0nTnNgI5ina5TFn85HKS0pbPDfxFfhyR/aNQEn4hGi1P1JyT//I0t4OgXUlofzWILRvS5w==",
"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.18.10",
"@babel/types": "^7.19.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": {
@ -5747,24 +5880,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.18.10",
"resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.18.10.tgz",
"integrity": "sha512-XtIfWmeNY3i4t7t4D2t02q50HvqHybPqW2ki1kosnvWCwuCMeo81Jf0gwr85jy/neUdg5XDdeFE/80DXiO+njw==",
"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.18.6",
"resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.18.6.tgz",
"integrity": "sha512-MmetCkz9ej86nJQV+sFCxoGGrUbU3q02kgLciwkrt9QqEB7cP39oKEY0PakknEO0Gu20SskMRi+AYZ3b1TpN9g==",
"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": {
@ -5785,13 +5918,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": {
@ -5854,9 +5987,9 @@
}
},
"@babel/parser": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.19.0.tgz",
"integrity": "sha512-74bEXKX2h+8rrfQUfsBfuZZHzsEs6Eql4pqy/T4Nn6Y9wNPggQOqD6z6pn5Bl8ZfysKouFZT/UXEH94ummEeQw==",
"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": {
@ -5986,30 +6119,30 @@
}
},
"@babel/template": {
"version": "7.18.10",
"resolved": "https://registry.npmjs.org/@babel/template/-/template-7.18.10.tgz",
"integrity": "sha512-TI+rCtooWHr3QJ27kJxfjutghu44DLnasDMwpDqCXVTal9RLp3RSYNh4NdBrRP2cQAoG9A8juOQl6P6oZG4JxA==",
"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.18.10",
"@babel/types": "^7.18.10"
"@babel/code-frame": "^7.22.13",
"@babel/parser": "^7.22.15",
"@babel/types": "^7.22.15"
}
},
"@babel/traverse": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.19.0.tgz",
"integrity": "sha512-4pKpFRDh+utd2mbRC8JLnlsMUii3PMHjpL6a0SZ4NMZy7YFP9aXORxEhdMVOc9CpWtDF09IkciQLEhK7Ml7gRA==",
"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.19.0",
"@babel/helper-environment-visitor": "^7.18.9",
"@babel/helper-function-name": "^7.19.0",
"@babel/helper-hoist-variables": "^7.18.6",
"@babel/helper-split-export-declaration": "^7.18.6",
"@babel/parser": "^7.19.0",
"@babel/types": "^7.19.0",
"@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"
},
@ -6023,13 +6156,13 @@
}
},
"@babel/types": {
"version": "7.19.0",
"resolved": "https://registry.npmjs.org/@babel/types/-/types-7.19.0.tgz",
"integrity": "sha512-YuGopBq3ke25BVSiS6fgF49Ul9gH1x70Bcr6bqRLjWCkcX8Hre1/5+z+IiWOIerRMSSEfGZVB9z9kyq7wVs9YA==",
"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.18.10",
"@babel/helper-validator-identifier": "^7.18.6",
"@babel/helper-string-parser": "^7.22.5",
"@babel/helper-validator-identifier": "^7.22.20",
"to-fast-properties": "^2.0.0"
}
},
@ -6433,13 +6566,13 @@
"dev": true
},
"@jridgewell/trace-mapping": {
"version": "0.3.15",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.15.tgz",
"integrity": "sha512-oWZNOULl+UbhsgB51uuZzglikfIKSUBO/M9W2OfEjn7cmqoAiCgmv9lyACTUacZwBz0ITnJ2NqjU8Tx0DHL88g==",
"version": "0.3.20",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.20.tgz",
"integrity": "sha512-R8LcPeWZol2zR8mmH3JeKQ6QRCFb7XgUhV9ZlGhHLGyg4wpPiPZNQOOWhFZhxKw8u//yTbNGI42Bx/3paXEQ+Q==",
"dev": true,
"requires": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
"@jridgewell/resolve-uri": "^3.1.0",
"@jridgewell/sourcemap-codec": "^1.4.14"
}
},
"@nodelib/fs.scandir": {
@ -6478,9 +6611,9 @@
}
},
"@sideway/formula": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.0.tgz",
"integrity": "sha512-vHe7wZ4NOXVfkoRb8T5otiENVlT7a3IAiw7H5M2+GO+9CDgcVUUsX1zalAztCmwyOr2RUTGJdgB+ZvSVqmdHmg==",
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz",
"integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==",
"dev": true
},
"@sideway/pinpoint": {
@ -8638,9 +8771,9 @@
"dev": true
},
"json5": {
"version": "2.2.1",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.1.tgz",
"integrity": "sha512-1hqLFMSrGHRHxav9q9gNjJ5EXznIxGVO09xQRrwplcS8qs28pZ8s8hupZAmqDwZUmVZ2Qb2jnyPOWcDH8m8dlA==",
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true
},
"kleur": {
@ -9456,9 +9589,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",
@ -9658,9 +9791,9 @@
}
},
"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

@ -16,23 +16,24 @@
<div id="warning" hidden=true></div>
<div id="select">
<label for="videoSource">Video source: </label><select id="videoSource"></select>
<label for="audioSource">Audio source: </label><select id="audioSource"></select>
<label for="videoSource">Video source: </label>
<select id="videoSource" autocomplete="off"></select>
<label for="audioSource">Audio source: </label>
<select id="audioSource" autocomplete="off"></select>
</div>
<div id="resolutionSelect">
<label for="videoResolution">Video resolution: </label><select id="videoResolution"></select>
<label for="videoResolution">Video resolution: </label><select id="videoResolution" autocomplete="off"></select>
</div>
<div id="resolutionInput">
<label for="cameraWidth">Camera width:</label><input id="cameraWidth" type="number" min="0" max="4096" disabled>
<label for="cameraHeight">Camera height:</label><input id="cameraHeight" type="number" min="0" max="4096"
disabled>
<label for="cameraWidth">Camera width:</label><input id="cameraWidth" type="number" min="0" max="4096" autocomplete="off" disabled>
<label for="cameraHeight">Camera height:</label><input id="cameraHeight" type="number" min="0" max="4096" autocomplete="off" disabled>
</div>
<div id="buttons">
<button type="button" id="startVideoButton">Start Video</button>
<button type="button" id="setUpButton" disabled>Set Up</button>
<button type="button" id="hangUpButton" disabled>Hang Up</button>
<button type="button" id="startVideoButton" autocomplete="off">Start Video</button>
<button type="button" id="setUpButton" autocomplete="off" disabled>Set Up</button>
<button type="button" id="hangUpButton" autocomplete="off" disabled>Hang Up</button>
</div>
<div id="preview">
@ -54,7 +55,7 @@
</div>
<div class="box">
<span>Codec preferences:</span>
<select id="codecPreferences" disabled>
<select id="codecPreferences" autocomplete="off" disabled>
<option selected value="">Default</option>
</select>
</div>
@ -75,9 +76,8 @@
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://unpkg.com/event-target@latest/min.js"></script>
<script src="https://unpkg.com/resize-observer-polyfill@1.5.0/dist/ResizeObserver.global.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<script type="module" src="js/main.js"></script>
</body>
</html>
</html>

View File

@ -58,7 +58,9 @@ const hangUpButton = document.getElementById('hangUpButton');
hangUpButton.addEventListener('click', hangUp);
window.addEventListener('beforeunload', async () => {
await sendVideo.stop();
if(!renderstreaming)
return;
await renderstreaming.stop();
}, true);
setupConfig();
@ -84,7 +86,6 @@ async function startVideo() {
cameraWidthInput.disabled = true;
cameraHeightInput.disabled = true;
startButton.disabled = true;
setupButton.disabled = false;
let width = 0;
let height = 0;
@ -98,6 +99,9 @@ async function startVideo() {
}
await sendVideo.startLocalVideo(videoSelect.value, audioSelect.value, width, height);
// enable setup button after initializing local video.
setupButton.disabled = false;
}
async function setUp() {
@ -112,7 +116,7 @@ async function setUp() {
renderstreaming.onConnect = () => {
const tracks = sendVideo.getLocalTracks();
for (const track of tracks) {
renderstreaming.addTrack(track);
renderstreaming.addTransceiver(track, { direction: 'sendonly' });
}
setCodecPreferences();
showStatsMessage();
@ -280,4 +284,4 @@ function clearStatsMessage() {
remoteVideoStatsDiv.innerHTML = '';
messageDiv.style.display = 'none';
messageDiv.innerHTML = '';
}
}

View File

@ -7,10 +7,10 @@ export class SendVideo {
}
/**
* @param {MediaTrackConstraints} videoSource
* @param {MediaTrackConstraints} audioSource
* @param {number} videoWidth
* @param {number} videoHeight
* @param {MediaTrackConstraints} videoSource
* @param {MediaTrackConstraints} audioSource
* @param {number} videoWidth
* @param {number} videoHeight
*/
async startLocalVideo(videoSource, audioSource, videoWidth, videoHeight) {
try {
@ -42,7 +42,7 @@ export class SendVideo {
}
/**
* @param {MediaStreamTrack} track
* @param {MediaStreamTrack} track
*/
addRemoteTrack(track) {
if (this.remoteVideo.srcObject == null) {

View File

@ -18,12 +18,43 @@ body {
word-break: break-word;
}
button {
margin: 20px 10px 0 0;
width: 130px;
}
button#gather {
display: block;
}
section {
border-bottom: 1px solid #eee;
margin: 0 0 1.5em 0;
padding: 0 0 1.5em 0;
}
section#iceServers label {
display: inline-block;
width: 150px;
}
section#iceServers input {
margin: 0 0 10px;
width: 260px;
}
select {
margin: 0 1em 1em 0;
position: relative;
top: -1px;
}
select#servers {
font-size: 1em;
padding: 5px;
width: 420px;
}
section:last-child {
border-bottom: none;
margin: 0;

View File

@ -15,9 +15,33 @@
</section>
<section>
<h2>Server Configuration</h2>
<div id="startup"></div>
</section>
<section id="iceServers">
<h2>ICE servers</h2>
<select id="servers" size="4">
</select>
<div>
<label for="url">STUN or TURN URI:</label>
<input id="url">
</div>
<div>
<label for="username">TURN username:</label>
<input id="username">
</div>
<div>
<label for="password">TURN password:</label>
<input id="password">
</div>
<div>
<button id="add">Add Server</button>
<button id="remove">Remove Server</button>
<button id="reset">Reset to defaults</button>
</div>
</section>
<section>
<h2 id="receiver"><a href="receiver/index.html">Receiver Sample</a></h2>
<p>This is a sample for receiving video / audio from Unity.</p>
@ -50,4 +74,4 @@
</div>
<script type="module" src="js/main.js"></script>
</body>
</body>

View File

@ -1,3 +1,5 @@
import {getServers} from "./icesettings.js";
export async function getServerConfig() {
const protocolEndPoint = location.origin + '/config';
const createResponse = await fetch(protocolEndPoint);
@ -7,6 +9,6 @@ export async function getServerConfig() {
export function getRTCConfiguration() {
let config = {};
config.sdpSemantics = 'unified-plan';
config.iceServers = [{ urls: ['stun:stun.l.google.com:19302'] }];
config.iceServers = getServers();
return config;
}
}

View File

@ -0,0 +1,103 @@
// This code is referenced from webrtc sample.
// https://github.com/webrtc/samples/blob/gh-pages/src/content/peerconnection/trickle-ice/js/main.js
const servers = document.querySelector('select#servers');
const urlInput = document.querySelector('input#url');
const usernameInput = document.querySelector('input#username');
const passwordInput = document.querySelector('input#password');
const allServersKey = 'servers';
export function addServer() {
const scheme = urlInput.value.split(':')[0];
if (!['stun', 'stuns', 'turn', 'turns'].includes(scheme)) {
alert(`URI scheme ${scheme} is not valid`);
return;
}
// Store the ICE server as a stringified JSON object in option.value.
const option = document.createElement('option');
const iceServer = {
urls: [urlInput.value],
username: usernameInput.value,
credential: passwordInput.value
};
option.value = JSON.stringify(iceServer);
option.text = `${urlInput.value} `;
const username = usernameInput.value;
const password = passwordInput.value;
if (username || password) {
option.text += (` [${username}:${password}]`);
}
option.ondblclick = selectServer;
servers.add(option);
urlInput.value = usernameInput.value = passwordInput.value = '';
writeServersToLocalStorage();
}
export function removeServer() {
for (let i = servers.options.length - 1; i >= 0; --i) {
if (servers.options[i].selected) {
servers.remove(i);
}
}
writeServersToLocalStorage();
}
export function reset() {
window.localStorage.clear();
document.querySelectorAll('select#servers option').forEach(option => option.remove());
const serversSelect = document.querySelector('select#servers');
setDefaultServer(serversSelect);
}
function selectServer(event) {
const option = event.target;
const value = JSON.parse(option.value);
urlInput.value = value.urls[0];
usernameInput.value = value.username || '';
passwordInput.value = value.credential || '';
}
function setDefaultServer(serversSelect) {
const option = document.createElement('option');
option.value = '{"urls":["stun:stun.l.google.com:19302"]}';
option.text = 'stun:stun.l.google.com:19302';
option.ondblclick = selectServer;
serversSelect.add(option);
}
function writeServersToLocalStorage() {
const serversSelect = document.querySelector('select#servers');
const allServers = JSON.stringify(Object.values(serversSelect.options).map(o => JSON.parse(o.value)));
window.localStorage.setItem(allServersKey, allServers);
}
export function readServersFromLocalStorage() {
document.querySelectorAll('select#servers option').forEach(option => option.remove());
const serversSelect = document.querySelector('select#servers');
const storedServers = window.localStorage.getItem(allServersKey);
if (storedServers === null || storedServers === '') {
setDefaultServer(serversSelect);
} else {
JSON.parse(storedServers).forEach((server) => {
const o = document.createElement('option');
o.value = JSON.stringify(server);
o.text = server.urls[0];
o.ondblclick = selectServer;
serversSelect.add(o);
});
}
}
export function getServers() {
const storedServers = window.localStorage.getItem(allServersKey);
if (storedServers === null || storedServers === '') {
return [{ urls: ['stun:stun.l.google.com:19302'] }];
}
else {
return JSON.parse(storedServers);
}
}

View File

@ -1,7 +1,15 @@
import * as Config from "./config.js";
import {addServer, removeServer, reset, readServersFromLocalStorage} from "./icesettings.js";
const addButton = document.querySelector('button#add');
const removeButton = document.querySelector('button#remove');
const resetButton = document.querySelector('button#reset');
const startupDiv = document.getElementById("startup");
startupDiv.innerHTML = "<h3>Server Configuration</h3>";
addButton.onclick = addServer;
removeButton.onclick = removeServer;
resetButton.onclick = reset;
startupDiv.innerHTML = "";
const displayConfig = async () => {
const res = await Config.getServerConfig();
@ -16,3 +24,4 @@ const displayConfig = async () => {
};
displayConfig();
readServersFromLocalStorage();

View File

@ -20,14 +20,14 @@
<div class="box">
<span>Codec preferences:</span>
<select id="codecPreferences" disabled>
<select id="codecPreferences" autocomplete="off" disabled>
<option selected value="">Default</option>
</select>
</div>
<div class="box">
<span>Lock Cursor to Player:</span>
<input type="checkbox" id="lockMouseCheck">
<input type="checkbox" id="lockMouseCheck" autocomplete="off" />
</div>
<p>
@ -46,9 +46,8 @@
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://unpkg.com/event-target@latest/min.js"></script>
<script src="https://unpkg.com/resize-observer-polyfill@1.5.0/dist/ResizeObserver.global.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<script type="module" src="js/main.js"></script>
</body>
</html>
</html>

View File

@ -39,6 +39,8 @@ window.addEventListener('resize', function () {
}, true);
window.addEventListener('beforeunload', async () => {
if(!renderstreaming)
return;
await renderstreaming.stop();
}, true);
@ -198,4 +200,4 @@ function clearStatsMessage() {
intervalId = null;
messageDiv.style.display = 'none';
messageDiv.innerHTML = '';
}
}

View File

@ -20,18 +20,18 @@
<div class="box">
<span>Codec preferences:</span>
<select id="codecPreferences" disabled>
<select id="codecPreferences" autocomplete="off" disabled>
<option selected value="">Default</option>
</select>
</div>
<div class="box">
<span>Lock Cursor to Player:</span>
<input type="checkbox" id="lockMouseCheck">
<input type="checkbox" id="lockMouseCheck" autocomplete="off" />
</div>
<p>
For more information about sample, see
For more information about sample, see
<a href="https://docs.unity3d.com/Packages/com.unity.renderstreaming@3.1/manual/sample-broadcast.html">Broadcast sample</a> document page.
</p>
@ -46,9 +46,8 @@
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://unpkg.com/event-target@latest/min.js"></script>
<script src="https://unpkg.com/resize-observer-polyfill@1.5.0/dist/ResizeObserver.global.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<script type="module" src="js/main.js"></script>
</body>
</html>
</html>

View File

@ -30,7 +30,6 @@
<script type="text/javascript" src="https://webrtc.github.io/adapter/adapter-latest.js"></script>
<script src="https://unpkg.com/event-target@latest/min.js"></script>
<script src="https://unpkg.com/resize-observer-polyfill@1.5.0/dist/ResizeObserver.global.js"></script>
<script src="https://cdn.polyfill.io/v2/polyfill.min.js?features=IntersectionObserver"></script>
<script type="module" src="js/main.js"></script>
</body>

View File

@ -0,0 +1,109 @@
// KeyboardEvent.charcode is already deprecated.
//
export const CharNumber = {
"Backspace": 8,
"Tab": 9,
"Enter": 13,
"Shift": 16,
"Control": 17,
"Alt": 18,
"Pause": 19,
"CapsLock": 20,
"Escape": 27,
" ": 32,
"!": 33,
"\"": 34,
"#": 35,
"$": 36,
"%": 37,
"&": 38,
"'": 39,
"(": 40,
")": 41,
"*": 42,
"+": 43,
",": 44,
"-": 45,
".": 46,
"/": 47,
"0": 48,
"1": 49,
"2": 50,
"3": 51,
"4": 52,
"5": 53,
"6": 54,
"7": 55,
"8": 56,
"9": 57,
":": 58,
";": 59,
"<": 60,
"=": 61,
">": 62,
"?": 63,
"@": 64,
"A": 65,
"B": 66,
"C": 67,
"D": 68,
"E": 69,
"F": 70,
"G": 71,
"H": 72,
"I": 73,
"J": 74,
"K": 75,
"L": 76,
"M": 77,
"N": 78,
"O": 79,
"P": 80,
"Q": 81,
"R": 82,
"S": 83,
"T": 84,
"U": 85,
"V": 86,
"W": 87,
"X": 88,
"Y": 89,
"Z": 90,
"[": 91,
"\\": 92,
"]": 93,
"^": 94,
"_": 95,
"`": 96,
"a": 97,
"b": 98,
"c": 99,
"d": 100,
"e": 101,
"f": 102,
"g": 103,
"h": 104,
"i": 105,
"j": 106,
"k": 107,
"l": 108,
"m": 109,
"n": 110,
"o": 111,
"p": 112,
"q": 113,
"r": 114,
"s": 115,
"t": 116,
"u": 117,
"v": 118,
"w": 119,
"x": 120,
"y": 121,
"z": 122,
"{": 123,
"|": 124,
"}": 125,
"~": 126,
"Delete": 127
};

View File

@ -1,7 +1,8 @@
import {
import {
MemoryHelper,
} from "./memoryhelper.js";
import { CharNumber } from "./charnumber.js";
import { Keymap } from "./keymap.js";
import { MouseButton } from "./mousebutton.js";
import { GamepadButton } from "./gamepadbutton.js";
@ -14,16 +15,16 @@ export class FourCC {
*/
/**
*
* @param {String} a
* @param {String} b
* @param {String} c
* @param {String} d
*
* @param {String} a
* @param {String} b
* @param {String} c
* @param {String} d
*/
constructor(a, b, c, d) {
this._code = (a.charCodeAt() << 24)
| (b.charCodeAt() << 16)
| (c.charCodeAt() << 8)
this._code = (a.charCodeAt() << 24)
| (b.charCodeAt() << 16)
| (c.charCodeAt() << 8)
| d.charCodeAt();
}
@ -39,37 +40,37 @@ export class FourCC {
export class InputDevice {
/**
*
*
* name;
* layout;
* deviceId;
* variants;
* usages;
* description;
*
*
* _inputState;
*/
/**
*
* @param {Number} name
* @param {String} layout
* @param {Number} deviceId
* @param {String} variants
* @param {Object} description
*
* @param {Number} name
* @param {String} layout
* @param {Number} deviceId
* @param {String[]} usages
* @param {Object} description
*/
constructor(name, layout, deviceId, variants, description) {
constructor(name, layout, deviceId, usages, description) {
this.name = name;
this.layout = layout;
this.deviceId = deviceId;
this.variants = variants;
this.usages = usages;
this.description = description;
this._inputState = null;
}
/**
*
* @param {IInputState} state
*
* @param {IInputState} state
*/
updateState(state) {
this._inputState = state;
@ -78,7 +79,7 @@ export class InputDevice {
queueEvent(event) {
throw new Error(`Please implement this method. event:${event}`);
}
/**
* @returns {IInputState}
*/
@ -89,7 +90,7 @@ export class InputDevice {
export class Mouse extends InputDevice {
/**
* @param {(MouseEvent|WheelEvent)} event
* @param {(MouseEvent|WheelEvent)} event
*/
queueEvent(event) {
this.updateState(new MouseState(event));
@ -99,8 +100,8 @@ export class Mouse extends InputDevice {
export class Keyboard extends InputDevice {
static get keycount() { return 110; }
/**
*
* @param {KeyboardEvent} event
*
* @param {KeyboardEvent} event
*/
queueEvent(event) {
this.updateState(new KeyboardState(event, this.currentState));
@ -109,7 +110,7 @@ export class Keyboard extends InputDevice {
export class Touchscreen extends InputDevice {
/**
* @param {TouchScreenEvent} event
* @param {TouchScreenEvent} event
*/
queueEvent(event, time) {
this.updateState(new TouchscreenState(event, this.currentState, time));
@ -118,7 +119,7 @@ export class Touchscreen extends InputDevice {
export class Gamepad extends InputDevice {
/**
* @param {GamepadButtonEvent | GamepadAxisEvent} event
* @param {GamepadButtonEvent | GamepadAxisEvent} event
*/
queueEvent(event) {
this.updateState(new GamepadState(event));
@ -129,29 +130,29 @@ export class InputEvent {
static get invalidEventId() { return 0; }
static get size() { return 20; }
/**
/**
* field offset 0
* @member {Number} type;
*
*
* field offset 4
* @member {Number} sizeInBytes;
*
*
* field offset 6
* @member {Number} deviceId;
*
*
* field offset 8
* @member {Number} time;
*
*
* field offset 16
* @member {Number} eventId;
*/
/**
*
* @param {Number} type
*
* @param {Number} type
* @param {Number} sizeInBytes
* @param {Number} deviceId
* @param {Number} time
* @param {Number} deviceId
* @param {Number} time
*/
constructor(type, sizeInBytes, deviceId, time) {
this.type = type;
@ -187,7 +188,7 @@ export class IInputState {
* @returns {Number}
*/
get format() {
throw new Error('Please implement this field');
throw new Error('Please implement this field');
}
}
@ -198,29 +199,29 @@ export class MouseState extends IInputState {
/**
* field offset 0
* @member {Array} position;
*
*
* field offset 8
* @member {Array} delta;
*
*
* field offset 16
* @member {Array} scroll;
*
*
* field offset 24
* @member {ArrayBuffer} buttons;
*
*
* field offset 26
* @member {Array} displayIndex;
*
*
* field offset 28
* @member {Array} clickCount;
*/
/**
* @param {MouseEvent | WheelEvent} event
* @param {MouseEvent | WheelEvent} event
*/
constructor(event) {
super();
this.position = [event.clientX, event.clientY];
this.delta = [event.movementX, -event.movementY];
this.scroll = [0, 0];
@ -281,7 +282,7 @@ export class KeyboardState extends IInputState {
*/
/**
* @param {KeyboardEvent} event
* @param {KeyboardEvent} event
*/
constructor(event, state) {
super();
@ -323,7 +324,7 @@ export class KeyboardState extends IInputState {
export class TouchState {
static get format() { return new FourCC('T', 'O', 'U', 'C').toInt32(); }
static get size() { return 56; }
static incrementTouchId() {
static incrementTouchId() {
if(TouchState._currentTouchId === undefined) {
TouchState._currentTouchId = 0;
}
@ -332,7 +333,7 @@ export class TouchState {
static prevTouches() {
if(TouchState._prevTouches === undefined) {
// max touch count is 10
TouchState._prevTouches = new Array(10);
TouchState._prevTouches = new Array(10);
}
return TouchState._prevTouches;
}
@ -366,42 +367,24 @@ export class TouchState {
/**
* @param {Touch} touch
* @param {TouchState} state
* @param {String} type
* @param {Touch} touchId
* @param {TouchState} prevState
* @param {Number[]} position
* @param {Number} pressure
* @param {Number[]} radius
* @param {TouchPhase} phaseId
* @param {Number} time
*/
constructor(touch, type, time) {
let phaseId = TouchPhase.Stationary;
switch(type) {
case 'touchstart':
phaseId = TouchPhase.Began; break;
case 'touchend':
phaseId = TouchPhase.Ended; break;
case 'touchmove':
phaseId = TouchPhase.Moved; break;
case 'touchcancel':
phaseId = TouchPhase.Canceled; break;
}
let touchId = 0;
let state = null;
if(phaseId == TouchPhase.Began) {
touchId = TouchState.incrementTouchId();
}
else {
state = TouchState.prevTouches[touch.identifier];
touchId = state.touchId;
}
constructor(touchId, prevState, position, pressure, radius, phaseId, time) {
this.touchId = touchId;
this.position = [touch.pageX, -touch.pageY];
this.position = position != null ? position.slice() : null;
if(phaseId == TouchPhase.Moved) {
this.delta = [this.position[0] - state.position[0], this.position[1] - state.position[1]];
this.delta = [this.position[0] - prevState.position[0], this.position[1] - prevState.position[1]];
} else {
this.delta = [0, 0];
}
this.pressure = touch.force;
this.radius = [touch.radiusX, touch.radiusY];
this.pressure = pressure;
this.radius = radius != null ? radius.slice(): null;
this.phaseId = phaseId;
this.tapCount = 0;
this.displayIndex = 0;
@ -411,12 +394,27 @@ export class TouchState {
this.startTime = time;
this.startPosition = this.position.slice();
} else {
this.startTime = state.startTime;
this.startPosition = state.startPosition.slice();
this.startTime = prevState != null ? prevState.startTime : null;
this.startPosition = prevState != null ? prevState.startPosition.slice() : null;
}
}
// cache state
TouchState.prevTouches[touch.identifier] = this;
copy() {
let state = new TouchState();
state.touchId = this.touchId;
state.position = this.position.slice();
state.delta = this.delta.slice();
state.pressure = this.pressure;
state.radius = this.radius.slice();
state.phaseId = this.phaseId;
state.tapCount = this.tapCount;
state.displayIndex = this.displayIndex;
state.flags = this.flags;
state.padding = this.padding;
state.startTime = this.startTime;
state.startPosition = this.startPosition.slice();
return state;
}
/**
@ -451,12 +449,26 @@ export class TouchState {
*/
get format() {
return TouchState.format;
}
}
}
export class TouchscreenState extends IInputState {
static get maxTouches() { return 10; }
static get maxTouches() { return 10; }
static get format() { return new FourCC('T', 'S', 'C', 'R').toInt32(); }
static convertPhaseId(type) {
let phaseId = TouchPhase.Stationary;
switch(type) {
case 'touchstart':
phaseId = TouchPhase.Began; break;
case 'touchend':
phaseId = TouchPhase.Ended; break;
case 'touchmove':
phaseId = TouchPhase.Moved; break;
case 'touchcancel':
phaseId = TouchPhase.Canceled; break;
}
return phaseId;
}
/**
* @param {TouchEvent} event
@ -467,6 +479,7 @@ export class TouchscreenState extends IInputState {
super();
switch(event.type) {
// `click` event is called when releasing mouse button or finger on screen.
case 'click' : {
this.touchData = new Array(state.touchData.length);
for(let i = 0; i < state.touchData.length; i++) {
@ -482,7 +495,21 @@ export class TouchscreenState extends IInputState {
let touches = event.changedTouches;
this.touchData = new Array(touches.length);
for(let i = 0; i < touches.length; i++) {
this.touchData[i] = new TouchState(touches[i], event.type, time);
const touch = touches[i];
const position = [touch.clientX, touch.clientY];
const phaseId = TouchscreenState.convertPhaseId(event.type);
const pressure = touch.force;
const radius = [touch.radiusX, touch.radiusY];
// `touchId` in InputSystem must be set uniquely.
// The numbers of `touch.identifier` in Web API are reused, so these are not unique.
const touchId = phaseId == TouchPhase.Began ? TouchState.incrementTouchId() : TouchState.prevTouches()[touch.identifier].touchId;
const prevState = phaseId != TouchPhase.Began ? TouchState.prevTouches()[touch.identifier] : null;
const touchData = new TouchState(touchId, prevState, position, pressure, radius, phaseId, time);
// cache state
TouchState.prevTouches()[touch.identifier] = touchData;
this.touchData[i] = touchData;
}
break;
}
@ -513,27 +540,27 @@ export class TouchscreenState extends IInputState {
export class GamepadState extends IInputState {
static get size() { return 28; }
static get format() { return new FourCC('G', 'P', 'A', 'D').toInt32(); }
/**
* field offset 0
* @member buttons;
*
*
* field offset 4
* @member leftStick;
*
*
* field offset 12
* @member rightStick;
*
*
* field offset 20
* @member leftTrigger;
*
*
* field offset 24
* @member rightTrigger;
*/
/**
*
* @param {GamepadButtonEvent | GamepadAxisEvent} event
*
* @param {GamepadButtonEvent | GamepadAxisEvent} event
*/
constructor(event) {
super();
@ -545,7 +572,7 @@ export class GamepadState extends IInputState {
this.rightStick = [ gamepad.axes[2], -gamepad.axes[3] ];
this.leftTrigger = buttons[6].value;
this.rightTrigger = buttons[7].value;
// see https://w3c.github.io/gamepad/#remapping
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.A, buttons[0].pressed);
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.B, buttons[1].pressed);
@ -562,7 +589,7 @@ export class GamepadState extends IInputState {
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadUp, buttons[12].pressed);
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadDown, buttons[13].pressed);
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadLeft, buttons[14].pressed);
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadRight, buttons[15].pressed);
MemoryHelper.writeSingleBit(this.buttons, GamepadButton.DpadRight, buttons[15].pressed);
}
/**
@ -596,26 +623,26 @@ export class TextEvent {
/**
* field offset 0
* @member {InputEvent} baseEvent;
*
*
* field offset 20
* @member {Number} character;
*/
/**
*
* @param {Number} deviceId
* @param {Number} character
* @param {Number} time
*
* @param {Number} deviceId
* @param {KeyboardEvent} event
* @param {Number} time
* @returns {TextEvent}
*/
static create(deviceId, character, time) {
static create(deviceId, event, time) {
const eventSize = InputEvent.size + MemoryHelper.sizeOfInt;
let event = new TextEvent();
event.baseEvent = new InputEvent(TextEvent.format, eventSize, deviceId, time);
event.character = character;
return event;
let textEvent = new TextEvent();
textEvent.baseEvent = new InputEvent(TextEvent.format, eventSize, deviceId, time);
textEvent.character = CharNumber[event.key];
return textEvent;
}
/**
@ -638,18 +665,18 @@ export class StateEvent {
/**
* field offset 0
* @member {InputEvent} baseEvent;
*
*
* field offset 20
* @member {Number} stateFormat;
*
*
* field offset 24
* @member {ArrayBuffer} stateData;
*/
/**
*
* @param {InputDevice} device
* @param {Number} time
*
* @param {InputDevice} device
* @param {Number} time
* @returns {StateEvent}
*/
static from(device, time) {
@ -657,16 +684,16 @@ export class StateEvent {
}
/**
*
* @param {IInputState} state
*
* @param {IInputState} state
* @param {Number} deviceId
* @param {Number} time
* @param {Number} time
*/
static fromState(state, deviceId, time) {
const stateData = state.buffer;
const stateSize = stateData.byteLength;
const eventSize = InputEvent.size + MemoryHelper.sizeOfInt + stateSize;
let stateEvent = new StateEvent();
stateEvent.baseEvent = new InputEvent(StateEvent.format, eventSize, deviceId, time);
stateEvent.stateFormat = state.format;
@ -688,4 +715,4 @@ export class StateEvent {
uint8View.set(new Uint8Array(this.stateData), InputEvent.size+MemoryHelper.sizeOfInt);
return _buffer;
}
}
}

View File

@ -180,7 +180,7 @@ export default class Peer extends EventTarget {
try {
await this.pc.addIceCandidate(candidate);
} catch (e) {
if (this.pc && !this.ignoreOffer)
if (this.pc && !this.ignoreOffer)
this.warn(`${this.pc} this candidate can't accept current signaling state ${this.pc.signalingState}.`);
}
}

View File

@ -5,12 +5,12 @@ export const LetterBoxType = {
export class PointerCorrector {
/**
* @param {Number} videoWidth
* @param {Number} videoWidth
* @param {Number} videoHeight
* @param {DOMRect} rect
* @param {HTMLVideoElement} videoElem
*/
constructor(videoWidth, videoHeight, rect) {
this.reset(videoWidth, videoHeight, rect);
constructor(videoWidth, videoHeight, videoElem) {
this.reset(videoWidth, videoHeight, videoElem);
}
/**
@ -18,14 +18,15 @@ export class PointerCorrector {
* @returns {Number[]}
*/
map(position) {
var rect = this._videoElem.getBoundingClientRect();
const _position = new Array(2);
// (1) set origin point to zero
_position[0] = position[0] - this._rect.left;
_position[1] = position[1] - this._rect.top;
_position[0] = position[0] - rect.left;
_position[1] = position[1] - rect.top;
// (2) translate Unity coordinate system (reverse y-axis)
_position[1] = this._rect.height - _position[1];
_position[1] = rect.height - _position[1];
// (3) add offset of letterbox
_position[0] -= this._contentRect.x;
@ -55,42 +56,44 @@ export class PointerCorrector {
}
/**
* @param {DOMRect} rect
* @param {HTMLVideoElement} videoElem
*/
setRect(rect) {
this._rect = rect;
setRect(videoElem) {
this._videoElem = videoElem;
this._reset();
}
/**
* @param {Number} videoWidth
* @param {Number} videoWidth
* @param {Number} videoHeight
* @param {DOMRect} rect
* @param {HTMLVideoElement} videoElem
*/
reset(videoWidth, videoHeight, rect) {
reset(videoWidth, videoHeight, videoElem) {
this._videoWidth = videoWidth;
this._videoHeight = videoHeight;
this._rect = rect;
this._videoElem = videoElem;
this._reset();
}
get letterBoxType() {
const videoRatio = this._videoHeight / this._videoWidth;
const rectRatio = this._rect.height / this._rect.width;
var rect = this._videoElem.getBoundingClientRect();
const rectRatio = rect.height / rect.width;
return videoRatio > rectRatio ? LetterBoxType.Vertical : LetterBoxType.Horizontal;
}
get letterBoxSize() {
var rect = this._videoElem.getBoundingClientRect();
switch(this.letterBoxType) {
case LetterBoxType.Horizontal: {
const ratioWidth = this._rect.width / this._videoWidth;
const ratioWidth = rect.width / this._videoWidth;
const height = this._videoHeight * ratioWidth;
return (this._rect.height - height) * 0.5;
return (rect.height - height) * 0.5;
}
case LetterBoxType.Vertical: {
const ratioHeight = this._rect.height / this._videoHeight;
const ratioHeight = rect.height / this._videoHeight;
const width = this._videoWidth * ratioHeight;
return (this._rect.width - width) * 0.5;
return (rect.width - width) * 0.5;
}
}
throw 'invalid status';
@ -99,16 +102,18 @@ export class PointerCorrector {
/**
* Returns rectangle for displaying video with the origin at the left-top of the element.
* Not considered applying CSS like `object-fit`.
* @returns {Object}
*/
* @returns {Object}
*/
get contentRect() {
const letterBoxType = this.letterBoxType;
const letterBoxSize = this.letterBoxSize;
var rect = this._videoElem.getBoundingClientRect();
const x = letterBoxType == LetterBoxType.Vertical ? letterBoxSize : 0;
const y = letterBoxType == LetterBoxType.Horizontal ? letterBoxSize : 0;
const width = letterBoxType == LetterBoxType.Vertical ? this._rect.width - letterBoxSize * 2 : this._rect.width;
const height = letterBoxType == LetterBoxType.Horizontal ? this._rect.height - letterBoxSize * 2 : this._rect.height;
const width = letterBoxType == LetterBoxType.Vertical ? rect.width - letterBoxSize * 2 : rect.width;
const height = letterBoxType == LetterBoxType.Horizontal ? rect.height - letterBoxSize * 2 : rect.height;
return {x: x, y: y, width: width, height: height};
}
@ -116,4 +121,4 @@ export class PointerCorrector {
_reset() {
this._contentRect = this.contentRect;
}
}
}

View File

@ -88,7 +88,7 @@ export class RenderStreaming {
/**
* if not set argument, a generated uuid is used.
* @param {string | null} connectionId
* @param {string | null} connectionId
*/
async createConnection(connectionId) {
this._connectionId = connectionId ? connectionId : uuid4();
@ -150,7 +150,7 @@ export class RenderStreaming {
}
/**
* @param {string} label
* @param {string} label
* @returns {RTCDataChannel | null}
*/
createDataChannel(label) {
@ -158,13 +158,23 @@ export class RenderStreaming {
}
/**
* @param {MediaStreamTrack} track
* @param {MediaStreamTrack} track
* @returns {RTCRtpSender | null}
*/
addTrack(track) {
return this._peer.addTrack(this._connectionId, track);
}
/**
* @param {MediaStreamTrack | string} trackOrKind
* @param {RTCRtpTransceiverInit | null} init
* @returns {RTCRtpTransceiver | null}
*/
addTransceiver(trackOrKind, init) {
return this._peer.addTransceiver(this._connectionId, trackOrKind, init);
}
/**
* @returns {RTCRtpTransceiver[] | null}
*/

View File

@ -1,4 +1,4 @@
import {
import {
Mouse,
Keyboard,
Gamepad,
@ -19,7 +19,7 @@ export class Sender extends LocalInputManager {
this._corrector = new PointerCorrector(
this._elem.videoWidth,
this._elem.videoHeight,
this._elem.getBoundingClientRect()
this._elem
);
//since line 27 cannot complete resize initialization but can only monitor div dimension changes, line 26 needs to be reserved
@ -36,9 +36,9 @@ export class Sender extends LocalInputManager {
m_Product: "",
m_Serial: "",
m_Version: "",
m_Capabilities: ""
};
this.mouse = new Mouse("Mouse", "Mouse", 1, "", descriptionMouse);
m_Capabilities: ""
};
this.mouse = new Mouse("Mouse", "Mouse", 1, null, descriptionMouse);
this._devices.push(this.mouse);
this._elem.addEventListener('click', this._onMouseEvent.bind(this), false);
@ -56,9 +56,9 @@ export class Sender extends LocalInputManager {
m_Product: "",
m_Serial: "",
m_Version: "",
m_Capabilities: ""
m_Capabilities: ""
};
this.keyboard = new Keyboard("Keyboard", "Keyboard", 2, "", descriptionKeyboard);
this.keyboard = new Keyboard("Keyboard", "Keyboard", 2, null, descriptionKeyboard);
this._devices.push(this.keyboard);
document.addEventListener('keyup', this._onKeyEvent.bind(this), false);
@ -75,12 +75,12 @@ export class Sender extends LocalInputManager {
m_Version: "",
m_Capabilities: ""
};
this.gamepad = new Gamepad("Gamepad", "Gamepad", 3, "", descriptionGamepad);
this.gamepad = new Gamepad("Gamepad", "Gamepad", 3, null, descriptionGamepad);
this._devices.push(this.gamepad);
window.addEventListener("gamepadconnected", this._onGamepadEvent.bind(this), false);
window.addEventListener("gamepaddisconnected", this._onGamepadEvent.bind(this), false);
this._gamepadHandler = new GamepadHandler();
this._gamepadHandler = new GamepadHandler();
this._gamepadHandler.addEventListener("gamepadupdated", this._onGamepadEvent.bind(this), false);
}
@ -92,9 +92,9 @@ export class Sender extends LocalInputManager {
m_Product: "",
m_Serial: "",
m_Version: "",
m_Capabilities: ""
m_Capabilities: ""
};
this.touchscreen = new Touchscreen("Touchscreen", "Touchscreen", 4, "", descriptionTouch);
this.touchscreen = new Touchscreen("Touchscreen", "Touchscreen", 4, null, descriptionTouch);
this._devices.push(this.touchscreen);
this._elem.addEventListener('touchend', this._onTouchEvent.bind(this), false);
@ -115,7 +115,7 @@ export class Sender extends LocalInputManager {
this._corrector.reset(
this._elem.videoWidth,
this._elem.videoHeight,
this._elem.getBoundingClientRect()
this._elem
);
}
_onMouseEvent(event) {
@ -134,8 +134,7 @@ export class Sender extends LocalInputManager {
this._queueStateEvent(this.keyboard.currentState, this.keyboard);
}
// TextEvent
const key = event.key.charCodeAt(0);
this._queueTextEvent(this.keyboard, key);
this._queueTextEvent(this.keyboard, event);
}
else if(event.type == 'keyup') {
this.keyboard.queueEvent(event);
@ -145,7 +144,9 @@ export class Sender extends LocalInputManager {
_onTouchEvent(event) {
this.touchscreen.queueEvent(event, this.timeSinceStartup);
for(let touch of this.touchscreen.currentState.touchData) {
this._queueStateEvent(touch, this.touchscreen);
let clone = touch.copy();
clone.position = this._corrector.map(clone.position);
this._queueStateEvent(clone, this.touchscreen);
}
}
_onGamepadEvent(event) {
@ -160,21 +161,21 @@ export class Sender extends LocalInputManager {
}
case 'gamepadupdated': {
this.gamepad.queueEvent(event);
this._queueStateEvent(this.gamepad.currentState, this.gamepad);
this._queueStateEvent(this.gamepad.currentState, this.gamepad);
break;
}
}
}
_queueStateEvent(state, device) {
const stateEvent =
const stateEvent =
StateEvent.fromState(state, device.deviceId, this.timeSinceStartup);
const e = new CustomEvent(
'event', {detail: { event: stateEvent, device: device}});
super.onEvent.dispatchEvent(e);
}
_queueTextEvent(device, character) {
const textEvent = TextEvent.create(device.deviceId, character, this.timeSinceStartup);
_queueTextEvent(device, event) {
const textEvent = TextEvent.create(device.deviceId, event, this.timeSinceStartup);
const e = new CustomEvent(
'event', {detail: { event: textEvent, device: device}});
super.onEvent.dispatchEvent(e);
@ -188,15 +189,15 @@ export class Sender extends LocalInputManager {
export class Observer {
/**
*
* @param {RTCDataChannel} channel
*
* @param {RTCDataChannel} channel
*/
constructor(channel) {
this.channel = channel;
this.channel = channel;
}
/**
*
* @param {Message} message
*
* @param {Message} message
*/
onNext(message) {
if(this.channel == null || this.channel.readyState != 'open') {
@ -204,4 +205,4 @@ export class Observer {
}
this.channel.send(message.buffer);
}
}
}

View File

@ -2,9 +2,10 @@ import * as Logger from "./logger.js";
export class Signaling extends EventTarget {
constructor() {
constructor(interval = 1000) {
super();
this.running = false;
this.interval = interval;
this.sleep = msec => new Promise(resolve => setTimeout(resolve, msec));
}
@ -17,10 +18,6 @@ export class Signaling extends EventTarget {
}
}
get interval() {
return 1000;
}
url(method, parameter='') {
let ret = location.origin + '/signaling';
if(method)
@ -53,9 +50,9 @@ export class Signaling extends EventTarget {
let lastTimeRequest = Date.now() - 30000;
while (this.running) {
const res = await this.getAll(lastTimeRequest);
lastTimeRequest = Date.parse(res.headers.get('Date'));
const data = await res.json();
lastTimeRequest = data.datetime ? data.datetime : Date.now();
const messages = data.messages;
for(const msg of messages) {
@ -76,94 +73,8 @@ export class Signaling extends EventTarget {
break;
default:
break;
}
}
await this.sleep(this.interval);
}
}
async loopGetConnection() {
let currentConnections = new Set();
while (this.running) {
const res = await this.getConnection();
const data = await res.json();
const connections = data.connections;
Logger.log('get connections:', connections);
const newSet = new Set();
connections.forEach(e => newSet.add(e.connectionId));
const deleteConnection = new Set([...currentConnections].filter(e => (!newSet.has(e))));
deleteConnection.forEach(connection => {
this.dispatchEvent(new CustomEvent('disconnect', { detail: { connectionId: connection } }));
currentConnections.delete(connection);
});
newSet.forEach(e => currentConnections.add(e));
await this.sleep(this.interval);
}
}
async loopGetOffer() {
let lastTimeRequest = Date.now() - 30000;
while (this.running) {
const res = await this.getOffer(lastTimeRequest);
lastTimeRequest = Date.parse(res.headers.get('Date'));
const data = await res.json();
const offers = data.offers;
Logger.log('get offers:', offers);
offers.forEach(offer => {
this.dispatchEvent(new CustomEvent('offer', { detail: offer }));
});
await this.sleep(this.interval);
}
}
async loopGetAnswer() {
// receive answer message from 30secs ago
let lastTimeRequest = Date.now() - 30000;
while (this.running) {
const res = await this.getAnswer(lastTimeRequest);
lastTimeRequest = Date.parse(res.headers.get('Date'));
const data = await res.json();
const answers = data.answers;
Logger.log('get answers:', answers);
answers.forEach(answer => {
this.dispatchEvent(new CustomEvent('answer', { detail: answer }));
});
await this.sleep(this.interval);
}
}
async loopGetCandidate() {
// receive answer message from 30secs ago
let lastTimeRequest = Date.now() - 30000;
while (this.running) {
const res = await this.getCandidate(lastTimeRequest);
lastTimeRequest = Date.parse(res.headers.get('Date'));
const data = await res.json();
const candidates = data.candidates;
Logger.log('get candidates:', candidates);
if (candidates.length > 0) {
const connectionId = candidates[0].connectionId;
for (let candidate of candidates[0].candidates) {
const dispatch = { connectionId: connectionId, candidate: candidate.candidate, sdpMLineIndex: candidate.sdpMLineIndex, sdpMid: candidate.sdpMid };
this.dispatchEvent(new CustomEvent('candidate', { detail: dispatch }));
}
}
await this.sleep(this.interval);
}
}
@ -215,22 +126,6 @@ export class Signaling extends EventTarget {
await fetch(this.url('candidate'), { method: 'POST', headers: this.headers(), body: JSON.stringify(data) });
}
async getConnection() {
return await fetch(this.url(`connection`), { method: 'GET', headers: this.headers() });
}
async getOffer(fromTime = 0) {
return await fetch(this.url(`offer`, `fromtime=${fromTime}`), { method: 'GET', headers: this.headers() });
}
async getAnswer(fromTime = 0) {
return await fetch(this.url(`answer`, `fromtime=${fromTime}`), { method: 'GET', headers: this.headers() });
}
async getCandidate(fromTime = 0) {
return await fetch(this.url(`candidate`, `fromtime=${fromTime}`), { method: 'GET', headers: this.headers() });
}
async getAll(fromTime = 0) {
return await fetch(this.url(``, `fromtime=${fromTime}`), { method: 'GET', headers: this.headers() });
}
@ -238,8 +133,9 @@ export class Signaling extends EventTarget {
export class WebSocketSignaling extends EventTarget {
constructor() {
constructor(interval = 1000) {
super();
this.interval = interval;
this.sleep = msec => new Promise(resolve => setTimeout(resolve, msec));
let websocketUrl;
@ -290,10 +186,6 @@ export class WebSocketSignaling extends EventTarget {
};
}
get interval() {
return 100;
}
async start() {
while (!this.isWsOpen) {
await this.sleep(100);
@ -344,4 +236,4 @@ export class WebSocketSignaling extends EventTarget {
Logger.log(sendJson);
this.websocket.send(sendJson);
}
}
}

View File

@ -4,4 +4,4 @@ export const TouchFlags =
PrimaryTouch: 1 << 4,
Tap: 1 << 5,
OrphanedPrimaryTouch: 1 << 6,
};
};

View File

@ -5,4 +5,4 @@ export const TouchPhase = {
Ended: 3,
Canceled: 4,
Stationary: 5
};
};

View File

@ -0,0 +1,11 @@
// mock class
export class DOMHTMLVideoElement {
constructor(rect) {
this.rect = rect;
}
getBoundingClientRect() {
return this.rect;
}
}

View File

@ -25,15 +25,15 @@ describe(`MouseState`, () => {
let event;
beforeEach(() => {
event = new MouseEvent('click', { buttons:1, clientX:0, clientY:0});
});
});
test('format', () => {
const format = new MouseState(event).format;
expect(format).toBe(0x4d4f5553);
});
});
test('buffer', () => {
const state = new MouseState(event);
expect(state.buffer.byteLength).toBeGreaterThan(0);
});
});
});
describe(`with WheelEvent`, () => {
let event;
@ -43,11 +43,11 @@ describe(`MouseState`, () => {
test('format', () => {
const format = new MouseState(event).format;
expect(format).toBe(0x4d4f5553);
});
});
test('buffer', () => {
const state = new MouseState(event);
expect(state.buffer.byteLength).toBeGreaterThan(0);
});
});
});
});
@ -59,7 +59,7 @@ describe(`KeyboardState`, () => {
test('format', () => {
const format = new KeyboardState(event).format;
expect(format).toBe(0x4b455953);
});
});
test('buffer', () => {
const state = new KeyboardState(event);
expect(state.buffer.byteLength).toBeGreaterThan(0);
@ -69,7 +69,7 @@ describe(`KeyboardState`, () => {
describe(`TouchscreenState`, () => {
let event;
beforeEach(() => {
event = new TouchEvent("touchstart", {
event = new TouchEvent("touchstart", {
changedTouches: [{ // InputInit
identifier: 0,
target: null,
@ -88,7 +88,7 @@ describe(`TouchscreenState`, () => {
touchType: "direct"
}]
});
});
});
test('format', () => {
const format = new TouchscreenState(event, null, Date.now()).format;
expect(format).toBe(0x54534352);
@ -113,7 +113,7 @@ describe(`GamepadState`, () => {
test('format', () => {
const format = new GamepadState(event).format;
expect(format).toBe(0x47504144);
});
});
test('buffer', () => {
const state = new GamepadState(event);
expect(state.buffer.byteLength).toBeGreaterThan(0);
@ -134,14 +134,15 @@ describe(`StateEvent`, () => {
describe(`TextEvent`, () => {
test('buffer', () => {
const character = 0x41;
const textEvent = TextEvent.create(0, character, Date.now());
const event = new KeyboardEvent('keydown', { code: 'KeyA', key: "a"});
const textEvent = TextEvent.create(0, event, Date.now());
expect(new Int32Array(textEvent.buffer.slice(0, 4))[0]).toBe(TextEvent.format);
const offset = InputEvent.size;
expect(new Uint32Array(textEvent.buffer.slice(offset, offset+4))[0]).toBe(character);
// 'a' is 97
expect(new Uint32Array(textEvent.buffer.slice(offset, offset+4))[0]).toBe(97);
});
});
describe(`Mouse`, () => {
test('alignedSizeInBytes', () => {
let device = new Mouse("Mouse", "Mouse", 1, null, null);
@ -168,4 +169,4 @@ describe(`Gamepad`, () => {
let device = new Gamepad("Gamepad", "Gamepad", 1, null, null);
expect(device).toBeInstanceOf(Gamepad);
});
});
});

View File

@ -9,8 +9,9 @@ export function reset(isPrivate) {
export class MockSignaling extends EventTarget {
get interval() {
return 100;
constructor(interval = 1000) {
super();
this.interval = interval;
}
async start() {
@ -115,7 +116,7 @@ class MockPrivateSignalingManager {
constructor() {
// structure Map<string:connectionId, Set<MockSignaling>> connectionIds
this.connectionIds = new Map();
this.delay = () => new Promise(resolve => setTimeout(resolve, 10));
this.delay = async () => await sleep(10);
}
async add(signaling) {

View File

@ -1,26 +1,30 @@
import {
import {
LetterBoxType,
PointerCorrector
} from "../src/pointercorrect.js";
import {DOMRect} from "./domrect.js";
import {DOMHTMLVideoElement} from "./domvideoelement.js";
describe(`PointerCorrector.map`, () => {
test('letterboxType', () => {
const rect = new DOMRect(10, 10, 200, 200);
let corrector = new PointerCorrector(50, 100, rect);
const element = new DOMHTMLVideoElement(rect);
let corrector = new PointerCorrector(50, 100, element);
expect(corrector.letterBoxType).toBe(LetterBoxType.Vertical);
corrector.reset(100, 50, rect);
corrector.reset(100, 50, element);
expect(corrector.letterBoxType).toBe(LetterBoxType.Horizontal);
});
test('letterboxSize', () => {
const rect = new DOMRect(0, 0, 100, 100);
let corrector = new PointerCorrector(50, 100, rect);
const element = new DOMHTMLVideoElement(rect);
let corrector = new PointerCorrector(50, 100, element);
expect(corrector.letterBoxSize).toBe(25);
});
test('contentRect', () => {
const rect = new DOMRect(0, 0, 100, 100);
let corrector = new PointerCorrector(50, 100, rect);
const element = new DOMHTMLVideoElement(rect);
let corrector = new PointerCorrector(50, 100, element);
expect(corrector.contentRect.x).toBe(25);
expect(corrector.contentRect.y).toBe(0);
expect(corrector.contentRect.width).toBe(50);
@ -28,13 +32,14 @@ describe(`PointerCorrector.map`, () => {
});
test('mapping', () => {
const rect = new DOMRect(10, 10, 200, 200);
const element = new DOMHTMLVideoElement(rect);
const videoWidth = 100;
const videoHeight = 100;
let corrector = new PointerCorrector(videoWidth, videoHeight, rect);
let corrector = new PointerCorrector(videoWidth, videoHeight, element);
const position = [10, 10];
const newPosition = corrector.map(position);
expect(newPosition[0]).toBe(0);
expect(newPosition[1]).toBe(100);
});
});
});

View File

@ -23,25 +23,25 @@ describe.each([
beforeAll(async () => {
if (mode == "mock") {
reset(false);
signaling1 = new MockSignaling();
signaling2 = new MockSignaling();
signaling1 = new MockSignaling(1);
signaling2 = new MockSignaling(1);
} else {
const path = Path.resolve(`../bin~/${serverExeName()}`);
let cmd = `${path} -p ${portNumber}`;
if (mode == "websocket") {
cmd += " -w";
if (mode == "http") {
cmd += " -t http";
}
await setup({ command: cmd, port: portNumber, usedPortAction: 'error' });
if (mode == "http") {
signaling1 = new Signaling();
signaling2 = new Signaling();
signaling1 = new Signaling(1);
signaling2 = new Signaling(1);
}
if (mode == "websocket") {
signaling1 = new WebSocketSignaling();
signaling2 = new WebSocketSignaling();
signaling1 = new WebSocketSignaling(1);
signaling2 = new WebSocketSignaling(1);
}
}
@ -221,27 +221,27 @@ describe.each([
beforeAll(async () => {
if (mode == "mock") {
reset(true);
signaling1 = new MockSignaling();
signaling2 = new MockSignaling();
signaling1 = new MockSignaling(1);
signaling2 = new MockSignaling(1);
return;
}
const path = Path.resolve(`../bin~/${serverExeName()}`);
let cmd = `${path} -p ${portNumber} -m private`;
if (mode == "websocket") {
cmd += " -w";
if (mode == "http") {
cmd += " -t http";
}
await setup({ command: cmd, port: portNumber, usedPortAction: 'error' });
if (mode == "http") {
signaling1 = new Signaling();
signaling2 = new Signaling();
signaling1 = new Signaling(1);
signaling2 = new Signaling(1);
}
if (mode == "websocket") {
signaling1 = new WebSocketSignaling();
signaling2 = new WebSocketSignaling();
signaling1 = new WebSocketSignaling(1);
signaling2 = new WebSocketSignaling(1);
}
await signaling1.start();
@ -455,6 +455,7 @@ describe.each([
signaling1.addEventListener('offer', (e) => offerRes1 = e.detail);
signaling2.addEventListener('offer', (e) => offerRes2 = e.detail);
await signaling1.sendOffer(connectionId, testsdp);
await waitFor(() => offerRes2 != null);
await sleep(signaling1.interval * 2);
expect(offerRes1).toBeUndefined();
expect(offerRes2).not.toBeUndefined();
@ -464,6 +465,7 @@ describe.each([
signaling1.addEventListener('answer', (e) => answerRes1 = e.detail);
signaling2.addEventListener('answer', (e) => answerRes2 = e.detail);
await signaling2.sendAnswer(connectionId, testsdp);
await waitFor(() => answerRes1 != null);
await sleep(signaling2.interval * 2);
expect(answerRes1).not.toBeUndefined();
expect(answerRes1.connectionId).toBe(connectionId);

3570
WebApp/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -15,6 +15,7 @@
"@types/express": "^4.17.13",
"@types/node": "^18.7.15",
"@types/ws": "^8.5.3",
"cors": "^2.8.5",
"debug": "~4.3.4",
"express": "~4.18.1",
"morgan": "^1.10.0",
@ -23,7 +24,7 @@
},
"devDependencies": {
"@jest-mock/express": "^2.0.1",
"@types/jest": "^29.0.0",
"@types/jest": "^29.0.2",
"@types/morgan": "^1.9.3",
"@typescript-eslint/eslint-plugin": "^5.36.2",
"@typescript-eslint/parser": "^5.36.2",
@ -32,9 +33,9 @@
"jest": "^29.0.2",
"jest-websocket-mock": "^2.4.0",
"mock-socket": "^9.1.5",
"newman": "^5.3.2",
"newman": "^6.0.0",
"pkg": "^5.8.0",
"ts-jest": "^28.0.8",
"ts-jest": "^29.0.2",
"ts-node": "^10.9.1",
"typescript": "^4.8.2"
},
@ -43,7 +44,8 @@
},
"pkg": {
"assets": [
"client/public/**/*"
"client/public/**/*",
"client/src/**/*"
],
"targets": [
"node10"

View File

@ -68,11 +68,11 @@ function checkSessionId(req: Request, res: Response, next): void {
res.sendStatus(404);
return;
}
lastRequestedTime[id] = Date.now();
lastRequestedTime.set(id, Date.now());
next();
}
function _deleteConnection(sessionId:string, connectionId:string) {
function _deleteConnection(sessionId:string, connectionId:string, datetime:number) {
clients.get(sessionId).delete(connectionId);
if(isPrivate) {
@ -83,7 +83,7 @@ function _deleteConnection(sessionId:string, connectionId:string) {
if (clients.has(otherSessionId)) {
clients.get(otherSessionId).delete(connectionId);
const array1 = disconnections.get(otherSessionId);
array1.push(new Disconnection(connectionId, Date.now()));
array1.push(new Disconnection(connectionId, datetime));
}
}
}
@ -91,7 +91,7 @@ function _deleteConnection(sessionId:string, connectionId:string) {
disconnections.forEach((array, id) => {
if (id == sessionId)
return;
array.push(new Disconnection(connectionId, Date.now()));
array.push(new Disconnection(connectionId, datetime));
});
}
@ -101,12 +101,14 @@ function _deleteConnection(sessionId:string, connectionId:string) {
candidates.get(sessionId).delete(connectionId);
const array2 = disconnections.get(sessionId);
array2.push(new Disconnection(connectionId, Date.now()));
array2.push(new Disconnection(connectionId, datetime));
}
function _deleteSession(sessionId: string) {
for(const connectionId of Array.from(clients.get(sessionId))) {
_deleteConnection(sessionId, connectionId);
if(clients.has(sessionId)) {
for(const connectionId of Array.from(clients.get(sessionId))) {
_deleteConnection(sessionId, connectionId, Date.now());
}
}
offers.delete(sessionId);
answers.delete(sessionId);
@ -115,37 +117,32 @@ function _deleteSession(sessionId: string) {
disconnections.delete(sessionId);
}
function _checkDeletedSession(sessionId: string): void {
const connectionIds = Array.from(clients.get(sessionId));
for (const connectionId of connectionIds) {
const pair = connectionPair.get(connectionId);
if (pair == null) {
function _checkForTimedOutSessions(): void {
for (const sessionId of Array.from(clients.keys()))
{
if(!lastRequestedTime.has(sessionId))
continue;
}
const otherSessionId = sessionId === pair[0] ? pair[1] : pair[0];
if(!lastRequestedTime.has(otherSessionId))
if(lastRequestedTime.get(sessionId) > Date.now() - TimeoutRequestedTime)
continue;
if(lastRequestedTime[otherSessionId] > Date.now() - TimeoutRequestedTime)
continue;
_deleteSession(otherSessionId);
console.log("deleted");
_deleteSession(sessionId);
console.log(`deleted sessionId:${sessionId} by timeout.`);
}
}
function _getConnection(sessionId: string): string[] {
_checkDeletedSession(sessionId);
function _getConnection(sessionId: string): string[] {
_checkForTimedOutSessions();
return Array.from(clients.get(sessionId));
}
function _getDisconnection(sessionId: string, fromTime: number): Disconnection[] {
_checkDeletedSession(sessionId);
_checkForTimedOutSessions();
let arrayDisconnections: Disconnection[] = [];
if (disconnections.size != 0 && disconnections.has(sessionId)) {
arrayDisconnections = disconnections.get(sessionId);
}
if (fromTime > 0) {
arrayDisconnections = arrayDisconnections.filter((v) => v.datetime > fromTime);
arrayDisconnections = arrayDisconnections.filter((v) => v.datetime >= fromTime);
}
return arrayDisconnections;
}
@ -165,7 +162,7 @@ function _getOffer(sessionId: string, fromTime: number): [string, Offer][] {
}
if (fromTime > 0) {
arrayOffers = arrayOffers.filter((v) => v[1].datetime > fromTime);
arrayOffers = arrayOffers.filter((v) => v[1].datetime >= fromTime);
}
return arrayOffers;
}
@ -178,7 +175,7 @@ function _getAnswer(sessionId: string, fromTime: number): [string, Answer][] {
}
if (fromTime > 0) {
arrayAnswers = arrayAnswers.filter((v) => v[1].datetime > fromTime);
arrayAnswers = arrayAnswers.filter((v) => v[1].datetime >= fromTime);
}
return arrayAnswers;
}
@ -196,7 +193,7 @@ function _getCandidate(sessionId: string, fromTime: number): [string, Candidate]
continue;
}
const arrayCandidates = candidates.get(otherSessionId).get(connectionId)
.filter((v) => v.datetime > fromTime);
.filter((v) => v.datetime >= fromTime);
if (arrayCandidates.length === 0) {
continue;
}
@ -246,17 +243,18 @@ function getAll(req: Request, res: Response): void {
const answers: [string, Answer][] = _getAnswer(sessionId, fromTime);
const candidates: [string, Candidate][] = _getCandidate(sessionId, fromTime);
const disconnections: Disconnection[] = _getDisconnection(sessionId, fromTime);
const datetime = lastRequestedTime.get(sessionId);
let array: any[] = [];
array = array.concat(connections.map((v) => ({ connectionId: v, type: "connect", datetime: Date.now() })));
array = array.concat(connections.map((v) => ({ connectionId: v, type: "connect", datetime: datetime })));
array = array.concat(offers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, polite: v[1].polite, type: "offer", datetime: v[1].datetime })));
array = array.concat(answers.map((v) => ({ connectionId: v[0], sdp: v[1].sdp, type: "answer", datetime: v[1].datetime })));
array = array.concat(candidates.map((v) => ({ connectionId: v[0], candidate: v[1].candidate, sdpMLineIndex: v[1].sdpMLineIndex, sdpMid: v[1].sdpMid, type: "candidate", datetime: v[1].datetime })));
array = array.concat(disconnections.map((v) => ({ connectionId: v.id, type: "disconnect", datetime: v.datetime })));
array.sort((a, b) => a.datetime - b.datetime);
res.json({ messages: array });
res.json({ messages: array, datetime: datetime });
}
function createSession(sessionId: string, res: Response): void;
@ -281,6 +279,8 @@ function deleteSession(req: Request, res: Response): void {
function createConnection(req: Request, res: Response): void {
const sessionId: string = req.header('session-id');
const { connectionId } = req.body;
const datetime = lastRequestedTime.get(sessionId);
if (connectionId == null) {
res.status(400).send({ error: new Error(`connectionId is required`) });
return;
@ -308,14 +308,15 @@ function createConnection(req: Request, res: Response): void {
const connectionIds = getOrCreateConnectionIds(sessionId);
connectionIds.add(connectionId);
res.json({ connectionId: connectionId, polite: polite, type: "connect", datetime: Date.now() });
res.json({ connectionId: connectionId, polite: polite, type: "connect", datetime: datetime });
}
function deleteConnection(req: Request, res: Response): void {
const sessionId: string = req.header('session-id');
const { connectionId } = req.body;
const datetime = lastRequestedTime.get(sessionId);
_deleteConnection(sessionId, connectionId);
_deleteConnection(sessionId, connectionId, datetime);
res.json({ connectionId: connectionId });
}
@ -323,6 +324,7 @@ function deleteConnection(req: Request, res: Response): void {
function postOffer(req: Request, res: Response): void {
const sessionId: string = req.header('session-id');
const { connectionId } = req.body;
const datetime = lastRequestedTime.get(sessionId);
let keySessionId = null;
let polite = false;
@ -333,17 +335,21 @@ function postOffer(req: Request, res: Response): void {
if (keySessionId != null) {
polite = true;
const map = offers.get(keySessionId);
map.set(connectionId, new Offer(req.body.sdp, Date.now(), polite));
map.set(connectionId, new Offer(req.body.sdp, datetime, polite));
}
}
res.sendStatus(200);
return;
}
connectionPair.set(connectionId, [sessionId, null]);
if(!connectionPair.has(connectionId))
{
connectionPair.set(connectionId, [sessionId, null]);
}
keySessionId = sessionId;
const map = offers.get(keySessionId);
map.set(connectionId, new Offer(req.body.sdp, Date.now(), polite));
map.set(connectionId, new Offer(req.body.sdp, datetime, polite));
res.sendStatus(200);
}
@ -351,6 +357,7 @@ function postOffer(req: Request, res: Response): void {
function postAnswer(req: Request, res: Response): void {
const sessionId: string = req.header('session-id');
const { connectionId } = req.body;
const datetime = lastRequestedTime.get(sessionId);
const connectionIds = getOrCreateConnectionIds(sessionId);
connectionIds.add(connectionId);
@ -373,7 +380,7 @@ function postAnswer(req: Request, res: Response): void {
}
const map = answers.get(otherSessionId);
map.set(connectionId, new Answer(req.body.sdp, Date.now()));
map.set(connectionId, new Answer(req.body.sdp, datetime));
// update datetime for candidates
const mapCandidates = candidates.get(otherSessionId);
@ -381,7 +388,7 @@ function postAnswer(req: Request, res: Response): void {
const arrayCandidates = mapCandidates.get(connectionId);
if (arrayCandidates) {
for (const candidate of arrayCandidates) {
candidate.datetime = Date.now();
candidate.datetime = datetime;
}
}
}
@ -391,13 +398,14 @@ function postAnswer(req: Request, res: Response): void {
function postCandidate(req: Request, res: Response): void {
const sessionId: string = req.header('session-id');
const { connectionId } = req.body;
const datetime = lastRequestedTime.get(sessionId);
const map = candidates.get(sessionId);
if (!map.has(connectionId)) {
map.set(connectionId, []);
}
const arr = map.get(connectionId);
const candidate = new Candidate(req.body.candidate, req.body.sdpMLineIndex, req.body.sdpMid, Date.now());
const candidate = new Candidate(req.body.candidate, req.body.sdpMLineIndex, req.body.sdpMid, datetime);
arr.push(candidate);
res.sendStatus(200);
}

View File

@ -3,7 +3,7 @@ export default interface Options {
port?: number;
keyfile?: string;
certfile?: string;
websocket?: boolean;
type?: string;
mode?: string;
logging?: string;
}
}

View File

@ -16,13 +16,13 @@ export class RenderStreaming {
if (Array.isArray(argv)) {
program
.usage('[options] <apps...>')
.option('-p, --port <n>', 'Port to start the server on', process.env.PORT || `80`)
.option('-s, --secure', 'Enable HTTPS (you need server.key and server.cert)', process.env.SECURE || false)
.option('-k, --keyfile <path>', 'https key file (default server.key)', process.env.KEYFILE || 'server.key')
.option('-c, --certfile <path>', 'https cert file (default server.cert)', process.env.CERTFILE || 'server.cert')
.option('-w, --websocket', 'Enable Websocket Signaling', process.env.WEBSOCKET || false)
.option('-m, --mode <type>', 'Choose Communication mode public or private (default public)', process.env.MODE || 'public')
.option('-l, --logging <type>', 'Choose http logging type combined, dev, short, tiny or none.(default dev)', process.env.LOGGING || 'dev')
.option('-p, --port <n>', 'Port to start the server on.', process.env.PORT || `80`)
.option('-s, --secure', 'Enable HTTPS (you need server.key and server.cert).', process.env.SECURE || false)
.option('-k, --keyfile <path>', 'https key file.', process.env.KEYFILE || 'server.key')
.option('-c, --certfile <path>', 'https cert file.', process.env.CERTFILE || 'server.cert')
.option('-t, --type <type>', 'Type of signaling protocol, Choose websocket or http.', process.env.TYPE || 'websocket')
.option('-m, --mode <type>', 'Choose Communication mode public or private.', process.env.MODE || 'public')
.option('-l, --logging <type>', 'Choose http logging type combined, dev, short, tiny or none.', process.env.LOGGING || 'dev')
.parse(argv);
const option = program.opts();
return {
@ -30,7 +30,7 @@ export class RenderStreaming {
secure: option.secure == undefined ? false : option.secure,
keyfile: option.keyfile,
certfile: option.certfile,
websocket: option.websocket == undefined ? false : option.websocket,
type: option.type == undefined ? 'websocket' : option.type,
mode: option.mode,
logging: option.logging,
};
@ -69,9 +69,17 @@ export class RenderStreaming {
}
});
}
if (this.options.type == 'http') {
console.log(`Use http polling for signaling server.`);
}
else if(this.options.type != 'websocket') {
console.log(`signaling type should be set "websocket" or "http". ${this.options.type} is not supported.`);
console.log(`Changing signaling type to websocket.`);
this.options.type = 'websocket';
}
if (this.options.type == 'websocket') {
console.log(`Use websocket for signaling server ws://${this.getIPAddress()[0]}`);
if (this.options.websocket) {
console.log(`start websocket signaling server ws://${this.getIPAddress()[0]}`);
//Start Websocket Signaling server
new WSSignaling(this.server, this.options.mode);
}
@ -94,4 +102,4 @@ export class RenderStreaming {
}
}
RenderStreaming.run(process.argv);
RenderStreaming.run(process.argv);

View File

@ -7,6 +7,8 @@ import { log, LogLevel } from './log';
import Options from './class/options';
import { reset as resetHandler }from './class/httphandler';
const cors = require('cors');
export const createServer = (config: Options): express.Application => {
const app: express.Application = express();
resetHandler(config.mode);
@ -15,9 +17,10 @@ export const createServer = (config: Options): express.Application => {
app.use(morgan(config.logging));
}
// const signal = require('./signaling');
app.use(cors({origin: '*'}));
app.use(express.urlencoded({ extended: true }));
app.use(express.json());
app.get('/config', (req, res) => res.json({ useWebSocket: config.websocket, startupMode: config.mode, logging: config.logging }));
app.get('/config', (req, res) => res.json({ useWebSocket: config.type == 'websocket', startupMode: config.mode, logging: config.logging }));
app.use('/signaling', signaling);
app.use(express.static(path.join(__dirname, '../client/public')));
app.use('/module', express.static(path.join(__dirname, '../client/src')));

View File

@ -1,9 +1,12 @@
import { getMockReq, getMockRes } from '@jest-mock/express';
import * as httpHandler from '../src/class/httphandler';
const RetriesToForceTimeout = 11; // Waits a second each time, timeout is 10 sec for httphandler.
describe('http signaling test in public mode', () => {
const sessionId = "abcd1234";
const sessionId2 = "abcd5678";
const sessionId3 = "abcd9101112";
const connectionId = "12345";
const connectionId2 = "67890";
const testsdp = "test sdp";
@ -11,6 +14,7 @@ describe('http signaling test in public mode', () => {
const { res, next, mockClear } = getMockRes();
const req = getMockReq({ header: jest.fn(() => sessionId) });
const req2 = getMockReq({ header: jest.fn(() => sessionId2) });
const req3 = getMockReq({ header: jest.fn(() => sessionId3) });
beforeAll(() => {
httpHandler.reset("public");
@ -18,6 +22,8 @@ describe('http signaling test in public mode', () => {
beforeEach(() => {
mockClear();
httpHandler.checkSessionId(req, res, next);
httpHandler.checkSessionId(req2, res, next);
});
test('throw check has session', async () => {
@ -59,7 +65,7 @@ describe('http signaling test in public mode', () => {
test('get all from session1', async () => {
await httpHandler.getAll(req, res);
const connect = { connectionId: connectionId, datetime: expect.anything(), type: "connect" };
expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([connect]) });
expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([connect]), datetime: expect.anything() });
});
test('post offer from session1', async () => {
@ -123,7 +129,7 @@ describe('http signaling test in public mode', () => {
test('disconnection get from session1', async () => {
await httpHandler.getAll(req, res);
const disconnect = { connectionId: connectionId, datetime: expect.anything(), type: "disconnect" };
expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([disconnect]) });
expect(res.json).toHaveBeenCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() });
});
test('delete connection from session1', async () => {
@ -152,7 +158,7 @@ describe('http signaling test in public mode', () => {
await httpHandler.createSession(sessionId2, res);
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: [] });
expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() });
const connectBody = { connectionId: connectionId };
req.body = connectBody;
@ -164,9 +170,9 @@ describe('http signaling test in public mode', () => {
const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false };
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() });
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() });
const deleteBody = { connectionId: connectionId };
req2.body = deleteBody;
@ -180,10 +186,127 @@ describe('http signaling test in public mode', () => {
const disconnect = { connectionId: connectionId, type: "disconnect", datetime: expect.anything() };
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() });
await httpHandler.deleteSession(req2, res);
});
test('Timed out session2 deleted after session1 resends offer', async () => {
httpHandler.reset("public");
await httpHandler.createSession(sessionId, res);
await httpHandler.createSession(sessionId2, res);
req.url = "";
req2.url = "";
await httpHandler.checkSessionId(req, res, next);
await httpHandler.checkSessionId(req2, res, next);
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() });
const connectBody = { connectionId: connectionId };
req.body = connectBody;
await httpHandler.createConnection(req, res);
const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" };
req.body = offerBody;
await httpHandler.postOffer(req, res);
const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false };
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() });
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() });
const answerBody = { connectionId: connectionId, sdp: testsdp };
req2.body = answerBody;
await httpHandler.postAnswer(req2, res);
// resend offer after answer to simulate PeerCandidate entering into failed state
req.body = offerBody;
await httpHandler.postOffer(req, res);
// Wait a second and then checkSession for only session1 to force timeout of session2.
for (let i = 0; i < RetriesToForceTimeout + 1; ++i)
{
await httpHandler.checkSessionId(req, res, next);
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Get all for session1 to trigger cleaning up associated session that timed out.
await httpHandler.getAll(req, res);
// Check that we do have session1 still
await httpHandler.checkSessionId(req, res, next);
expect(res.sendStatus).toHaveBeenLastCalledWith(200);
// Check that we no longer have session2
await httpHandler.checkSessionId(req2, res, next);
expect(res.sendStatus).toHaveBeenLastCalledWith(404);
await httpHandler.deleteSession(req, res);
}, 16000);
test('Timed out sessions are deleted when other sessions check', async () => {
httpHandler.reset("public");
await httpHandler.createSession(sessionId, res);
await httpHandler.createSession(sessionId2, res);
await httpHandler.createSession(sessionId3, res);
req.url = "";
req2.url = "";
req3.url = "";
await httpHandler.checkSessionId(req, res, next);
await httpHandler.checkSessionId(req2, res, next);
await httpHandler.checkSessionId(req3, res, next);
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() });
const connectBody = { connectionId: connectionId };
req.body = connectBody;
await httpHandler.createConnection(req, res);
const offerBody = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer" };
req.body = offerBody;
await httpHandler.postOffer(req, res);
const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: false };
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() });
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() });
const answerBody = { connectionId: connectionId, sdp: testsdp };
req2.body = answerBody;
await httpHandler.postAnswer(req2, res);
// Wait a second and then checkSession for only session3 to force timeout of session1 & session2.
for (let i = 0; i < RetriesToForceTimeout + 1; ++i)
{
await httpHandler.checkSessionId(req3, res, next);
await new Promise(resolve => setTimeout(resolve, 1000));
}
// Get all for session3 to trigger cleaning up sessions that timed out.
await httpHandler.getAll(req3, res);
// Check that we do have session3 still
await httpHandler.checkSessionId(req3, res, next);
expect(res.sendStatus).toHaveBeenLastCalledWith(200);
// Check that we do have session1 still
await httpHandler.checkSessionId(req, res, next);
expect(res.sendStatus).toHaveBeenLastCalledWith(404);
// Check that we no longer have session2
await httpHandler.checkSessionId(req2, res, next);
expect(res.sendStatus).toHaveBeenLastCalledWith(404);
await httpHandler.deleteSession(req3, res);
}, 16000);
});
describe('http signaling test in private mode', () => {
@ -202,6 +325,9 @@ describe('http signaling test in private mode', () => {
beforeEach(() => {
mockClear();
httpHandler.checkSessionId(req, res, next);
httpHandler.checkSessionId(req2, res, next);
});
test('throw check has session', async () => {
@ -346,7 +472,7 @@ describe('http signaling test in private mode', () => {
await httpHandler.createSession(sessionId2, res);
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: [] });
expect(res.json).toHaveBeenLastCalledWith({ messages: [], datetime: expect.anything() });
const connectBody = { connectionId: connectionId };
req.body = connectBody;
@ -360,9 +486,9 @@ describe('http signaling test in private mode', () => {
const offer = { connectionId: connectionId, sdp: testsdp, datetime: expect.anything(), type: "offer", polite: true };
await httpHandler.getAll(req, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.not.arrayContaining([offer]), datetime: expect.anything() });
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([offer]), datetime: expect.anything() });
const deleteBody = { connectionId: connectionId };
req2.body = deleteBody;
@ -376,7 +502,7 @@ describe('http signaling test in private mode', () => {
const disconnect = { connectionId: connectionId, type: "disconnect", datetime: expect.anything() };
await httpHandler.getAll(req2, res);
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]) });
expect(res.json).toHaveBeenLastCalledWith({ messages: expect.arrayContaining([disconnect]), datetime: expect.anything() });
await httpHandler.deleteSession(req2, res);
});

View File

@ -860,6 +860,7 @@
"pm.test(\"The response has a valid JSON body\", function () {",
" pm.response.to.be.json;",
" pm.response.to.have.jsonBody(\"messages\");",
" pm.response.to.have.jsonBody(\"datetime\");",
" var jsonData = pm.response.json();",
" console.log(jsonData);",
" pm.expect(jsonData.messages.length).to.be.above(0);",

View File

@ -4,7 +4,75 @@ All notable changes to com.unity.renderstreaming package will be documented in t
The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/)
and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html).
## [Unreleased] - yyyy-mm-dd
## [3.1.0-exp.9] - 2024-12-13
### Changed
- deps: use com.unity.webrtc@3.0.0-pre.8
- doc: improve the API documentation of VideoCodecInfo
- doc: improve the API documentation of AudioCodecInfo
- doc: improve the API documentation of VideoStreamSender
- doc: improve the API documentation of VideoStreamReceiver
- doc: improve the API documentation of InputSender
- doc: improve the API documentation of InputReceiver
- doc: improve the API documentation of AudioStreamSender
- doc: improve the API documentation of AudioStreamReceiver
- doc: improve the API documentation of SignalingManager
## [3.1.0-exp.8] - 2023-11-30
### Changed
- Upgrade the version of WebRTC package `3.0.0-pre.7`.
## [3.1.0-exp.7] - 2023-08-09
### Added
- Added configurable logger to enable users to customize logging for their environment.
### Changed
- Upgrade the version of WebRTC package `3.0.0-pre.6`.
- Add `AudioStreamSender.loopback` property.
### Fixed
- Fixed error on HTTP signaling when using short polling interval.
- Fixed `SignalingManager` so that ICE server configurations aren't effected.
- Added a workaround to fix an issue where `InputField` wasn't worked when entering characters from browsers or a `Receiver` scene of package sample.
### Removed
- Removed Furioos Integration.
## [3.1.0-exp.6] - 2023-02-24
### Added
- Support Automatic Streaming.
- Support Render Streaming Wizard.
- Support Command line arguments.
- Add Render Streaming Settings in the Project Settings window.
### Changed
- Rename classes.
- `RenderStreaming` > `SignalingManager`
- Websocket is in default for signaling protocol instead of HTTP polling.
- Changed a unit of the HTTP polling interval, second to millisecond.
## [3.1.0-exp.5] - 2023-01-16
### Changed
- Upgrade the version of Input System package `1.4.4`.
- Upgrade the version of WebRTC package `3.0.0-pre.4`.
### Fixed
- Fix incorrect mouse position in full-screen web player sample.
## [3.1.0-exp.4] - 2022-10-06
### Added
@ -14,7 +82,7 @@ and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.
### Changed
- Upgraded the version of Input System package `1.4.1`.
- Upgraded the version of WebRTC package `2.4.0-exp.10`.
- Upgraded the version of WebRTC package `2.4.0-exp.11`.
- Merge features of three classes to `VideoStreamSender`.
- `MicrophoneStreamSender`
- `AudioStreamReceiver`

View File

@ -1,10 +1,11 @@
* [About Unity Render Streaming](index.md)
* [Overview](overview.md)
* [Tutorial](tutorial.md)
* [Developing a streaming application](dev-streaming-app-intro.md)
* [Installing The Package](installation.md)
* [Launching The Web Application](launch-webapp.md)
* [Creating The Scene](create-scene.md)
* [Setting Up Device Input](control-camera.md)
* [Render Streaming Settings](settings.md)
* [Render Streaming Wizard](wizard.md)
* [Web Application](webapp.md)
* [Configure Self-Signed Credentials for https](https.md)
* [Setting for TURN Server](turnserver.md)
@ -15,8 +16,7 @@
* [Video Streaming Component](video-streaming.md)
* [Audio Streaming Component](audio-streaming.md)
* [Data Streaming Component](data-streaming.md)
* [Using with Input System](use-inputsystem.md)
* [Deploy to Furioos](deploy-to-furioos.md)
* [Command-line option](commandline-option.md)
* [Samples](samples.md)
* [Receiver](sample-receiver.md)
* [Broadcast](sample-broadcast.md)
@ -26,5 +26,4 @@
* [Gyroscope](sample-gyroscope.md)
* [Web Browser Input](sample-browserinput.md)
* [Multiplay](sample-multiplay.md)
* [Project Template](template.md)
* [FAQ](faq.md)

View File

@ -15,9 +15,10 @@ This component streams the audio rendering results from [`AudioListener`](https:
| **Audio Source Type** | Choose the type of source for your audio streaming. <br/> - *Audio Listener* <br/> - *Audio Source* <br/> - *Microphone* | *Audio Listener* |
| *Audio Listener* | [`Audio Listener`](https://docs.unity3d.com/ScriptReference/AudioSource.html) instance for sending audio | |
| *Audio Source* | [`Audio Source`](https://docs.unity3d.com/ScriptReference/AudioSource.html) instance for sending audio | |
| *Microphone Device Index* | The index of the video input device to be used. See [Microphone.devices](https://docs.unity3d.com/ScriptReference/Microphone-devices.html). | 0 |
| *Microphone Device Index* | The index of the microphone input device to be used. See [Microphone.devices](https://docs.unity3d.com/ScriptReference/Microphone-devices.html). | 0 |
| *Auto Request User Authorization* | Whether request permission to use microphone. You don't need to enable it if you call [Application.RequestUserAuthorization](https://docs.unity3d.com/ScriptReference/Application.RequestUserAuthorization.html) yourself. | Enabled |
| **Audio Codec** | *Default* option means trying to use all available codecs for negotiating other peers. | Default |
| *Loopback* | The sending audio is also played on sender side. | Disabled |
| **Bitrate (kbits/sec)** | The bitrate of the audio streaming. | |
| *Min* | The minimum value of the bitrate. | 0 |
| *Max* | The maximum value of the bitrate. | 1000 |

View File

@ -0,0 +1,73 @@
# Command line arguments
Unity Render Streaming supports configuration changes via command line arguments. you can change settings to match the deployment environments. Command line arguments work with Windows, macOS, and Linux runtime applications. Mobile platforms aren't supported.
> [!WARNING]
> **-batchmode** and **-nographics** options don't work with Unity Render Streaming.
Command line arguments are evaluated when initializing the [**SignalingManager**](streaming-management.md) component. When command line arguments are evaluated in the **SignalingManager** component, it overrides the settings specified in the [Settings Window](settings.md). If you wish to ignore the command line options, specify **Evaluate command line arguments** off in the SignalingManager inspector. If a command line arguments contain invalid values, the contents of the configuration window are evaluated, instead of the arguments of the command line.
Use a command line with the following arguments to start your standalone app.
| Argument | Description |
| --- | --- |
| `signalingType <value>` | Specify the signaling type. **websocket** or **http**. |
| `signalingUrl <value>` | Specify the URL of signaling server. |
| `iceServerUrl <value>` | Set the URL of STUN/TURN server. |
| `iceServerUsername <value>` | Specify the user name of the TURN server. |
| `iceServerCredential <value>` | Specify the password of the TURN server. |
| `iceServerCredentialType <value>` | Specify the credential type for the TURN server. **password** or **oauth**. |
| `pollingInterval <value>` | Specify the polling interval in milliseconds to the signaling server. This value is used when using **http** for the signaling type. |
| `importJson <path>` | Specify the path of the JSON file. |
## Import JSON
You can change the configuration via the JSON file when using **-importJson** option in command line. The JSON file must be written in the following format:
```javascript
{
"signalingType": "websocket",
"signalingUrl": "ws://192.168.11.11",
"iceServers": [{
"urls": [
"stun:stun.l.google.com:19302"
],
"username": "user",
"credential": "pass",
"credentialType": "password"
}],
"pollingInterval": "5000"
}
```
## Command line examples
Change the signaling type to **http**:
```
RenderStreaming.exe -signalingType http
```
Change the URL of the signaling server:
```
RenderStreaming.exe -signalingUrl http://192.168.10.1
```
Specify multiple URLs of STAN servers:
```
RenderStreaming.exe -iceServerUrl stun:stun.l.google.com:19302 -iceServerUrl stun:stun.l.google.com:19303
```
Specify the URL, username, and password of the TURN server:
```
RenderStreaming.exe -iceServerUrl turn:192.168.10.10:3478?transport=udp -iceServerUsername username -iceServerCredentialType password -iceServerCredential pass
```
Specify the path of the JSON file:
```
RenderStreaming.exe -importJson config.json
```

View File

@ -4,7 +4,7 @@ To control the camera on the remote PC, we need to link the input events on web
## Check settings of Input System
First, please check [the settings](use-inputsystem.md) for using Input System.
First, please check the [Wizard window](wizard.md) about the Input System settings.
## Adding components for input processing
@ -84,8 +84,8 @@ Once you have copied the script and saved the file, assign `PlayerController.Loo
## Checking on browsers
The mouse operation in the browser should be reflected in the rotation of the camera. If the camera is not moved, please check [the settings](use-inputsystem.md).
The mouse operation in the browser should be reflected in the rotation of the camera. If the camera is not moved, please check the settings on the [Wizard](wizard.md) window.
## Next step
We were able to incorporate the input processing using the Input Actions feature. If you would like to learn more about the features of Unity Render Streaming, please see the [Sample page](samples.md). Also, check out [Customizing your web application](customize-webapp.md) for information on how to modify the web user interface.
We were able to incorporate the input processing using the Input Actions feature. If you would like to learn more about the features of Unity Render Streaming, please see the [Sample page](samples.md). Also, check out [Customizing your web application](customize-webapp.md) for information on how to modify the web user interface.

View File

@ -2,25 +2,31 @@
This tutorial explains how to edit an empty scene in Unity Editor and display the image rendered from the camera to the browser.
## Changing Project Settings
The procedure described in this page assumes that the [**Automatic Streaming**](settings.md##general-settings) feature is not used. Please turn the flag off following steps.
1: Open the **Project Settings** window.
2: Select **Render Streaming** tab.
3: Select **Create New Settings Asset**.
4: Save the asset with any name.
5: Disable **Automatic Streaming**.
![Disable Automatic Streaming](images/disable_automaticstreaming.png)
## Setting component
If Unity version is 2020 or later, Create a new empty scene. Select **File > New Scene** from the menu to open the dialog and select **Basic (Built-in)**.
> [!NOTE]
> This dialog is not opened if you are using Unity 2019.
![Create new scene](images/create_new_scene.png)
Select the **Main Camera** object in the Hierarchy window, and add the **Render Streaming** component in the Inspector window.
Select the **Main Camera** object in the Hierarchy window, and add the **Signaling Manager** component in the Inspector window.
![Add RenderStreaming component](images/add_renderstreaming_component.png)
Update properties in the inspector.
- **Signaling Type** : `WebSocketSignaling`
- **Signaling URL** : `ws://localhost`
![Create scene 03](images/change_properties_websocket.png)
![Add SignalingManager component](images/add_signalingmanager_component.png)
Next, we will add the **Broadcast** component to the **Main Camera** object. this component deliver the stream to multiple peers.
@ -34,7 +40,7 @@ Add a [**Video Stream Sender**](video-streaming.html#videostreamsenderapiunityre
![Add VideoStreamSender component](images/add_videostreamsender_component.png)
Assign the [**Video Stream Sender**](video-streaming.html#videostreamsenderapiunityrenderstreamingvideostreamsenderhtml-component) component to the **Broadcast** component property.
Assign the [**Video Stream Sender**](video-streaming.html#videostreamsenderapiunityrenderstreamingvideostreamsenderhtml-component) component to the **Broadcast** component property. And set camera
![Assign VideoStreamSender component to streams](images/assign_videostreamsender_to_streams.png)

View File

@ -2,7 +2,7 @@
Data streaming is using [`RTCDataChannel`](https://docs.unity3d.com/Packages/com.unity.webrtc@2.4/manual/datachannel.html) of the WebRTC package internally.
Using the data streaming feature, we provide a component to send messages of [Input System](https://docs.unity3d.com/Packages/com.unity.inputsystem@latest). For more details, please check the section on [Using with Input System](use-inputsystem.md).
Using the data streaming feature, Unity Render Streaming provides a component to send messages of [Input System](https://docs.unity3d.com/Packages/com.unity.inputsystem@latest).
## [`InputSender`](../api/Unity.RenderStreaming.InputSender.html) component reference

View File

@ -1,19 +0,0 @@
# Deploy to Furioos
As you may already know, **Unity Render Streaming** has a Furioos-compatible signaling option. This means that you can build a dedicated version of your application, host it on **Furioos**, and share it with thousands of customers who will enjoy all the features of **Unity Render Streaming**. But you will **not** have to deal with any of the difficulties of setting up a private server, a machine in the cloud or manage the scalability of your solution.
To do so, the requirement is to select `FurioosSignaling` in the `Signaling type` parameter of the [RenderStreaming](streaming-management.md#render-streaming) component.
This allow your application to connect to Furioos services when running on the managed virtual machines.
![Selecting FurioosSignaling](images/furioos_signaling.png)
Then just build a **standalone Windows version** of your application, and zip it! Don't try to build iOS, Android, linux or whatever version of your app, **Furioos only support Windows applications**. Also, be sure to zip the whole exported folder with all files and sub-folders, not just the ".exe" file.
![Selecting FurioosSignaling](images/furioos_zip_folder.png)
Finally just upload it on your account at https://portal.furioos.com/ .
If you need futher help to upload your application on **Furioos**, please follow [this tutorial](https://support.furioos.com/article/adding-an-application-on-furioos/).
You can check the stream type on https://portal.furioos.com/ by clicking to the "more options" button in the toolbar.
![Selecting FurioosSignaling](images/furioos_stream_type.png)

View File

@ -2,14 +2,6 @@
This section will walk you through the steps to create a simple streaming application from an empty Unity project.
## Install The Package
Install the package to start working. Please refer to the [Installing the package](installation.md) page to get started.
## Start the web application
After installing the package, please refer to the [Launching the Web Application](launch-webapp.md) page.
## Creating The Scene
To open the Unity editor and create a scene for streaming, see [Creating The Scene](create-scene.md).

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 68 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 42 KiB

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 22 KiB

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 503 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 534 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 45 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 253 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 337 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 37 KiB

After

Width:  |  Height:  |  Size: 37 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 896 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 564 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 KiB

After

Width:  |  Height:  |  Size: 285 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 27 KiB

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 217 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 386 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 976 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 418 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 164 KiB

View File

@ -16,14 +16,14 @@ This package provides the main features below.
We can broadcast video rendered on Unity to browsers via network. For example, It can show the video rendered with HDRP on the browser on the iPad. In addition, broadcasting from multiple cameras is supported.
![feature-multicamera](images/feature_multicamera.png)
![Render Streaming Wizard](images/feature_multicamera.png)
### Audio streaming
This package enables streaming sounds generated on Unity. And it can cast to multi-browsers simultaneously.
### Remote control
It is possible to send input messages to Unity from the browser, and sending inputs from multiple browsers is supported. Mouse, keyboard, touch, and gamepad are supported as input devices on the browser. For more information, please see the [Using with Input System](use-inputsystem.md) page.
It's possible to send input messages to Unity from the browser, and sending inputs from multiple browsers is supported. Mouse, keyboard, touch, and gamepad are supported as input devices on the browser.
## Requirements
@ -31,15 +31,19 @@ This version of Render Streaming is compatible with the following versions of th
- **Unity 2020.3**
- **Unity 2021.3**
- **Unity 2022.1**
- **Unity 2022.3**
- **Unity 2023.1**
### Platform
- **Windows**
- **Windows** (x64 only)
- **Linux**
- **macOS** (**Apple Slicon** is not supported yet)
- **macOS** (**Intel** and **Apple Slicon**)
- **iOS**
- **Android** (**ARMv7** is not supported)
- **Android** (**ARM64** only. **ARMv7** is not supported)
> [!NOTE]
> This package depends on [the WebRTC package](https://docs.unity3d.com/Packages/com.unity.webrtc@3.0). If you build for mobile platform (iOS/Android), please see [the package documentation](https://docs.unity3d.com/Packages/com.unity.webrtc@3.0/manual/requirements.html#additional-notes) to know the requirements for building.
### Browser support
@ -61,14 +65,3 @@ Unity Render Streaming supports almost all browsers that can use WebRTC.
## Samples
Please check [this page](samples.md).
## Project template
Please check [this page](template.md).
## Furioos compatibility
**Unity Render Streaming** is also supported natively by **Furioos** platform https://www.furioos.com/ .
That means that you can easily build a Unity application, upload it on **Furioos** and enjoy all the features of **Unity Render Streaming** without worrying about the deployment and scalability issues of your project.
Please see [Furioos Tutorial](deploy-to-furioos.md) section to find out how it works.

View File

@ -1,27 +0,0 @@
# Installing The Package
Select **Window > Package Manager** in the menu bar.
![Install Package Manager from menu bar](images/install_select_packman_menu_unity2020.png)
Check Package Manager window, Click `+` button and select `Add package from git URL...`.
![Select add package from git url](images/install_select_add_package_from_git_url.png)
Input the string below to the input field.
```
com.unity.renderstreaming@3.1.0-exp.4
```
The list of version string is [here](https://github.com/Unity-Technologies/UnityRenderStreaming/tags). In most cases, the latest version is recommended to use.
Click `Add` button, and will start install the package.
If an input system dialog box appears, click `Yes`
![Input system backend](images/input_system_backend.png)
## Next Step
After installing the package in the Unity Editor, you can launch the web application for signaling. Please see the next page [Launching The Web Application](launch-webapp.md).

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