Files
UnrealEngineUWP/Engine/Source/Programs/PixelStreaming/WebServers/SignallingWebServer/scripts/app.js

1243 lines
40 KiB
JavaScript
Raw Normal View History

// Copyright 1998-2019 Epic Games, Inc. All Rights Reserved.
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4341740) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4280523 by Patrick.Boutot Add option in AjaCustomTimeStep to wait until the frame to be ready. Previously, the frame was there but not yet processed so it was possible that it was not ready by the time we wanted to read it. It won't work with interlaced because the 2 fields are processed at the same time. In interlaced, will get a 30fps behaviour when we actually want a 60fps. Fix bug that didn't set and reset bIsOwned properly when it was first initialized as not owned. Change 4280526 by Patrick.Boutot Add accessor to get the leaf media source or output. Change 4280624 by Patrick.Boutot Add timecode acessor to media samples Change 4280626 by Patrick.Boutot Rework the timing for AJA Media Player. Previously, we took the timing of the frame. That was a bad idea because if 2 incomings video frames were coming a the same time, you would only show one. Making the buffering system useless. That affects the Custom Time Step since it was waiting for the interrupt signal and in some behavior we would like the frame to be ready to be used by UE. Same the timecode in the MediaSample because we may not used it to stamps the frame. Change 4283022 by Patrick.Boutot [EditorScriptingUtilitites] Check folder names invalid characters separatly from the object's name. #jira UE-59886, UE-62333 Change 4283112 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Rename TimemanagemenetEditor module names. Change 4283426 by JeanLuc.Corenthin Fix crash with FBX file #jira UE-62501 Change 4284940 by Patrick.Boutot A widget that let you select a single permutation from a list. It groups the values into categories and removes duplicates inside that category. Change 4285471 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Change 4286925 by Patrick.Boutot [AJA] Add support to read LTC from the reference In. Add more detail on video format and the device. MediaSource use the Permutations Selection widget to select his mode and device. Remove debugging option to trigger an AJA custom time step and timecode provider. Remove the UYVY pixel option from AJA. It's better do to the conversion on the AJA card that on the GPU. Change the tooltip and category for some AjaMediaSource properties. Change 4287026 by Julien.StJean Modifed the file STimeCodeProviderTab.cpp to fix the position of a SComboButton that wasn't properly place. Change 4287663 by Jon.Nabozny Add timecode messages into nDisplay, and sync those between Master and Slave Change 4287884 by Jon.Nabozny Create a TimecodeProvider for SystemTime and introduce a notion for DefaultTimecodeProvider in Engine. Change 4288050 by Jon.Nabozny Rework the TimeSynchronization implementation for usability and functionality. Change 4288283 by Jon.Nabozny Fixed swapped MetaClass and DisplayName options on UEngine::DefaultTimecodeProviderClassName; Change 4288352 by Jon.Nabozny Set TimecodeProviderClassName and DefaultTimecodeProviderClassName in BaseEngine.ini Change 4288378 by Jon.Nabozny Fixup some issues in TimecodeSynchronizer where code was reset improperly due to multiple unshelves / resolves. Change 4288394 by Jon.Nabozny Add TimeSync functionality into LiveLink. Also add test cases for this. This should allow us to easily synchronize multiple LiveLink sources together, as well as synchronize those to anything else using the sync system (Relies on CL-4235417) Change 4288899 by Patrick.Boutot Fix initialization order of FMediaIOCorePlayerBase variables Change 4289157 by Patrick.Boutot Allow the user to change the source of a capture without stopping the current capture. [AJA] AjaMediaCapture, add support for UpdateSceneViewport & UpdateRenderTarget @made by julien.stjean Change 4291328 by Jon.Nabozny Report the Skeleton Guid with TimeSyncData and track sync state in LiveLinkTimeSynchronizationSource. This prevents a crash that can happen if a source is quickly cleared and reset before the next tick of Time Synchronization. Change 4296294 by Jon.Nabozny Fixup errors when TimecodeProviderClassName is empty. It's valid to leave this empty. Change 4297122 by Patrick.Boutot Media Profile with timecode provider & custom time step Change 4301855 by Austin.Crismore Fix for movment scaling and virtual joystick controls. Movement scaling in for truck and dolly is locked to the world xy plane, and virtual joysticks use their own method for movement scaling now. #jira UE-61762, UE-62187 Change 4301856 by Austin.Crismore Virtual sequence level controller now listens to on object spawned, so that it can intercept the camera actor and disable attatching to HMD to prevent camera movement that isn't from the level sequence #jira UE-61766 Change 4301860 by Austin.Crismore Fix for touch scrubbing. Added default values back in. Added logic to only allow scrubbing when touch focus was off. #jira UE-61865 Change 4302294 by Jamie.Dale Added functions to get your the localized spoken and subtitle text from a dialogue wave Change 4304393 by Jamie.Dale Added support for BlueprintAssignable properties in Python Change 4305852 by Jamie.Dale Removed hard-dependency between EditorScriptingUtilities and PythonScriptPlugin Backed-out changelist 4259264 and query Python availability based on whether anything is available to handle the command #jira UE-62318 Change 4308550 by Jamie.Dale Fixed crash when passing a null world to Python actor iterators Change 4311867 by Homam.Bahnassi Revit master material with exposed parameters matching the API when possible. Change 4314428 by Francis.Hurteau Made the usage of the bBuildDeveloperTools switch independent of the bCompileAgainstEngine switch. Changed bBuildDeveloperTools TargetRule in UnrealBuildTool to a nullable to keep the old behavior in case where bBuildDeveloperTools wasn't explicitly set in TargetRules Change 4315134 by Jamie.Dale Defer editable text focus selection until mouse-up to allow the user to make an initial selection #jira UE-58086 Change 4318615 by Johan.Duparc EditorFactories: consistent return values after asset import. Change 4322459 by Jamie.Dale Made SequencerScripting an Editor plugin as it depends on PythonScriptPlugin which is an Editor plugin This was causing issues at runtime when SequencerScripting was enabled, as it failed to load PythonScriptPlugin (which hadn't been built). Change 4323341 by Francis.Hurteau Implement proper message bus protocol version negociation with static nodes Change 4323733 by Francis.Hurteau Fix VR Pausing Sequence Scrubbing just setting playback speed to 0.0 Change 4324319 by Jamie.Dale Exposed transactions to Blueprints Change 4325847 by Alistair.White Copying //Tasks/UE4/Private-PixelStreaming@4325566 to Dev-Enterprise-Minimal (//UE4/Dev-Enterprise-Minimal) This adds the new experimental PixelStreaming plugin to allow streaming of an Unreal client's audio & video stream to a browser through the WebRTC protocol to support new uses for enterprise customers. Change 4326282 by Simon.Tourangeau nDisplay native present handler Change 4326581 by Jamie.Dale Replacing FDateTime with int64 Ticks value to workaround UE-63485 Change 4326599 by Homam.Bahnassi Moving texture coords outside UVEdit function to allow using different UV channels. Change 4333250 by Francis.Hurteau Small TFuture changes: * cleans up TFuture::Then with usage of TUniqueFunction * added TFuture::Reset to invalidate it and remove continuation from a future shared state Change 4333359 by Homam.Bahnassi Support scaling and rotating UVs around arbitrary pivot Change 4333566 by Johan.Duparc Expose ProxyLOD functionalities to Scripting #jira UEENT-1788 Change 4333988 by Jamie.Dale Allow UHT to parse FText default parameter values INVTEXT, NSLOCTEXT, LOCTABLE, and FText::GetEmpty() are supported. LOCTEXT isn't as it relies on an external macro that is known to C++ but not to UHT (NSLOCTEXT can easily be used instead). Change 4335020 by Francis.Hurteau Uncomment MessageBus::Send deprecation notice for 4.21 Update MessageBus Send usage to new API Change 4335195 by JeanMichel.Dignard Add a SetLodFromStaticMesh script utility function #jira UEENT-1789 Change 4335231 by Anousack.Kitisa Added functions to generate planar, cylindrical, box UV mapping. #jira UEENT-1598 Change 4335373 by Jamie.Dale Cleaned up some places creating empty literal texts Change 4335458 by Jamie.Dale Allow UHT to parse FText() as an alias of FText::GetEmpty() when processing default values Change 4335875 by Max.Chen Sequencer: Clear RF_Transient on pasted tracks/sections #jira UE-63537 Change 4336497 by Johan.Duparc ProxyLOD: Fix progress bar issue - removed duplicated code - removed duplicated LongTask object #jira UEENT-1788 Change 4336723 by Jamie.Dale Ensure that Python generated types create their CDO at the correct point #jira UE-62895 Change 4340594 by Ben.Marsh Fix manifest being invalidated when building two enterprise targets in a row. Fixes CIS error. #jira UE-63644 [CL 4342443 by JeanMichel Dignard in Main branch]
2018-09-04 16:35:02 -04:00
var webRtcPlayerObj = null;
var print_stats = false;
var print_inputs = false;
var connect_on_load = false;
var is_reconnection = false;
var socket;
var qualityControlOwnershipCheckBox;
var matchViewportResolution;
// TODO: Remove this - workaround because of bug causing UE to crash when switching resolutions too quickly
var lastTimeResized = new Date().getTime();
var resizeTimeout;
var onDataChannelConnected;
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4341740) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4280523 by Patrick.Boutot Add option in AjaCustomTimeStep to wait until the frame to be ready. Previously, the frame was there but not yet processed so it was possible that it was not ready by the time we wanted to read it. It won't work with interlaced because the 2 fields are processed at the same time. In interlaced, will get a 30fps behaviour when we actually want a 60fps. Fix bug that didn't set and reset bIsOwned properly when it was first initialized as not owned. Change 4280526 by Patrick.Boutot Add accessor to get the leaf media source or output. Change 4280624 by Patrick.Boutot Add timecode acessor to media samples Change 4280626 by Patrick.Boutot Rework the timing for AJA Media Player. Previously, we took the timing of the frame. That was a bad idea because if 2 incomings video frames were coming a the same time, you would only show one. Making the buffering system useless. That affects the Custom Time Step since it was waiting for the interrupt signal and in some behavior we would like the frame to be ready to be used by UE. Same the timecode in the MediaSample because we may not used it to stamps the frame. Change 4283022 by Patrick.Boutot [EditorScriptingUtilitites] Check folder names invalid characters separatly from the object's name. #jira UE-59886, UE-62333 Change 4283112 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Rename TimemanagemenetEditor module names. Change 4283426 by JeanLuc.Corenthin Fix crash with FBX file #jira UE-62501 Change 4284940 by Patrick.Boutot A widget that let you select a single permutation from a list. It groups the values into categories and removes duplicates inside that category. Change 4285471 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Change 4286925 by Patrick.Boutot [AJA] Add support to read LTC from the reference In. Add more detail on video format and the device. MediaSource use the Permutations Selection widget to select his mode and device. Remove debugging option to trigger an AJA custom time step and timecode provider. Remove the UYVY pixel option from AJA. It's better do to the conversion on the AJA card that on the GPU. Change the tooltip and category for some AjaMediaSource properties. Change 4287026 by Julien.StJean Modifed the file STimeCodeProviderTab.cpp to fix the position of a SComboButton that wasn't properly place. Change 4287663 by Jon.Nabozny Add timecode messages into nDisplay, and sync those between Master and Slave Change 4287884 by Jon.Nabozny Create a TimecodeProvider for SystemTime and introduce a notion for DefaultTimecodeProvider in Engine. Change 4288050 by Jon.Nabozny Rework the TimeSynchronization implementation for usability and functionality. Change 4288283 by Jon.Nabozny Fixed swapped MetaClass and DisplayName options on UEngine::DefaultTimecodeProviderClassName; Change 4288352 by Jon.Nabozny Set TimecodeProviderClassName and DefaultTimecodeProviderClassName in BaseEngine.ini Change 4288378 by Jon.Nabozny Fixup some issues in TimecodeSynchronizer where code was reset improperly due to multiple unshelves / resolves. Change 4288394 by Jon.Nabozny Add TimeSync functionality into LiveLink. Also add test cases for this. This should allow us to easily synchronize multiple LiveLink sources together, as well as synchronize those to anything else using the sync system (Relies on CL-4235417) Change 4288899 by Patrick.Boutot Fix initialization order of FMediaIOCorePlayerBase variables Change 4289157 by Patrick.Boutot Allow the user to change the source of a capture without stopping the current capture. [AJA] AjaMediaCapture, add support for UpdateSceneViewport & UpdateRenderTarget @made by julien.stjean Change 4291328 by Jon.Nabozny Report the Skeleton Guid with TimeSyncData and track sync state in LiveLinkTimeSynchronizationSource. This prevents a crash that can happen if a source is quickly cleared and reset before the next tick of Time Synchronization. Change 4296294 by Jon.Nabozny Fixup errors when TimecodeProviderClassName is empty. It's valid to leave this empty. Change 4297122 by Patrick.Boutot Media Profile with timecode provider & custom time step Change 4301855 by Austin.Crismore Fix for movment scaling and virtual joystick controls. Movement scaling in for truck and dolly is locked to the world xy plane, and virtual joysticks use their own method for movement scaling now. #jira UE-61762, UE-62187 Change 4301856 by Austin.Crismore Virtual sequence level controller now listens to on object spawned, so that it can intercept the camera actor and disable attatching to HMD to prevent camera movement that isn't from the level sequence #jira UE-61766 Change 4301860 by Austin.Crismore Fix for touch scrubbing. Added default values back in. Added logic to only allow scrubbing when touch focus was off. #jira UE-61865 Change 4302294 by Jamie.Dale Added functions to get your the localized spoken and subtitle text from a dialogue wave Change 4304393 by Jamie.Dale Added support for BlueprintAssignable properties in Python Change 4305852 by Jamie.Dale Removed hard-dependency between EditorScriptingUtilities and PythonScriptPlugin Backed-out changelist 4259264 and query Python availability based on whether anything is available to handle the command #jira UE-62318 Change 4308550 by Jamie.Dale Fixed crash when passing a null world to Python actor iterators Change 4311867 by Homam.Bahnassi Revit master material with exposed parameters matching the API when possible. Change 4314428 by Francis.Hurteau Made the usage of the bBuildDeveloperTools switch independent of the bCompileAgainstEngine switch. Changed bBuildDeveloperTools TargetRule in UnrealBuildTool to a nullable to keep the old behavior in case where bBuildDeveloperTools wasn't explicitly set in TargetRules Change 4315134 by Jamie.Dale Defer editable text focus selection until mouse-up to allow the user to make an initial selection #jira UE-58086 Change 4318615 by Johan.Duparc EditorFactories: consistent return values after asset import. Change 4322459 by Jamie.Dale Made SequencerScripting an Editor plugin as it depends on PythonScriptPlugin which is an Editor plugin This was causing issues at runtime when SequencerScripting was enabled, as it failed to load PythonScriptPlugin (which hadn't been built). Change 4323341 by Francis.Hurteau Implement proper message bus protocol version negociation with static nodes Change 4323733 by Francis.Hurteau Fix VR Pausing Sequence Scrubbing just setting playback speed to 0.0 Change 4324319 by Jamie.Dale Exposed transactions to Blueprints Change 4325847 by Alistair.White Copying //Tasks/UE4/Private-PixelStreaming@4325566 to Dev-Enterprise-Minimal (//UE4/Dev-Enterprise-Minimal) This adds the new experimental PixelStreaming plugin to allow streaming of an Unreal client's audio & video stream to a browser through the WebRTC protocol to support new uses for enterprise customers. Change 4326282 by Simon.Tourangeau nDisplay native present handler Change 4326581 by Jamie.Dale Replacing FDateTime with int64 Ticks value to workaround UE-63485 Change 4326599 by Homam.Bahnassi Moving texture coords outside UVEdit function to allow using different UV channels. Change 4333250 by Francis.Hurteau Small TFuture changes: * cleans up TFuture::Then with usage of TUniqueFunction * added TFuture::Reset to invalidate it and remove continuation from a future shared state Change 4333359 by Homam.Bahnassi Support scaling and rotating UVs around arbitrary pivot Change 4333566 by Johan.Duparc Expose ProxyLOD functionalities to Scripting #jira UEENT-1788 Change 4333988 by Jamie.Dale Allow UHT to parse FText default parameter values INVTEXT, NSLOCTEXT, LOCTABLE, and FText::GetEmpty() are supported. LOCTEXT isn't as it relies on an external macro that is known to C++ but not to UHT (NSLOCTEXT can easily be used instead). Change 4335020 by Francis.Hurteau Uncomment MessageBus::Send deprecation notice for 4.21 Update MessageBus Send usage to new API Change 4335195 by JeanMichel.Dignard Add a SetLodFromStaticMesh script utility function #jira UEENT-1789 Change 4335231 by Anousack.Kitisa Added functions to generate planar, cylindrical, box UV mapping. #jira UEENT-1598 Change 4335373 by Jamie.Dale Cleaned up some places creating empty literal texts Change 4335458 by Jamie.Dale Allow UHT to parse FText() as an alias of FText::GetEmpty() when processing default values Change 4335875 by Max.Chen Sequencer: Clear RF_Transient on pasted tracks/sections #jira UE-63537 Change 4336497 by Johan.Duparc ProxyLOD: Fix progress bar issue - removed duplicated code - removed duplicated LongTask object #jira UEENT-1788 Change 4336723 by Jamie.Dale Ensure that Python generated types create their CDO at the correct point #jira UE-62895 Change 4340594 by Ben.Marsh Fix manifest being invalidated when building two enterprise targets in a row. Fixes CIS error. #jira UE-63644 [CL 4342443 by JeanMichel Dignard in Main branch]
2018-09-04 16:35:02 -04:00
var responseEventListeners = new Map();
var t0 = Date.now();
function log(str) {
console.log(`${Math.floor(Date.now() - t0)}: ` + str);
}
function setupHtmlEvents(){
//Window events
window.addEventListener('resize', resizePlayerStyle, true);
window.addEventListener('orientationchange', onOrientationChange);
//HTML elements controls
let resizeCheckBox = document.getElementById('enlarge-display-to-fill-window-tgl');
if (resizeCheckBox != null) {
resizeCheckBox.onchange = function(event){
resizePlayerStyle();
}
}
qualityControlOwnershipCheckBox = document.getElementById('quality-control-ownership-tgl');
if (qualityControlOwnershipCheckBox != null) {
qualityControlOwnershipCheckBox.onchange = function (event) {
requestQualityControl();
}
}
let prioritiseQualityCheckbox = document.getElementById('prioritise-quality-tgl');
let qualityParamsSubmit = document.getElementById('quality-params-submit');
if (prioritiseQualityCheckbox != null) {
prioritiseQualityCheckbox.onchange = function (event) {
if (prioritiseQualityCheckbox.checked) {
// TODO: This state should be read from the UE Application rather than from the initial values in the HTML
let lowBitrate = document.getElementById('low-bitrate-text').value;
let highBitrate = document.getElementById('high-bitrate-text').value;
let minFPS = document.getElementById('min-fps-text').value;
let initialDescriptor = {
PrioritiseQuality: 1,
LowBitrate: lowBitrate,
HighBitrate: highBitrate,
MinFPS: minFPS
}
// TODO: The descriptor should be sent as is to a generic handler on the UE side
// but for now we're just sending it as separate console commands
//emitUIInteraction(initialDescriptor);
sendQualityConsoleCommands(initialDescriptor);
console.log(initialDescriptor);
qualityParamsSubmit.onclick = function (event) {
let lowBitrate = document.getElementById('low-bitrate-text').value;
let highBitrate = document.getElementById('high-bitrate-text').value;
let minFPS = document.getElementById('min-fps-text').value;
let descriptor = {
PrioritiseQuality: 1,
LowBitrate: lowBitrate,
HighBitrate: highBitrate,
MinFPS: minFPS
}
//emitUIInteraction(descriptor);
sendQualityConsoleCommands(descriptor);
console.log(descriptor);
}
} else { // Prioritise Quality unchecked
let initialDescriptor = {
PrioritiseQuality: 0
}
//emitUIInteraction(initialDescriptor);
sendQualityConsoleCommands(initialDescriptor);
console.log(initialDescriptor);
qualityParamsSubmit.onclick = null;
}
}
}
let showFPSButton = document.getElementById('show-fps-button');
if (showFPSButton != null) {
showFPSButton.onclick = function (event) {
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4341740) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4280523 by Patrick.Boutot Add option in AjaCustomTimeStep to wait until the frame to be ready. Previously, the frame was there but not yet processed so it was possible that it was not ready by the time we wanted to read it. It won't work with interlaced because the 2 fields are processed at the same time. In interlaced, will get a 30fps behaviour when we actually want a 60fps. Fix bug that didn't set and reset bIsOwned properly when it was first initialized as not owned. Change 4280526 by Patrick.Boutot Add accessor to get the leaf media source or output. Change 4280624 by Patrick.Boutot Add timecode acessor to media samples Change 4280626 by Patrick.Boutot Rework the timing for AJA Media Player. Previously, we took the timing of the frame. That was a bad idea because if 2 incomings video frames were coming a the same time, you would only show one. Making the buffering system useless. That affects the Custom Time Step since it was waiting for the interrupt signal and in some behavior we would like the frame to be ready to be used by UE. Same the timecode in the MediaSample because we may not used it to stamps the frame. Change 4283022 by Patrick.Boutot [EditorScriptingUtilitites] Check folder names invalid characters separatly from the object's name. #jira UE-59886, UE-62333 Change 4283112 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Rename TimemanagemenetEditor module names. Change 4283426 by JeanLuc.Corenthin Fix crash with FBX file #jira UE-62501 Change 4284940 by Patrick.Boutot A widget that let you select a single permutation from a list. It groups the values into categories and removes duplicates inside that category. Change 4285471 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Change 4286925 by Patrick.Boutot [AJA] Add support to read LTC from the reference In. Add more detail on video format and the device. MediaSource use the Permutations Selection widget to select his mode and device. Remove debugging option to trigger an AJA custom time step and timecode provider. Remove the UYVY pixel option from AJA. It's better do to the conversion on the AJA card that on the GPU. Change the tooltip and category for some AjaMediaSource properties. Change 4287026 by Julien.StJean Modifed the file STimeCodeProviderTab.cpp to fix the position of a SComboButton that wasn't properly place. Change 4287663 by Jon.Nabozny Add timecode messages into nDisplay, and sync those between Master and Slave Change 4287884 by Jon.Nabozny Create a TimecodeProvider for SystemTime and introduce a notion for DefaultTimecodeProvider in Engine. Change 4288050 by Jon.Nabozny Rework the TimeSynchronization implementation for usability and functionality. Change 4288283 by Jon.Nabozny Fixed swapped MetaClass and DisplayName options on UEngine::DefaultTimecodeProviderClassName; Change 4288352 by Jon.Nabozny Set TimecodeProviderClassName and DefaultTimecodeProviderClassName in BaseEngine.ini Change 4288378 by Jon.Nabozny Fixup some issues in TimecodeSynchronizer where code was reset improperly due to multiple unshelves / resolves. Change 4288394 by Jon.Nabozny Add TimeSync functionality into LiveLink. Also add test cases for this. This should allow us to easily synchronize multiple LiveLink sources together, as well as synchronize those to anything else using the sync system (Relies on CL-4235417) Change 4288899 by Patrick.Boutot Fix initialization order of FMediaIOCorePlayerBase variables Change 4289157 by Patrick.Boutot Allow the user to change the source of a capture without stopping the current capture. [AJA] AjaMediaCapture, add support for UpdateSceneViewport & UpdateRenderTarget @made by julien.stjean Change 4291328 by Jon.Nabozny Report the Skeleton Guid with TimeSyncData and track sync state in LiveLinkTimeSynchronizationSource. This prevents a crash that can happen if a source is quickly cleared and reset before the next tick of Time Synchronization. Change 4296294 by Jon.Nabozny Fixup errors when TimecodeProviderClassName is empty. It's valid to leave this empty. Change 4297122 by Patrick.Boutot Media Profile with timecode provider & custom time step Change 4301855 by Austin.Crismore Fix for movment scaling and virtual joystick controls. Movement scaling in for truck and dolly is locked to the world xy plane, and virtual joysticks use their own method for movement scaling now. #jira UE-61762, UE-62187 Change 4301856 by Austin.Crismore Virtual sequence level controller now listens to on object spawned, so that it can intercept the camera actor and disable attatching to HMD to prevent camera movement that isn't from the level sequence #jira UE-61766 Change 4301860 by Austin.Crismore Fix for touch scrubbing. Added default values back in. Added logic to only allow scrubbing when touch focus was off. #jira UE-61865 Change 4302294 by Jamie.Dale Added functions to get your the localized spoken and subtitle text from a dialogue wave Change 4304393 by Jamie.Dale Added support for BlueprintAssignable properties in Python Change 4305852 by Jamie.Dale Removed hard-dependency between EditorScriptingUtilities and PythonScriptPlugin Backed-out changelist 4259264 and query Python availability based on whether anything is available to handle the command #jira UE-62318 Change 4308550 by Jamie.Dale Fixed crash when passing a null world to Python actor iterators Change 4311867 by Homam.Bahnassi Revit master material with exposed parameters matching the API when possible. Change 4314428 by Francis.Hurteau Made the usage of the bBuildDeveloperTools switch independent of the bCompileAgainstEngine switch. Changed bBuildDeveloperTools TargetRule in UnrealBuildTool to a nullable to keep the old behavior in case where bBuildDeveloperTools wasn't explicitly set in TargetRules Change 4315134 by Jamie.Dale Defer editable text focus selection until mouse-up to allow the user to make an initial selection #jira UE-58086 Change 4318615 by Johan.Duparc EditorFactories: consistent return values after asset import. Change 4322459 by Jamie.Dale Made SequencerScripting an Editor plugin as it depends on PythonScriptPlugin which is an Editor plugin This was causing issues at runtime when SequencerScripting was enabled, as it failed to load PythonScriptPlugin (which hadn't been built). Change 4323341 by Francis.Hurteau Implement proper message bus protocol version negociation with static nodes Change 4323733 by Francis.Hurteau Fix VR Pausing Sequence Scrubbing just setting playback speed to 0.0 Change 4324319 by Jamie.Dale Exposed transactions to Blueprints Change 4325847 by Alistair.White Copying //Tasks/UE4/Private-PixelStreaming@4325566 to Dev-Enterprise-Minimal (//UE4/Dev-Enterprise-Minimal) This adds the new experimental PixelStreaming plugin to allow streaming of an Unreal client's audio & video stream to a browser through the WebRTC protocol to support new uses for enterprise customers. Change 4326282 by Simon.Tourangeau nDisplay native present handler Change 4326581 by Jamie.Dale Replacing FDateTime with int64 Ticks value to workaround UE-63485 Change 4326599 by Homam.Bahnassi Moving texture coords outside UVEdit function to allow using different UV channels. Change 4333250 by Francis.Hurteau Small TFuture changes: * cleans up TFuture::Then with usage of TUniqueFunction * added TFuture::Reset to invalidate it and remove continuation from a future shared state Change 4333359 by Homam.Bahnassi Support scaling and rotating UVs around arbitrary pivot Change 4333566 by Johan.Duparc Expose ProxyLOD functionalities to Scripting #jira UEENT-1788 Change 4333988 by Jamie.Dale Allow UHT to parse FText default parameter values INVTEXT, NSLOCTEXT, LOCTABLE, and FText::GetEmpty() are supported. LOCTEXT isn't as it relies on an external macro that is known to C++ but not to UHT (NSLOCTEXT can easily be used instead). Change 4335020 by Francis.Hurteau Uncomment MessageBus::Send deprecation notice for 4.21 Update MessageBus Send usage to new API Change 4335195 by JeanMichel.Dignard Add a SetLodFromStaticMesh script utility function #jira UEENT-1789 Change 4335231 by Anousack.Kitisa Added functions to generate planar, cylindrical, box UV mapping. #jira UEENT-1598 Change 4335373 by Jamie.Dale Cleaned up some places creating empty literal texts Change 4335458 by Jamie.Dale Allow UHT to parse FText() as an alias of FText::GetEmpty() when processing default values Change 4335875 by Max.Chen Sequencer: Clear RF_Transient on pasted tracks/sections #jira UE-63537 Change 4336497 by Johan.Duparc ProxyLOD: Fix progress bar issue - removed duplicated code - removed duplicated LongTask object #jira UEENT-1788 Change 4336723 by Jamie.Dale Ensure that Python generated types create their CDO at the correct point #jira UE-62895 Change 4340594 by Ben.Marsh Fix manifest being invalidated when building two enterprise targets in a row. Fixes CIS error. #jira UE-63644 [CL 4342443 by JeanMichel Dignard in Main branch]
2018-09-04 16:35:02 -04:00
let consoleDescriptor = {
Console: 'stat fps'
}
emitUIInteraction(consoleDescriptor);
}
}
let matchViewportResolutionCheckBox = document.getElementById('match-viewport-res-tgl');
if (matchViewportResolutionCheckBox != null) {
matchViewportResolutionCheckBox.onchange = function (event) {
matchViewportResolution = matchViewportResolutionCheckBox.checked;
}
}
let statsCheckBox = document.getElementById('show-stats-tgl');
if (statsCheckBox != null) {
statsCheckBox.onchange = function(event){
let stats = document.getElementById('statsContainer');
stats.style.display = (event.target.checked) ? "block" : "none";
}
}
var kickButton = document.getElementById('kick-other-players-button');
if(kickButton) {
kickButton.onclick = function(event){
socket.emit('kick', {});
}
}
}
function sendQualityConsoleCommands(descriptor) {
if (descriptor.PrioritiseQuality != null) {
var command = 'Streamer.PrioritiseQuality ' + descriptor.PrioritiseQuality;
let consoleDescriptor = {
Console: command
}
emitUIInteraction(consoleDescriptor);
}
if (descriptor.LowBitrate != null) {
var command = 'Streamer.LowBitrate ' + descriptor.LowBitrate;
let consoleDescriptor = {
Console: command
}
emitUIInteraction(consoleDescriptor);
}
if (descriptor.HighBitrate != null) {
var command = 'Streamer.HighBitrate ' + descriptor.HighBitrate;
let consoleDescriptor = {
Console: command
}
emitUIInteraction(consoleDescriptor);
}
if (descriptor.MinFPS != null) {
var command = 'Streamer.MinFPS ' + descriptor.MinFPS;
let consoleDescriptor = {
Console: command
}
emitUIInteraction(consoleDescriptor);
}
}
function setOverlay(htmlClass, htmlElement, onClickFunction){
var videoPlayOverlay = document.getElementById('videoPlayOverlay');
if(!videoPlayOverlay){
var playerDiv = document.getElementById('player');
videoPlayOverlay = document.createElement('div');
videoPlayOverlay.id = 'videoPlayOverlay';
playerDiv.appendChild(videoPlayOverlay);
}
// Remove existing html child elements so we can add the new one
while (videoPlayOverlay.lastChild) {
videoPlayOverlay.removeChild(videoPlayOverlay.lastChild);
}
if(htmlElement)
videoPlayOverlay.appendChild(htmlElement);
if(onClickFunction){
videoPlayOverlay.addEventListener('click', function onOverlayClick(event){
onClickFunction(event);
videoPlayOverlay.removeEventListener('click', onOverlayClick);
});
}
// Remove existing html classes so we can set the new one
var cl = videoPlayOverlay.classList;
for( var i = cl.length-1; i >= 0; i-- ) {
cl.remove( cl[i] );
}
videoPlayOverlay.classList.add(htmlClass);
}
function showConnectOverlay(){
var startText = document.createElement('div');
startText.id = 'playButton';
startText.innerHTML = 'Click to start';
setOverlay('clickableState', startText, event => {
connect();
});
}
function showTextOverlay(text){
var textOverlay = document.createElement('div');
textOverlay.id = 'messageOverlay';
textOverlay.innerHTML = text ? text : '';
setOverlay('textDisplayState', textOverlay);
}
function showPlayOverlay(){
var img = document.createElement('img');
img.id = 'playButton';
img.src = '/images/Play.png';
img.alt = 'Start Streaming';
setOverlay('clickableState', img, event => {
if(webRtcPlayerObj)
webRtcPlayerObj.video.play();
requestQualityControl();
hideOverlay();
});
}
function hideOverlay(){
setOverlay('hiddenState');
}
function createWebRtcOffer(){
if(webRtcPlayerObj){
console.log('Creating offer');
showTextOverlay('Starting connection to server, please wait');
webRtcPlayerObj.createOffer();
} else {
console.log('WebRTC player not setup, cannot create offer');
showTextOverlay('Unable to setup video');
}
}
function sendInputData(data){
if(webRtcPlayerObj)
webRtcPlayerObj.send(data);
}
function addResponseEventListener(name, listener) {
responseEventListeners.set(name, listener);
}
function removeResponseEventListener(name) {
responseEventListeners.remove(name);
}
// Must be kept in sync with PixelStreamingProtocol::EToClientMsg C++ enum.
const ToClientMessageType = {
QualityControlOwnership: 0,
Response: 1
};
function setupWebRtcPlayer(htmlElement, clientConfig){
webRtcPlayerObj = new webRtcPlayer({peerConnectionOptions: clientConfig.peerConnectionOptions});
htmlElement.appendChild(webRtcPlayerObj.video);
webRtcPlayerObj.onWebRtcOffer = function (offer) {
socket.emit("webrtc-offer", offer);
};
webRtcPlayerObj.onWebRtcCandidate = function(candidate) {
socket.emit('webrtc-ice', candidate);
};
webRtcPlayerObj.onVideoInitialised = function(){
showPlayOverlay();
resizePlayerStyle();
}
webRtcPlayerObj.onDataChannelConnected = function(){
showTextOverlay('WebRTC connected, waiting for video');
if (onDataChannelConnected) {
onDataChannelConnected();
}
Copying //UE4/Dev-Enterprise to //UE4/Dev-Main (Source: //UE4/Dev-Enterprise @ 4341740) #lockdown Nick.Penwarden #rb none ============================ MAJOR FEATURES & CHANGES ============================ Change 4280523 by Patrick.Boutot Add option in AjaCustomTimeStep to wait until the frame to be ready. Previously, the frame was there but not yet processed so it was possible that it was not ready by the time we wanted to read it. It won't work with interlaced because the 2 fields are processed at the same time. In interlaced, will get a 30fps behaviour when we actually want a 60fps. Fix bug that didn't set and reset bIsOwned properly when it was first initialized as not owned. Change 4280526 by Patrick.Boutot Add accessor to get the leaf media source or output. Change 4280624 by Patrick.Boutot Add timecode acessor to media samples Change 4280626 by Patrick.Boutot Rework the timing for AJA Media Player. Previously, we took the timing of the frame. That was a bad idea because if 2 incomings video frames were coming a the same time, you would only show one. Making the buffering system useless. That affects the Custom Time Step since it was waiting for the interrupt signal and in some behavior we would like the frame to be ready to be used by UE. Same the timecode in the MediaSample because we may not used it to stamps the frame. Change 4283022 by Patrick.Boutot [EditorScriptingUtilitites] Check folder names invalid characters separatly from the object's name. #jira UE-59886, UE-62333 Change 4283112 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Rename TimemanagemenetEditor module names. Change 4283426 by JeanLuc.Corenthin Fix crash with FBX file #jira UE-62501 Change 4284940 by Patrick.Boutot A widget that let you select a single permutation from a list. It groups the values into categories and removes duplicates inside that category. Change 4285471 by Patrick.Boutot Remove MediaFrameworkUtilititesModule dependency to the Settings module at runtime. Change 4286925 by Patrick.Boutot [AJA] Add support to read LTC from the reference In. Add more detail on video format and the device. MediaSource use the Permutations Selection widget to select his mode and device. Remove debugging option to trigger an AJA custom time step and timecode provider. Remove the UYVY pixel option from AJA. It's better do to the conversion on the AJA card that on the GPU. Change the tooltip and category for some AjaMediaSource properties. Change 4287026 by Julien.StJean Modifed the file STimeCodeProviderTab.cpp to fix the position of a SComboButton that wasn't properly place. Change 4287663 by Jon.Nabozny Add timecode messages into nDisplay, and sync those between Master and Slave Change 4287884 by Jon.Nabozny Create a TimecodeProvider for SystemTime and introduce a notion for DefaultTimecodeProvider in Engine. Change 4288050 by Jon.Nabozny Rework the TimeSynchronization implementation for usability and functionality. Change 4288283 by Jon.Nabozny Fixed swapped MetaClass and DisplayName options on UEngine::DefaultTimecodeProviderClassName; Change 4288352 by Jon.Nabozny Set TimecodeProviderClassName and DefaultTimecodeProviderClassName in BaseEngine.ini Change 4288378 by Jon.Nabozny Fixup some issues in TimecodeSynchronizer where code was reset improperly due to multiple unshelves / resolves. Change 4288394 by Jon.Nabozny Add TimeSync functionality into LiveLink. Also add test cases for this. This should allow us to easily synchronize multiple LiveLink sources together, as well as synchronize those to anything else using the sync system (Relies on CL-4235417) Change 4288899 by Patrick.Boutot Fix initialization order of FMediaIOCorePlayerBase variables Change 4289157 by Patrick.Boutot Allow the user to change the source of a capture without stopping the current capture. [AJA] AjaMediaCapture, add support for UpdateSceneViewport & UpdateRenderTarget @made by julien.stjean Change 4291328 by Jon.Nabozny Report the Skeleton Guid with TimeSyncData and track sync state in LiveLinkTimeSynchronizationSource. This prevents a crash that can happen if a source is quickly cleared and reset before the next tick of Time Synchronization. Change 4296294 by Jon.Nabozny Fixup errors when TimecodeProviderClassName is empty. It's valid to leave this empty. Change 4297122 by Patrick.Boutot Media Profile with timecode provider & custom time step Change 4301855 by Austin.Crismore Fix for movment scaling and virtual joystick controls. Movement scaling in for truck and dolly is locked to the world xy plane, and virtual joysticks use their own method for movement scaling now. #jira UE-61762, UE-62187 Change 4301856 by Austin.Crismore Virtual sequence level controller now listens to on object spawned, so that it can intercept the camera actor and disable attatching to HMD to prevent camera movement that isn't from the level sequence #jira UE-61766 Change 4301860 by Austin.Crismore Fix for touch scrubbing. Added default values back in. Added logic to only allow scrubbing when touch focus was off. #jira UE-61865 Change 4302294 by Jamie.Dale Added functions to get your the localized spoken and subtitle text from a dialogue wave Change 4304393 by Jamie.Dale Added support for BlueprintAssignable properties in Python Change 4305852 by Jamie.Dale Removed hard-dependency between EditorScriptingUtilities and PythonScriptPlugin Backed-out changelist 4259264 and query Python availability based on whether anything is available to handle the command #jira UE-62318 Change 4308550 by Jamie.Dale Fixed crash when passing a null world to Python actor iterators Change 4311867 by Homam.Bahnassi Revit master material with exposed parameters matching the API when possible. Change 4314428 by Francis.Hurteau Made the usage of the bBuildDeveloperTools switch independent of the bCompileAgainstEngine switch. Changed bBuildDeveloperTools TargetRule in UnrealBuildTool to a nullable to keep the old behavior in case where bBuildDeveloperTools wasn't explicitly set in TargetRules Change 4315134 by Jamie.Dale Defer editable text focus selection until mouse-up to allow the user to make an initial selection #jira UE-58086 Change 4318615 by Johan.Duparc EditorFactories: consistent return values after asset import. Change 4322459 by Jamie.Dale Made SequencerScripting an Editor plugin as it depends on PythonScriptPlugin which is an Editor plugin This was causing issues at runtime when SequencerScripting was enabled, as it failed to load PythonScriptPlugin (which hadn't been built). Change 4323341 by Francis.Hurteau Implement proper message bus protocol version negociation with static nodes Change 4323733 by Francis.Hurteau Fix VR Pausing Sequence Scrubbing just setting playback speed to 0.0 Change 4324319 by Jamie.Dale Exposed transactions to Blueprints Change 4325847 by Alistair.White Copying //Tasks/UE4/Private-PixelStreaming@4325566 to Dev-Enterprise-Minimal (//UE4/Dev-Enterprise-Minimal) This adds the new experimental PixelStreaming plugin to allow streaming of an Unreal client's audio & video stream to a browser through the WebRTC protocol to support new uses for enterprise customers. Change 4326282 by Simon.Tourangeau nDisplay native present handler Change 4326581 by Jamie.Dale Replacing FDateTime with int64 Ticks value to workaround UE-63485 Change 4326599 by Homam.Bahnassi Moving texture coords outside UVEdit function to allow using different UV channels. Change 4333250 by Francis.Hurteau Small TFuture changes: * cleans up TFuture::Then with usage of TUniqueFunction * added TFuture::Reset to invalidate it and remove continuation from a future shared state Change 4333359 by Homam.Bahnassi Support scaling and rotating UVs around arbitrary pivot Change 4333566 by Johan.Duparc Expose ProxyLOD functionalities to Scripting #jira UEENT-1788 Change 4333988 by Jamie.Dale Allow UHT to parse FText default parameter values INVTEXT, NSLOCTEXT, LOCTABLE, and FText::GetEmpty() are supported. LOCTEXT isn't as it relies on an external macro that is known to C++ but not to UHT (NSLOCTEXT can easily be used instead). Change 4335020 by Francis.Hurteau Uncomment MessageBus::Send deprecation notice for 4.21 Update MessageBus Send usage to new API Change 4335195 by JeanMichel.Dignard Add a SetLodFromStaticMesh script utility function #jira UEENT-1789 Change 4335231 by Anousack.Kitisa Added functions to generate planar, cylindrical, box UV mapping. #jira UEENT-1598 Change 4335373 by Jamie.Dale Cleaned up some places creating empty literal texts Change 4335458 by Jamie.Dale Allow UHT to parse FText() as an alias of FText::GetEmpty() when processing default values Change 4335875 by Max.Chen Sequencer: Clear RF_Transient on pasted tracks/sections #jira UE-63537 Change 4336497 by Johan.Duparc ProxyLOD: Fix progress bar issue - removed duplicated code - removed duplicated LongTask object #jira UEENT-1788 Change 4336723 by Jamie.Dale Ensure that Python generated types create their CDO at the correct point #jira UE-62895 Change 4340594 by Ben.Marsh Fix manifest being invalidated when building two enterprise targets in a row. Fixes CIS error. #jira UE-63644 [CL 4342443 by JeanMichel Dignard in Main branch]
2018-09-04 16:35:02 -04:00
}
webRtcPlayerObj.onDataChannelMessage = function (data) {
var view = new Uint8Array(data);
if (view[0] == ToClientMessageType.QualityControlOwnership)
{
let ownership = view[1] == 0 ? false : true;
// If we own the quality control, we can't relenquish it. We only loose
// quality control when another peer asks for it
if (qualityControlOwnershipCheckBox != null) {
qualityControlOwnershipCheckBox.disabled = ownership;
qualityControlOwnershipCheckBox.checked = ownership;
}
} else if (view[0] == ToClientMessageType.Response) {
let response = new TextDecoder("utf-16").decode(data.slice(1));
for (let listener of responseEventListeners.values()) {
listener(response);
}
}
}
socket.on('webrtc-answer', function(webRTCData) {
webRtcPlayerObj.receiveAnswer(webRTCData);
let printInterval = 5 * 60 * 1000; /*Print every 5 minutes*/
let nextPrintDuration = printInterval;
webRtcPlayerObj.onAggregatedStats = (aggregatedStats) => {
let numberFormat = new Intl.NumberFormat(window.navigator.language, { maximumFractionDigits: 0 });
let timeFormat = new Intl.NumberFormat(window.navigator.language, { maximumFractionDigits: 0, minimumIntegerDigits: 2 });
let statsText = '';
// Calculate duration of run
let runTime = (aggregatedStats.timestamp - aggregatedStats.timestampStart) / 1000;
let timeValues = [];
let timeDurations = [60, 60]
for(let timeIndex = 0; timeIndex < timeDurations.length; timeIndex ++)
{
timeValues.push(runTime % timeDurations[timeIndex]);
runTime = runTime / timeDurations[timeIndex];
}
timeValues.push(runTime);
let runTimeSeconds = timeValues[0];
let runTimeMinutes = Math.floor(timeValues[1]);
let runTimeHours = Math.floor([timeValues[2]]);
receivedBytesMeasurement = 'B'
receivedBytes = aggregatedStats.hasOwnProperty('bytesReceived') ? aggregatedStats.bytesReceived : 0;
let dataMeasurements = ['kB', 'MB', 'GB'];
for(let index = 0; index < dataMeasurements.length; index++){
if(receivedBytes < 100 * 1000)
break;
receivedBytes = receivedBytes / 1000;
receivedBytesMeasurement = dataMeasurements[index];
};
statsText += `Duration: ${timeFormat.format((runTimeHours))}:${timeFormat.format((runTimeMinutes))}:${timeFormat.format((runTimeSeconds))}</br>`;
statsText += `Video Resolution: ${
aggregatedStats.hasOwnProperty('frameWidth') && aggregatedStats.frameWidth && aggregatedStats.hasOwnProperty('frameHeight') && aggregatedStats.frameHeight?
aggregatedStats.frameWidth + 'x' + aggregatedStats.frameHeight : 'N/A'
}</br>`;
statsText += `Received (${receivedBytesMeasurement}): ${numberFormat.format((receivedBytes))}</br>`;
statsText += `Frames Decoded: ${aggregatedStats.hasOwnProperty('framesDecoded') ? numberFormat.format(aggregatedStats.framesDecoded) : 'N/A'}</br>`;
statsText += `Packets Lost: ${aggregatedStats.hasOwnProperty('packetsLost') ? numberFormat.format(aggregatedStats.packetsLost) : 'N/A'}</br>`;
statsText += `Bitrate (kbps): ${aggregatedStats.hasOwnProperty('bitrate') ? numberFormat.format(aggregatedStats.bitrate) : 'N/A'}</br>`;
statsText += `Framerate: ${aggregatedStats.hasOwnProperty('framerate') ? numberFormat.format(aggregatedStats.framerate) : 'N/A'}</br>`;
statsText += `Frames dropped: ${aggregatedStats.hasOwnProperty('framesDropped') ? numberFormat.format(aggregatedStats.framesDropped) : 'N/A'}</br>`;
statsText += `Latency (ms): ${aggregatedStats.hasOwnProperty('currentRoundTripTime') ? numberFormat.format(aggregatedStats.currentRoundTripTime * 1000) : 'N/A'}</br>`;
let statsDiv = document.getElementById("stats");
if(statsDiv){
statsDiv.innerHTML = statsText;
}
if(print_stats){
if(aggregatedStats.timestampStart){
if((aggregatedStats.timestamp - aggregatedStats.timestampStart) > nextPrintDuration ){
console.log(JSON.stringify(aggregatedStats));
if(socket.connected)
socket.emit('webrtc-stats', aggregatedStats);
nextPrintDuration += printInterval;
}
}
}
}
webRtcPlayerObj.aggregateStats(1 * 1000 /*Check every 1 second*/);
//let displayStats = () => { webRtcPlayerObj.getStats( (s) => { s.forEach(stat => { console.log(JSON.stringify(stat)); }); } ); }
//var displayStatsIntervalId = setInterval(displayStats, 30 * 1000);
});
socket.on('webrtc-ice', function(iceCandidate) {
if(webRtcPlayerObj)
webRtcPlayerObj.handleCandidateFromServer(iceCandidate);
});
registerInputs(webRtcPlayerObj.video);
createWebRtcOffer();
return webRtcPlayerObj.video;
}
var styleWidth;
var styleHeight;
var styleTop;
var styleLeft;
var styleCursor = 'default';
var styleAdditional;
const ControlSchemeType = {
// A mouse can lock inside the WebRTC player so the user can simply move the
// mouse to control the orientation of the camera. The user presses the
// Escape key to unlock the mouse.
LockedMouse : 0,
// A mouse can hover over the WebRTC player so the user needs to click and
// drag to control the orientation of the camera.
HoveringMouse : 1
};
var inputOptions = {
// The control scheme controls the behaviour of the mouse when it interacts
// with the WebRTC player.
controlScheme: ControlSchemeType.LockedMouse,
// Browser keys are those which are typically used by the browser UI. We
// usually want to suppress these to allow, for example, UE4 to show shader
// complexity with the F5 key without the web page refreshing.
suppressBrowserKeys: true,
// UE4 has a faketouches option which fakes a single finger touch when the
// user drags with their mouse. We may perform the reverse; a single finger
// touch may be converted into a mouse drag UE4 side. This allows a
// non-touch application to be controlled partially via a touch device.
fakeMouseWithTouches: false
};
function resizePlayerStyleToFillWindow(playerElement) {
let videoElement = playerElement.getElementsByTagName("VIDEO");
// Fill the player display in window, keeping picture's aspect ratio.
let windowAspectRatio = window.innerHeight / window.innerWidth;
let playerAspectRatio = playerElement.clientHeight / playerElement.clientWidth;
// We want to keep the video ratio correct for the video stream
let videoAspectRatio = videoElement.videoHeight / videoElement.videoWidth;
if(isNaN(videoAspectRatio)){
//Video is not initialised yet so set playerElement to size of window
styleWidth = window.innerWidth;
styleHeight = window.innerHeight;
styleTop = 0;
styleLeft = 0;
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
} else if (windowAspectRatio < playerAspectRatio) {
// Window height is the constraining factor so to keep aspect ratio change width appropriately
styleWidth = Math.floor(window.innerHeight / videoAspectRatio);
styleHeight = window.innerHeight;
styleTop = 0;
styleLeft = Math.floor((window.innerWidth - styleWidth) * 0.5);
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
} else {
// Window width is the constraining factor so to keep aspect ratio change height appropriately
styleWidth = window.innerWidth;
styleHeight = Math.floor(window.innerWidth * videoAspectRatio);
styleTop = Math.floor((window.innerHeight - styleHeight) * 0.5);
styleLeft = 0;
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
}
}
function resizePlayerStyleToActualSize(playerElement) {
let videoElement = playerElement.getElementsByTagName("VIDEO");
// Display image in its actual size
styleWidth = videoElement.videoWidth;
styleHeight = videoElement.videoHeight;
styleTop = Math.floor((window.innerHeight - styleHeight) * 0.5);
styleLeft = Math.floor((window.innerWidth - styleWidth) * 0.5);
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: " + styleTop + "px; left: " + styleLeft + "px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
}
function resizePlayerStyleToArbitrarySize(playerElement) {
let videoElement = playerElement.getElementsByTagName("VIDEO");
//Video is now 100% of the playerElement, so set the playerElement style
playerElement.style = "top: 0px; left: 0px; width: " + styleWidth + "px; height: " + styleHeight + "px; cursor: " + styleCursor + "; " + styleAdditional;
}
function resizePlayerStyle(event) {
var playerElement = document.getElementById('player');
if(!playerElement)
return;
updateVideoStreamSize();
// Calculating and normalizing positions depends on the width and height of
// the player.
playerElementClientRect = playerElement.getBoundingClientRect();
setupNormalizeAndQuantize();
if (playerElement.classList.contains('fixed-size'))
return;
let checkBox = document.getElementById('enlarge-display-to-fill-window-tgl');
let windowSmallerThanPlayer = window.innerWidth < playerElement.videoWidth || window.innerHeight < playerElement.videoHeight;
if (checkBox != null) {
if (checkBox.checked || windowSmallerThanPlayer) {
resizePlayerStyleToFillWindow(playerElement);
} else {
resizePlayerStyleToActualSize(playerElement);
}
} else {
resizePlayerStyleToArbitrarySize(playerElement);
}
}
function updateVideoStreamSize() {
if (!matchViewportResolution) {
return;
}
var now = new Date().getTime();
if (now - lastTimeResized > 1000) {
var playerElement = document.getElementById('player');
if (!playerElement)
return;
let descriptor = {
Console: 'setres ' + playerElement.clientWidth + 'x' + playerElement.clientHeight
};
emitUIInteraction(descriptor);
console.log(descriptor);
lastTimeResized = new Date().getTime();
}
else {
console.log('Resizing too often - skipping');
clearTimeout(resizeTimeout);
resizeTimeout = setTimeout(updateVideoStreamSize, 1000);
}
}
// Fix for bug in iOS where windowsize is not correct at instance or orientation change
// https://github.com/dimsemenov/PhotoSwipe/issues/1315
var _orientationChangeTimeout;
function onOrientationChange(event){
clearTimeout(_orientationChangeTimeout);
_orientationChangeTimeout = setTimeout(function() {
resizePlayerStyle();
}, 500);
}
// Must be kept in sync with PixelStreamingProtocol::EToUE4Msg C++ enum.
const MessageType = {
/**********************************************************************/
/*
* Control Messages. Range = 0..49.
*/
IFrameRequest : 0,
RequestQualityControl: 1,
MaxFpsRequest: 2,
AverageBitrateRequest: 3,
StartStreaming: 4,
StopStreaming: 5,
/**********************************************************************/
/*
* Input Messages. Range = 50..89.
*/
// Generic Input Messages. Range = 50..59.
UIInteraction: 50,
Command: 51,
// Keyboard Input Message. Range = 60..69.
KeyDown: 60,
KeyUp: 61,
KeyPress: 62,
// Mouse Input Messages. Range = 70..79.
MouseEnter: 70,
MouseLeave: 71,
MouseDown: 72,
MouseUp: 73,
MouseMove: 74,
MouseWheel: 75,
// Touch Input Messages. Range = 80..89.
TouchStart: 80,
TouchEnd: 81,
TouchMove: 82,
/**************************************************************************/
};
// A generic message has a type and a descriptor.
function emitDescriptor(messageType, descriptor) {
// Convert the dscriptor object into a JSON string.
let descriptorAsString = JSON.stringify(descriptor);
// Add the UTF-16 JSON string to the array byte buffer, going two bytes at
// a time.
let data = new DataView(new ArrayBuffer(1 + 2 + 2 * descriptorAsString.length));
let byteIdx = 0;
data.setUint8(byteIdx, messageType);
byteIdx++;
data.setUint16(byteIdx, descriptorAsString.length, true);
byteIdx += 2;
for (i = 0; i < descriptorAsString.length; i++) {
data.setUint16(byteIdx, descriptorAsString.charCodeAt(i), true);
byteIdx += 2;
}
sendInputData(data.buffer);
}
// A UI interation will occur when the user presses a button powered by
// JavaScript as opposed to pressing a button which is part of the pixel
// streamed UI from the UE4 client.
function emitUIInteraction(descriptor) {
emitDescriptor(MessageType.UIInteraction, descriptor);
}
// A build-in command can be sent to UE4 client. The commands are defined by a
// JSON descriptor and will be executed automatically.
// The currently supported commands are:
//
// 1. A command to run any console command:
// "{ ConsoleCommand: <string> }"
//
// 2. A command to change the resolution to the given width and height.
// "{ Resolution: { Width: <value>, Height: <value> } }"
//
// 3. A command to change the encoder settings by reducing the bitrate by the
// given percentage.
// "{ Encoder: { BitrateReduction: <value> } }"
function emitCommand(descriptor) {
emitDescriptor(MessageType.Command, descriptor);
}
function requestQualityControl() {
sendInputData(new Uint8Array([MessageType.RequestQualityControl]).buffer);
}
var playerElementClientRect = undefined;
var normalizeAndQuantizeUnsigned = undefined;
var normalizeAndQuantizeSigned = undefined;
function setupNormalizeAndQuantize() {
let playerElement = document.getElementById('player');
let videoElement = playerElement.getElementsByTagName("video");
if (playerElement && videoElement.length > 0) {
let playerAspectRatio = playerElement.clientHeight / playerElement.clientWidth;
let videoAspectRatio = videoElement[0].videoHeight / videoElement[0].videoWidth;
// Unsigned XY positions are the ratio (0.0..1.0) along a viewport axis,
// quantized into an uint16 (0..65536).
// Signed XY deltas are the ratio (-1.0..1.0) along a viewport axis,
// quantized into an int16 (-32767..32767).
// This allows the browser viewport and client viewport to have a different
// size.
// Hack: Currently we set an out-of-range position to an extreme (65535)
// as we can't yet accurately detect mouse enter and leave events
// precisely inside a video with an aspect ratio which causes mattes.
if (playerAspectRatio > videoAspectRatio) {
if (print_inputs) {
console.log('Setup Normalize and Quantize for playerAspectRatio > videoAspectRatio');
}
let ratio = playerAspectRatio / videoAspectRatio;
// Unsigned.
normalizeAndQuantizeUnsigned = (x, y) => {
let normalizedX = x / playerElement.clientWidth;
let normalizedY = ratio * (y / playerElement.clientHeight - 0.5) + 0.5;
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) {
return {
inRange: false,
x: 65535,
y: 65535
};
} else {
return {
inRange: true,
x: normalizedX * 65536,
y: normalizedY * 65536
};
}
}
// Signed.
normalizeAndQuantizeSigned = (x, y) => {
let normalizedX = x / (0.5 * playerElement.clientWidth);
let normalizedY = (ratio * y) / (0.5 * playerElement.clientHeight);
return {
x: normalizedX * 32767,
y: normalizedY * 32767
};
}
} else {
if (print_inputs) {
console.log('Setup Normalize and Quantize for playerAspectRatio <= videoAspectRatio');
}
let ratio = videoAspectRatio / playerAspectRatio;
normalizeAndQuantizeUnsigned = (x, y) => {
// Unsigned.
let normalizedX = ratio * (x / playerElement.clientWidth - 0.5) + 0.5;
let normalizedY = y / playerElement.clientHeight;
if (normalizedX < 0.0 || normalizedX > 1.0 || normalizedY < 0.0 || normalizedY > 1.0) {
return {
inRange: false,
x: 65535,
y: 65535
};
} else {
return {
inRange: true,
x: normalizedX * 65536,
y: normalizedY * 65536
};
}
}
normalizeAndQuantizeSigned = (x, y) => {
// Signed.
let normalizedX = (ratio * x) / (0.5 * playerElement.clientWidth);
let normalizedY = y / (0.5 * playerElement.clientHeight);
return {
x: normalizedX * 32767,
y: normalizedY * 32767
};
}
}
}
}
function emitMouseMove(x, y, deltaX, deltaY) {
if (print_inputs) {
console.log(`x: ${x}, y:${y}, dX: ${deltaX}, dY: ${deltaY}`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
let delta = normalizeAndQuantizeSigned(deltaX, deltaY);
var Data = new DataView(new ArrayBuffer(9));
Data.setUint8(0, MessageType.MouseMove);
Data.setUint16(1, coord.x, true);
Data.setUint16(3, coord.y, true);
Data.setInt16(5, delta.x, true);
Data.setInt16(7, delta.y, true);
sendInputData(Data.buffer);
}
function emitMouseDown(button, x, y) {
if (print_inputs) {
console.log(`mouse button ${button} down at (${x}, ${y})`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
var Data = new DataView(new ArrayBuffer(6));
Data.setUint8(0, MessageType.MouseDown);
Data.setUint8(1, button);
Data.setUint16(2, coord.x, true);
Data.setUint16(4, coord.y, true);
sendInputData(Data.buffer);
}
function emitMouseUp(button, x, y) {
if (print_inputs) {
console.log(`mouse button ${button} up at (${x}, ${y})`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
var Data = new DataView(new ArrayBuffer(6));
Data.setUint8(0, MessageType.MouseUp);
Data.setUint8(1, button);
Data.setUint16(2, coord.x, true);
Data.setUint16(4, coord.y, true);
sendInputData(Data.buffer);
}
function emitMouseWheel(delta, x, y) {
if (print_inputs) {
console.log(`mouse wheel with delta ${delta} at (${x}, ${y})`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
var Data = new DataView(new ArrayBuffer(7));
Data.setUint8(0, MessageType.MouseWheel);
Data.setInt16(1, delta, true);
Data.setUint16(3, coord.x, true);
Data.setUint16(5, coord.y, true);
sendInputData(Data.buffer);
}
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/button
const MouseButton = {
MainButton: 0, // Left button.
AuxiliaryButton: 1, // Wheel button.
SecondaryButton: 2 // Right button.
};
// https://developer.mozilla.org/en-US/docs/Web/API/MouseEvent/buttons
const MouseButtonsMask = {
PrimaryButton: 1, // Left button.
SecondaryButton: 2, // Right button.
AuxiliaryButton: 4 // Wheel button.
};
// If the user has any mouse buttons pressed then release them.
function releaseMouseButtons(buttons, x, y) {
if (buttons & MouseButtonsMask.PrimaryButton) {
emitMouseUp(MouseButton.MainButton, x, y);
}
if (buttons & MouseButtonsMask.SecondaryButton) {
emitMouseUp(MouseButton.SecondaryButton, x, y);
}
if (buttons & MouseButtonsMask.AuxiliaryButton) {
emitMouseUp(MouseButton.AuxiliaryButton, x, y);
}
}
// If the user has any mouse buttons pressed then press them again.
function pressMouseButtons(buttons, x, y) {
if (buttons & MouseButtonsMask.PrimaryButton) {
emitMouseDown(MouseButton.MainButton, x, y);
}
if (buttons & MouseButtonsMask.SecondaryButton) {
emitMouseDown(MouseButton.SecondaryButton, x, y);
}
if (buttons & MouseButtonsMask.AuxiliaryButton) {
emitMouseDown(MouseButton.AuxiliaryButton, x, y);
}
}
function registerInputs(playerElement){
if(!playerElement)
return;
registerMouseEnterAndLeaveEvents(playerElement);
registerTouchEvents(playerElement);
}
function registerMouseEnterAndLeaveEvents(playerElement) {
playerElement.onmouseenter = function (e) {
if (print_inputs) {
console.log('mouse enter');
}
var Data = new DataView(new ArrayBuffer(1));
Data.setUint8(0, MessageType.MouseEnter);
sendInputData(Data.buffer);
playerElement.pressMouseButtons(e);
}
playerElement.onmouseleave = function (e) {
if (print_inputs) {
console.log('mouse leave');
}
var Data = new DataView(new ArrayBuffer(1));
Data.setUint8(0, MessageType.MouseLeave);
sendInputData(Data.buffer);
playerElement.releaseMouseButtons(e);
}
}
// A locked mouse works by the user clicking in the browser player and the
// cursor disappears and is locked. The user moves the cursor and the camera
// moves, for example. The user presses escape to free the mouse.
function registerLockedMouseEvents(playerElement) {
var x = playerElement.width / 2;
var y = playerElement.height / 2;
playerElement.requestPointerLock = playerElement.requestPointerLock || playerElement.mozRequestPointerLock;
document.exitPointerLock = document.exitPointerLock || document.mozExitPointerLock;
playerElement.onclick = function () {
playerElement.requestPointerLock();
};
// Respond to lock state change events
document.addEventListener('pointerlockchange', lockStateChange, false);
document.addEventListener('mozpointerlockchange', lockStateChange, false);
function lockStateChange() {
if (document.pointerLockElement === playerElement ||
document.mozPointerLockElement === playerElement) {
console.log('Pointer locked');
document.addEventListener("mousemove", updatePosition, false);
} else {
console.log('The pointer lock status is now unlocked');
document.removeEventListener("mousemove", updatePosition, false);
}
}
function updatePosition(e) {
x += e.movementX;
y += e.movementY;
if (x > styleWidth) {
x -= styleWidth;
}
if (y > styleHeight) {
y -= styleHeight;
}
if (x < 0) {
x = styleWidth + x;
}
if (y < 0) {
y = styleHeight - y;
}
emitMouseMove(x, y, e.movementX, e.movementY);
}
playerElement.onmousedown = function (e) {
emitMouseDown(e.button, x, y);
};
playerElement.onmouseup = function (e) {
emitMouseUp(e.button, x, y);
};
playerElement.onmousewheel = function (e) {
emitMouseWheel(e.wheelDelta, x, y);
}
playerElement.pressMouseButtons = function (e) {
pressMouseButtons(e.buttons, x, y);
}
playerElement.releaseMouseButtons = function (e) {
releaseMouseButtons(e.buttons, x, y);
}
}
// A hovering mouse works by the user clicking the mouse button when they want
// the cursor to have an effect over the video. Otherwise the cursor just
// passes over the browser.
function registerHoveringMouseEvents(playerElement) {
styleCursor = 'none'; // We will rely on UE4 client's software cursor.
playerElement.onmousemove = function (e) {
emitMouseMove(e.offsetX, e.offsetY, e.movementX, e.movementY);
e.preventDefault();
}
playerElement.onmousedown = function (e) {
emitMouseDown(e.button, e.offsetX, e.offsetY);
e.preventDefault();
};
playerElement.onmouseup = function (e) {
emitMouseUp(e.button, e.offsetX, e.offsetY);
e.preventDefault();
};
// When the context menu is shown then it is safest to release the button
// which was pressed when the event happened. This will guarantee we will
// get at least one mouse up corresponding to a mouse down event. Otherwise
// the mouse can get stuck.
// https://github.com/facebook/react/issues/5531
playerElement.oncontextmenu = function (e) {
emitMouseUp(e.button, e.offsetX, e.offsetY);
}
if ('onmousewheel' in playerElement) {
playerElement.onmousewheel = function (e) {
emitMouseWheel(e.wheelDelta, e.offsetX, e.offsetY);
e.preventDefault();
}
} else {
playerElement.addEventListener('DOMMouseScroll', function (e) {
emitMouseWheel(e.detail * -120, e.offsetX, e.offsetY);
e.preventDefault();
}, false)
}
playerElement.pressMouseButtons = function (e) {
pressMouseButtons(e.buttons, e.offsetX, e.offsetY);
}
playerElement.releaseMouseButtons = function (e) {
releaseMouseButtons(e.buttons, e.offsetX, e.offsetY);
}
}
function registerTouchEvents(playerElement) {
// We need to assign a unique identifier to each finger.
// We do this by mapping each Touch object to the identifier.
var fingers = [9, 8, 7, 6, 5, 4, 3, 2, 1, 0];
var fingerIds = {};
function rememberTouch(touch) {
let finger = fingers.pop();
if (finger === undefined) {
console.log('exhausted touch indentifiers');
}
fingerIds[touch.identifier] = finger;
}
function forgetTouch(touch) {
fingers.push(fingerIds[touch.identifier]);
delete fingerIds[touch.identifier];
}
function emitTouchData(type, touches) {
let data = new DataView(new ArrayBuffer(2 + 6 * touches.length));
data.setUint8(0, type);
data.setUint8(1, touches.length);
let byte = 2;
for (let t = 0; t < touches.length; t++) {
let touch = touches[t];
let x = touch.clientX - playerElement.offsetLeft;
let y = touch.clientY - playerElement.offsetTop;
if (print_inputs) {
console.log(`F${fingerIds[touch.identifier]}=(${x}, ${y})`);
}
let coord = normalizeAndQuantizeUnsigned(x, y);
data.setUint16(byte, coord.x, true);
byte += 2;
data.setUint16(byte, coord.y, true);
byte += 2;
data.setUint8(byte, fingerIds[touch.identifier], true);
byte += 1;
data.setUint8(byte, 255 * touch.force, true); // force is between 0.0 and 1.0 so quantize into byte.
byte += 1;
}
sendInputData(data.buffer);
}
if (inputOptions.fakeMouseWithTouches) {
var finger = undefined;
playerElement.ontouchstart = function (e) {
if (finger === undefined) {
let firstTouch = e.changedTouches[0];
finger = {
id: firstTouch.identifier,
x: firstTouch.clientX - playerElementClientRect.left,
y: firstTouch.clientY - playerElementClientRect.top
};
// Hack: Mouse events require an enter and leave so we just
// enter and leave manually with each touch as this event
// is not fired with a touch device.
playerElement.onmouseenter(e);
emitMouseDown(MouseButton.MainButton, finger.x, finger.y);
}
e.preventDefault();
}
playerElement.ontouchend = function (e) {
for (let t = 0; t < e.changedTouches.length; t++) {
let touch = e.changedTouches[t];
if (touch.identifier === finger.id) {
let x = touch.clientX - playerElementClientRect.left;
let y = touch.clientY - playerElementClientRect.top;
emitMouseUp(MouseButton.MainButton, x, y);
// Hack: Manual mouse leave event.
playerElement.onmouseleave(e);
finger = undefined;
break;
}
}
e.preventDefault();
}
playerElement.ontouchmove = function (e) {
for (let t = 0; t < e.touches.length; t++) {
let touch = e.touches[t];
if (touch.identifier === finger.id) {
let x = touch.clientX - playerElementClientRect.left;
let y = touch.clientY - playerElementClientRect.top;
emitMouseMove(x, y, x - finger.x, y - finger.y);
finger.x = x;
finger.y = y;
break;
}
}
e.preventDefault();
}
} else {
playerElement.ontouchstart = function (e) {
// Assign a unique identifier to each touch.
for (let t = 0; t < e.changedTouches.length; t++) {
rememberTouch(e.changedTouches[t]);
}
if (print_inputs) {
console.log('touch start');
}
emitTouchData(MessageType.TouchStart, e.changedTouches);
e.preventDefault();
}
playerElement.ontouchend = function (e) {
if (print_inputs) {
console.log('touch end');
}
emitTouchData(MessageType.TouchEnd, e.changedTouches);
// Re-cycle unique identifiers previously assigned to each touch.
for (let t = 0; t < e.changedTouches.length; t++) {
forgetTouch(e.changedTouches[t]);
}
e.preventDefault();
}
playerElement.ontouchmove = function (e) {
if (print_inputs) {
console.log('touch move');
}
emitTouchData(MessageType.TouchMove, e.touches);
e.preventDefault();
}
}
}
// Browser keys do not have a charCode so we only need to test keyCode.
function isKeyCodeBrowserKey(keyCode) {
// Function keys or tab key.
return keyCode >= 112 && keyCode <= 123 || keyCode == 9;
}
function registerKeyboardEvents() {
document.onkeydown = function (e) {
if (print_inputs) {
console.log(`key down ${e.keyCode}, repeat = ${e.repeat}`);
}
sendInputData(new Uint8Array([MessageType.KeyDown, e.keyCode, e.repeat]).buffer);
if (inputOptions.suppressBrowserKeys && isKeyCodeBrowserKey(e.keyCode)) {
e.preventDefault();
}
};
document.onkeyup = function (e) {
if (print_inputs) {
console.log(`key up ${e.keyCode}`);
}
sendInputData(new Uint8Array([MessageType.KeyUp, e.keyCode]).buffer);
if (inputOptions.suppressBrowserKeys && isKeyCodeBrowserKey(e.keyCode)) {
e.preventDefault();
}
};
document.onkeypress = function (e) {
if (print_inputs) {
console.log(`key press ${e.charCode}`);
}
let data = new DataView(new ArrayBuffer(3));
data.setUint8(0, MessageType.KeyPress);
data.setUint16(1, e.charCode, true);
sendInputData(data.buffer);
}
}
function onExpandOverlay_Click() {
let subElement = document.getElementById('overlaySettings');
if (subElement.style.display === "none" || subElement.style.display === "") {
subElement.style.display = "block";
} else {
subElement.style.display = "none";
}
}
function start() {
let statsDiv = document.getElementById("stats");
if(statsDiv){
statsDiv.innerHTML = 'Not connected';
}
if (!connect_on_load || is_reconnection){
showConnectOverlay();
resizePlayerStyle();
} else {
connect();
}
}
function connect() {
socket = io();
socket.on('clientConfig', function (clientConfig) {
onClientConfig(clientConfig);
});
socket.on('message', function (data) {
console.log(`unrecognised message ${data.byteLength}: ${data.slice(0, 50).toString("hex")}`);
});
socket.on('clientCount', function (data) {
var kickButton = document.getElementById('kick-other-players-button');
if (kickButton)
kickButton.value = `Kick (${data.count})`;
});
socket.on('connect', () => {
log("connected");
sendUserConfig();
});
socket.on('error', (error) => {
console.log(`WS error ${error}`);
});
socket.on('disconnect', (reason) => {
console.log(`Connection is closed: ${reason}`);
socket.close();
socket = undefined;
is_reconnection = true;
// destroy `webRtcPlayerObj` if any
let playerDiv = document.getElementById('player');
if (webRtcPlayerObj) {
playerDiv.removeChild(webRtcPlayerObj.video);
webRtcPlayerObj.close();
webRtcPlayerObj = undefined;
}
start();
});
}
/**
* Config data to sent to the Cirrus web server.
*/
function sendUserConfig() {
userConfig = {
emitData: 'ArrayBuffer'
};
userConfigString = JSON.stringify(userConfig);
log(`userConfig = ${userConfigString}`);
socket.emit('userConfig', userConfigString);
}
/**
* Config data received from WebRTC sender via the Cirrus web server
*/
function onClientConfig(clientConfig) {
log(`clientConfig = ${JSON.stringify(clientConfig)}`);
let playerDiv = document.getElementById('player');
let playerElement = setupWebRtcPlayer(playerDiv, clientConfig)
resizePlayerStyle();
switch (inputOptions.controlScheme) {
case ControlSchemeType.HoveringMouse:
registerHoveringMouseEvents(playerElement);
break;
case ControlSchemeType.LockedMouse:
registerLockedMouseEvents(playerElement);
break;
default:
console.log(`ERROR: Unknown control scheme ${inputOptions.controlScheme}`);
registerLockedMouseEvents(playerElement);
break;
}
}
function load() {
setupHtmlEvents();
registerKeyboardEvents();
start();
}