diff options
| author | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-03-08 01:19:58 +0200 |
|---|---|---|
| committer | Roy Ben Shabat <Roy.mail.net@gmail.com> | 2020-03-08 01:19:58 +0200 |
| commit | 436ceaea56ecff755476a3796cff72e1da39dfc6 (patch) | |
| tree | 5d8ebc02e999f777378df5e699f0b13a9827d622 /Software | |
| parent | 9d18d9ec9658af3716814625b608d58ad3daa14c (diff) | |
| download | Tango-436ceaea56ecff755476a3796cff72e1da39dfc6.tar.gz Tango-436ceaea56ecff755476a3796cff72e1da39dfc6.zip | |
Integrated WebRTC channel to PPC/FSE.
Diffstat (limited to 'Software')
33 files changed, 816 insertions, 222 deletions
diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj index 75cae76a9..477678559 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Tango.FSE.PPCConsole.csproj @@ -37,6 +37,9 @@ <Reference Include="ControlzEx, Version=3.0.2.4, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll</HintPath> </Reference> + <Reference Include="Dragablz, Version=0.0.3.203, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\..\packages\Dragablz.0.0.3.203\lib\net45\Dragablz.dll</HintPath> + </Reference> <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <HintPath>..\..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath> </Reference> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/ConsoleView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/ConsoleView.xaml index 9514db919..0a26fc8b4 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/ConsoleView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/ConsoleView.xaml @@ -11,7 +11,7 @@ mc:Ignorable="d" d:DesignHeight="450" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:ConsoleViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.ConsoleViewVM}"> <Grid> - <Border Background="#121212" CornerRadius="10" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1"> + <Border Background="#121212" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1"> <console:ConsoleControl Background="#121212" Margin="10" BorderBrush="{StaticResource FSE_BorderBrush}" SuggestionsBackground="{StaticResource FSE_PrimaryBackgroundBrush}" SuggestionsBorderBrush="{StaticResource FSE_BorderBrush}" SuggestionsForeground="Silver" DataContext="{Binding ConsoleVM}"> <console:ConsoleControl.BusyTemplate> <DataTemplate> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml index 39fb4549d..2246fa873 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/MainView.xaml @@ -4,6 +4,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:global="clr-namespace:Tango.FSE.PPCConsole" + xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz" xmlns:vm="clr-namespace:Tango.FSE.PPCConsole.ViewModels" xmlns:local="clr-namespace:Tango.FSE.PPCConsole.Views" xmlns:console="clr-namespace:Tango.Console;assembly=Tango.Console" @@ -11,31 +12,35 @@ mc:Ignorable="d" d:DesignHeight="720" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:MainViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.MainViewVM}"> <Grid Margin="10"> - <Grid.RowDefinitions> - <RowDefinition Height="327*"/> - <RowDefinition Height="5"/> - <RowDefinition Height="50*"/> - </Grid.RowDefinitions> + <Grid> <Grid.ColumnDefinitions> - <ColumnDefinition Width="257*"/> - <ColumnDefinition Width="137*"/> + <ColumnDefinition Width="200" /> + <ColumnDefinition Width="1*" /> </Grid.ColumnDefinitions> - <!--CONSOLE--> <Grid> - <local:ConsoleView Margin="5" /> + <ListBox x:Name="listMenu" HorizontalContentAlignment="Stretch" Focusable="False"> + <Button Margin="5" HorizontalContentAlignment="Right" IsHitTestVisible="False" Style="{StaticResource FSE_FlatButton_ForegroundAccentHover}">CONSOLE</Button> + <Button Margin="5" HorizontalContentAlignment="Right" IsHitTestVisible="False" Style="{StaticResource FSE_FlatButton_ForegroundAccentHover}">REMOTE DESKTOP</Button> + </ListBox> </Grid> - <!--REMOTE DESKTOP--> - <Grid Grid.Column="1"> - <local:RemoteDesktopView Margin="5" /> - </Grid> - </Grid> + <TabControl Margin="10 0 0 0" Background="Transparent" BorderThickness="0" Padding="0" Grid.Column="1" SelectedIndex="{Binding ElementName=listMenu,Path=SelectedIndex,Mode=TwoWay}"> + <TabItem Header="CONSOLE" Visibility="Collapsed"> + <!--CONSOLE--> + <Grid> + <local:ConsoleView /> + </Grid> + </TabItem> - <!--SOMETHING OTHER ?--> - <Grid Grid.Row="2"> - + <TabItem Header="REMOTE DESKTOP" Visibility="Collapsed"> + <!--REMOTE DESKTOP--> + <Grid Grid.Column="1"> + <local:RemoteDesktopView /> + </Grid> + </TabItem> + </TabControl> </Grid> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml index 9d3308741..040379ced 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/Views/RemoteDesktopView.xaml @@ -9,11 +9,42 @@ xmlns:console="clr-namespace:Tango.Console;assembly=Tango.Console" xmlns:material="http://materialdesigninxaml.net/winfx/xaml/themes" mc:Ignorable="d" - d:DesignHeight="1280" d:DesignWidth="800" d:DataContext="{d:DesignInstance Type=vm:RemoteDesktopViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RemoteDesktopViewVM}"> + d:DesignHeight="800" d:DesignWidth="1280" d:DataContext="{d:DesignInstance Type=vm:RemoteDesktopViewVM, IsDesignTimeCreatable=False}" DataContext="{x:Static global:ViewModelLocator.RemoteDesktopViewVM}"> <Grid> <DockPanel> + <Border DockPanel.Dock="Right" CornerRadius="15" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1"> + <Grid> + <Border CornerRadius="1" BorderThickness="30"> + <Border.BorderBrush> + <LinearGradientBrush> + <GradientStop Color="#101010" Offset="0" /> + <GradientStop Color="#202020" Offset="1" /> + </LinearGradientBrush> + </Border.BorderBrush> + <Border BorderThickness="1"> + <Border.BorderBrush> + <LinearGradientBrush> + <GradientStop Color="#3E3E3E" Offset="0" /> + <GradientStop Color="#101010" Offset="0.5" /> + <GradientStop Color="#3E3E3E" Offset="1" /> + </LinearGradientBrush> + </Border.BorderBrush> + <Border.Background> + <ImageBrush ImageSource="{StaticResource FSE_PPC_Back}" /> + </Border.Background> + <Border Width="{Binding RelativeSource={RelativeSource Self},Path=ActualHeight,Converter={StaticResource MathOperatorConverter},ConverterParameter='/1.7777',FallbackValue=500,TargetNullValue=500}"> + <Image x:Name="img" Focusable="True" Source="{Binding Source}" RenderOptions.BitmapScalingMode="Fant" Stretch="Fill" Visibility="{Binding RemoteDesktopProvider.InSession,Converter={StaticResource BooleanToVisibilityConverter}}"></Image> + </Border> + </Border> + </Border> + + <Grid IsHitTestVisible="False"> + <material:PackIcon Visibility="{Binding RemoteDesktopProvider.IsWebRtcActive,Converter={StaticResource BooleanToVisibilityConverter}}" Kind="LightningBolt" HorizontalAlignment="Right" VerticalAlignment="Top" Width="16" Height="16" Margin="10" Foreground="{StaticResource FSE_GreenBrush}" /> + </Grid> + </Grid> + </Border> - <Grid DockPanel.Dock="Bottom" Height="50" Margin="0 10 0 0"> + <Grid HorizontalAlignment="Center" VerticalAlignment="Center" Height="50" Width="400"> <Grid.ColumnDefinitions> <ColumnDefinition Width="1*" /> <ColumnDefinition Width="50*" /> @@ -22,30 +53,6 @@ <Button Command="{Binding StopCommand}" IsEnabled="{Binding RemoteDesktopProvider.InSession}" Grid.Column="1" Style="{StaticResource FSE_RaisedButton_Dark_Hover}">STOP</Button> <Button Command="{Binding StartCommand}" IsEnabled="{Binding RemoteDesktopProvider.CanStartSession}" Grid.Column="2" Margin="10 0 0 0" Style="{StaticResource FSE_RaisedButton_Dark_Hover}">START</Button> </Grid> - - <Border CornerRadius="15" BorderBrush="{StaticResource FSE_BorderBrush}" BorderThickness="1"> - <Border CornerRadius="1" BorderThickness="30"> - <Border.BorderBrush> - <LinearGradientBrush> - <GradientStop Color="#101010" Offset="0" /> - <GradientStop Color="#202020" Offset="1" /> - </LinearGradientBrush> - </Border.BorderBrush> - <Border BorderThickness="1"> - <Border.BorderBrush> - <LinearGradientBrush> - <GradientStop Color="#3E3E3E" Offset="0" /> - <GradientStop Color="#101010" Offset="0.5" /> - <GradientStop Color="#3E3E3E" Offset="1" /> - </LinearGradientBrush> - </Border.BorderBrush> - <Border.Background> - <ImageBrush ImageSource="{StaticResource FSE_PPC_Back}" /> - </Border.Background> - <Image x:Name="img" Focusable="True" Source="{Binding Source}" RenderOptions.BitmapScalingMode="Fant" Stretch="Fill" Visibility="{Binding RemoteDesktopProvider.InSession,Converter={StaticResource BooleanToVisibilityConverter}}"></Image> - </Border> - </Border> - </Border> </DockPanel> </Grid> </UserControl> diff --git a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/packages.config b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/packages.config index d17a56d7d..c795da787 100644 --- a/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/packages.config +++ b/Software/Visual_Studio/FSE/Modules/Tango.FSE.PPCConsole/packages.config @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="ControlzEx" version="3.0.2.4" targetFramework="net461" /> + <package id="Dragablz" version="0.0.3.203" targetFramework="net461" /> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> <package id="MahApps.Metro" version="1.6.5" targetFramework="net461" /> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/DesktopFrameReceivedEventArgs.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/DesktopFrameReceivedEventArgs.cs index 1589c2b99..a88cb4666 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/DesktopFrameReceivedEventArgs.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/DesktopFrameReceivedEventArgs.cs @@ -9,6 +9,15 @@ namespace Tango.FSE.Common.RemoteDesktop { public class DesktopFrameReceivedEventArgs : EventArgs { + public enum FrameOrigin + { + WebSockets, + WebRTC + } + + public BitmapSource Source { get; set; } + + public FrameOrigin Origin { get; set; } } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/IRemoteDesktopProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/IRemoteDesktopProvider.cs index 716739d0a..82f84c267 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/IRemoteDesktopProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/RemoteDesktop/IRemoteDesktopProvider.cs @@ -12,6 +12,8 @@ namespace Tango.FSE.Common.RemoteDesktop public interface IRemoteDesktopProvider { event EventHandler<DesktopFrameReceivedEventArgs> FrameReceived; + bool IsWebRtcActive { get; } + bool EnableWebRtc { get; set; } bool InSession { get; } bool CanStartSession { get; } TimeSpan MouseMoveInterval { get; set; } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml index e78cd767e..464c606e8 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.Common/Resources/Colors.xaml @@ -64,8 +64,8 @@ <!-- primary --> <!--<SolidColorBrush x:Key="PrimaryHueDarkBrush" Color="#4D1DCF"/> <SolidColorBrush x:Key="PrimaryHueDarkForegroundBrush" Color="#FFFFFF"/>--> - <!--accent--><!-- - <SolidColorBrush x:Key="SecondaryAccentBrush" Color="#5C5B5E"/> - <SolidColorBrush x:Key="SecondaryAccentForegroundBrush" Color="#FFFFFF"/>--> + <!--accent--> + <SolidColorBrush x:Key="SecondaryAccentBrush" Color="{StaticResource FSE_PrimaryAccentColor}"/> + <SolidColorBrush x:Key="SecondaryAccentForegroundBrush" Color="{StaticResource FSE_PrimaryForegroundColor}"/> </ResourceDictionary>
\ No newline at end of file diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml index 774681c22..4ca272840 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml @@ -2,14 +2,15 @@ xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes" + xmlns:dragablz="clr-namespace:Dragablz;assembly=Dragablz" xmlns:local="clr-namespace:Tango.FSE.UI" StartupUri="MainWindow.xaml"> <Application.Resources> <ResourceDictionary> <ResourceDictionary.MergedDictionaries> - + <!--LOADS IN App.xaml.cs--> - + <!--<ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/Accents/BaseDark.xaml" /> <ResourceDictionary Source="pack://application:,,,/MahApps.Metro;component/Styles/VS/Colors.xaml" /> @@ -48,6 +49,8 @@ <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/materialdesigntheme.ProgressBar.xaml"/> <ResourceDictionary Source="pack://application:,,,/MaterialDesignThemes.Wpf;component/Themes/MaterialDesignTheme.ComboBox.xaml" /> + <ResourceDictionary Source="pack://application:,,,/Dragablz;component/Themes/materialdesign.xaml"/> + <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Converters.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Colors.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Fonts.xaml" /> @@ -55,6 +58,11 @@ <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Styles.xaml" /> <ResourceDictionary Source="pack://application:,,,/Tango.FSE.Common;component/Resources/Controls.xaml" /> </ResourceDictionary.MergedDictionaries> + + <!-- tell Dragablz tab control to use the Material Design theme --> + <Style TargetType="{x:Type dragablz:TabablzControl}" BasedOn="{StaticResource MaterialDesignTabablzControlStyle}"> + <Setter Property="BorderBrush" Value="Transparent"></Setter> + </Style> </ResourceDictionary> </Application.Resources> </Application> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs index 298563de1..396068ab6 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/App.xaml.cs @@ -2,10 +2,17 @@ using System.Collections.Generic; using System.Configuration; using System.Data; +using System.Diagnostics; using System.Linq; +using System.Net; +using System.Threading; using System.Threading.Tasks; using System.Windows; +using Tango.FSE.Common; using Tango.FSE.Common.Helpers; +using Tango.Integration.Operation; +using Tango.Logging; +using Tango.Settings; namespace Tango.FSE.UI { @@ -14,6 +21,8 @@ namespace Tango.FSE.UI /// </summary> public partial class App : Application { + private LogManager LogManager = LogManager.Default; + public App() : base() { if (!DesignModeHelper.IsInDesignMode()) @@ -28,6 +37,44 @@ namespace Tango.FSE.UI protected override void OnStartup(StartupEventArgs e) { + ThreadPool.SetMaxThreads(1000, 1000); + + //If no debugger is attached and the argument -debug was passed launch the debugger. + if (e.Args.Contains("-debug") && !Debugger.IsAttached) + { + Debugger.Launch(); + } + + //LogManager.RegisterLogger(new ConsoleLogger("Tango PPC Debug")); + LogManager.RegisterLogger(new FileLogger() { EnableAutoLogRemoval = true, EnableMaxFileSizeLimit = true }); + LogManager.RegisterLogger(new VSOutputLogger()); + + //Configure machine operator logger. + var operatorLogger = MachineOperator.EmbeddedLogManager.RegisteredLoggers.SingleOrDefault(x => x is FileLogger) as FileLogger; + if (operatorLogger != null) + { + operatorLogger.EnableAutoLogRemoval = true; + operatorLogger.EnableMaxFileSizeLimit = true; + } + + LogManager.Log("Application Started..."); + + var settings = SettingsManager.Default.GetOrCreate<FSESettings>(); + + //if (settings.LoggingCategories.Count == 0) + //{ + // settings.LoggingCategories.Add(LogCategory.Critical); + // settings.LoggingCategories.Add(LogCategory.Error); + // settings.LoggingCategories.Add(LogCategory.Info); + // settings.LoggingCategories.Add(LogCategory.Warning); + //} + + settings.Save(); + + //LogManager.Categories.AddRange(settings.LoggingCategories); + + WebRequest.DefaultWebProxy = null; + base.OnStartup(e); } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml.cs index acb1e80d5..19d928c37 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/MainWindow.xaml.cs @@ -37,6 +37,12 @@ namespace Tango.FSE.UI IFSEApplicationManager appManager = TangoIOC.Default.GetInstance<IFSEApplicationManager>(); + Closing += (x, e) => + { + e.Cancel = true; + appManager.ShutDown(); + }; + btnMinimize.Click += (_, __) => WindowState = WindowState.Minimized; btnMaximize.Click += (_, __) => WindowState = WindowState == WindowState.Maximized ? WindowState = WindowState.Normal : WindowState = WindowState.Maximized; btnClose.Click += (_, __) => Close(); diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteDesktop/DefaultRemoteDesktopProvider.cs b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteDesktop/DefaultRemoteDesktopProvider.cs index ab98fdbab..53aedb9d9 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteDesktop/DefaultRemoteDesktopProvider.cs +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/RemoteDesktop/DefaultRemoteDesktopProvider.cs @@ -15,16 +15,17 @@ using Tango.Core.Threading; using Tango.FSE.Common.Connection; using Tango.FSE.Common.Notifications; using Tango.FSE.Common.RemoteDesktop; +using Tango.PMR; +using Tango.PMR.Integration; using Tango.RemoteDesktop.Frames; using Tango.RemoteDesktop.Network; using Tango.Transport; +using Tango.WebRTC; namespace Tango.FSE.UI.RemoteDesktop { public class DefaultRemoteDesktopProvider : ExtendedObject, IRemoteDesktopProvider { - - private class MouseMovement { public Point Location { get; set; } @@ -38,9 +39,18 @@ namespace Tango.FSE.UI.RemoteDesktop private IntervalMessageDispatcher<StartRemoteDesktopSessionResponse> _frameDispatcher; private Thread _mouseMoveThread; private ProducerConsumerQueue<MouseMovement> _mouseMovements; + private WebRtcClient _webRtcClient; + private List<IceCandidate> _iceCandidates; + private bool _answerReceived; + + #region Events public event EventHandler<DesktopFrameReceivedEventArgs> FrameReceived; + #endregion + + #region Properties + [TangoInject] private INotificationProvider NotificationProvider { get; set; } @@ -51,6 +61,27 @@ namespace Tango.FSE.UI.RemoteDesktop set { _inSession = value; RaisePropertyChangedAuto(); RaisePropertyChanged(nameof(CanStartSession)); } } + public bool EnableWebRtc { get; set; } + + private bool _isWebRtcActive; + public bool IsWebRtcActive + { + get { return _isWebRtcActive; } + set + { + if (_isWebRtcActive != value) + { + _isWebRtcActive = value; + RaisePropertyChangedAuto(); + + if (_isWebRtcActive) + { + LogManager.Log("WebRTC is now active."); + } + } + } + } + public TimeSpan MouseMoveInterval { get; set; } public bool CanStartSession @@ -58,9 +89,15 @@ namespace Tango.FSE.UI.RemoteDesktop get { return _machineProvider.IsConnected && !InSession; } } + #endregion + + #region Constructors + public DefaultRemoteDesktopProvider() { + _iceCandidates = new List<IceCandidate>(); MouseMoveInterval = TimeSpan.FromMilliseconds(100); + EnableWebRtc = true; } public DefaultRemoteDesktopProvider(IMachineProvider machineProvider) : this() @@ -75,9 +112,35 @@ namespace Tango.FSE.UI.RemoteDesktop InSession = false; OnFrameReceived(null); }; + _machineProvider.MachineOperator.RequestReceived += MachineOperator_RequestReceived; } - public Task StartSession() + #endregion + + private async void MachineOperator_RequestReceived(object sender, PMR.Common.MessageContainer container) + { + if (container.Type == PMR.Common.MessageType.GenericRequest) + { + var message = MessageFactory.ExtractMessageFromContainer(container); + var type = Type.GetType((message as GenericRequest).Type); + + if (type == typeof(WebRtcIceCandidateRequest)) + { + LogManager.Log("Ice candidate request received from the remote peer."); + await _machineProvider.MachineOperator.SendGenericResponse(new WebRtcIceCandidateResponse() { }, container.Token); + + var iceCandidateRequest = ProtoSerializer.DeserializeFromByteString(type, (message as GenericRequest).Data) as WebRtcIceCandidateRequest; + + LogManager.Log("Adding ice candidate..."); + _webRtcClient.AddIceCandidate(iceCandidateRequest.IceCandidate); + LogManager.Log("Ice candidate added."); + } + } + } + + #region Start/Stop Session + + public async Task StartSession() { TaskCompletionSource<bool> completionSource = new TaskCompletionSource<bool>(); @@ -88,10 +151,17 @@ namespace Tango.FSE.UI.RemoteDesktop if (!InSession) { + LogManager.Log("Starting remote desktop session..."); + + _iceCandidates.Clear(); + _answerReceived = false; + InSession = true; var taskItem = NotificationProvider.PushTaskItem("Starting remote desktop session..."); + await Task.Delay(2000); + if (_frameDispatcher != null) { _frameDispatcher.Dispose(); @@ -105,6 +175,7 @@ namespace Tango.FSE.UI.RemoteDesktop _machineProvider.MachineOperator.SendGenericContinuousRequest<StartRemoteDesktopSessionRequest, StartRemoteDesktopSessionResponse>(new StartRemoteDesktopSessionRequest() { }, new TransportContinuousRequestConfig() { Timeout = TimeSpan.FromSeconds(10), + ShouldLog = true }).Subscribe((response) => { if (!taskCompleted) @@ -112,6 +183,12 @@ namespace Tango.FSE.UI.RemoteDesktop taskCompleted = true; taskItem.Dispose(); completionSource.SetResult(true); + + if (EnableWebRtc) + { + LogManager.Log("WebRTC enabled. Starting WebRTC..."); + StartWebRTC(); + } } _frameDispatcher.Push(response); @@ -130,20 +207,17 @@ namespace Tango.FSE.UI.RemoteDesktop } InSession = false; - - //TODO: handle exception. }, () => { - //This cannot happen! InSession = false; OnFrameReceived(null); }); - return completionSource.Task; + await completionSource.Task; } else { - return Task.FromResult(true); + await Task.FromResult(true); } } @@ -153,23 +227,52 @@ namespace Tango.FSE.UI.RemoteDesktop { using (NotificationProvider.PushTaskItem("Stopping remote desktop session...")) { - await _machineProvider.MachineOperator.SendGenericRequest<StopRemoteDesktopSessionRequest, StopRemoteDesktopSessionResponse>(new StopRemoteDesktopSessionRequest()); + LogManager.Log("Stopping remote desktop session..."); + await Task.Delay(2000); + + try + { + await _machineProvider.MachineOperator.SendGenericRequest<StopRemoteDesktopSessionRequest, StopRemoteDesktopSessionResponse>(new StopRemoteDesktopSessionRequest(), new TransportRequestConfig() + { + ShouldLog = true + }); + + LogManager.Log("Remote desktop session stopped."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error stopping the remote desktop session."); + } + + DisposeWebRtc(); + InSession = false; } } } - private void OnFailed(Exception exception) + #endregion + + #region Virtual Methods + + protected virtual void OnFrameReceived(BitmapSource source, DesktopFrameReceivedEventArgs.FrameOrigin origin = DesktopFrameReceivedEventArgs.FrameOrigin.WebSockets) { - InSession = false; - OnFrameReceived(null); + IsWebRtcActive = origin == DesktopFrameReceivedEventArgs.FrameOrigin.WebRTC; - if (!(exception is TransporterDisconnectedException)) + if (InSession) { - NotificationProvider.PushSnackbarItem(MessageType.Error, "Remote desktop session terminated unexpectedly.", true, null, TimeSpan.FromSeconds(5)); + FrameReceived?.Invoke(this, new DesktopFrameReceivedEventArgs() + { + Source = source, + Origin = origin + }); } } + #endregion + + #region SignalR Response Received + private void OnRemoteDesktopResponse(StartRemoteDesktopSessionResponse response) { if (!InSession) return; //To stop frame delivery immediately. @@ -205,17 +308,13 @@ namespace Tango.FSE.UI.RemoteDesktop } catch (Exception ex) { - Debug.WriteLine($"Error on remote desktop packet received: {ex.Message}"); + LogManager.Log(ex, "Error on remote desktop packet received."); } } - protected virtual void OnFrameReceived(BitmapSource source) - { - FrameReceived?.Invoke(this, new DesktopFrameReceivedEventArgs() - { - Source = source, - }); - } + #endregion + + #region Mouse/Keyboard public async void MouseDown(MouseButton button, Point location, Size viewSize) { @@ -336,5 +435,146 @@ namespace Tango.FSE.UI.RemoteDesktop IsAltDown = altDown, }); } + + #endregion + + #region WebRTC + + private async void StartWebRTC() + { + _webRtcClient = new WebRtcClient(); + + try + { + _webRtcClient.NewIceCandidate += _webRtcClient_NewIceCandidate; + _webRtcClient.FrameReceived += _webRtcClient_FrameReceived; + _webRtcClient.Disconnected += _webRtcClient_Disconnected; + + LogManager.Log("Initializing WebRTC client..."); + await _webRtcClient.Init(); + + LogManager.Log("Creating WebRTC offer..."); + var offer = await _webRtcClient.CreateOffer(); + + LogManager.Log("Sending WebRTC offer..."); + var response = await _machineProvider.MachineOperator.SendGenericRequest<WebRtcOfferRequest, WebRtcOfferResponse>(new WebRtcOfferRequest() { Offer = offer }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + ShouldLog = true + }); + + LogManager.Log("WebRTC offer sent and responded with an answer. Setting WebRTC answer..."); + _webRtcClient.SetAnswer(response.Answer); + _answerReceived = true; + + foreach (var ice in _iceCandidates.ToList()) + { + LogManager.Log("Sending existing ice candidate..."); + + await _machineProvider.MachineOperator.SendGenericRequest<WebRtcIceCandidateRequest, WebRtcIceCandidateResponse>(new WebRtcIceCandidateRequest() { IceCandidate = ice }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + ShouldLog = true + }); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error starting WebRTC."); + } + } + + private void DisposeWebRtc() + { + if (_webRtcClient != null) + { + LogManager.Log("Disposing WebRTC client..."); + + _webRtcClient.NewIceCandidate -= _webRtcClient_NewIceCandidate; + _webRtcClient.FrameReceived -= _webRtcClient_FrameReceived; + _webRtcClient.Disconnected -= _webRtcClient_Disconnected; + + if (_webRtcClient != null) + { + try + { + _webRtcClient.Dispose(); + _webRtcClient = null; + LogManager.Log("WebRTC client disposed."); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error disposing WebRTC client."); + } + } + } + } + + private void _webRtcClient_Disconnected(object sender, EventArgs e) + { + LogManager.Log("WebRTC client is now disconnected."); + IsWebRtcActive = false; + } + + private async void _webRtcClient_NewIceCandidate(object sender, NewIceCandidateEventArgs e) + { + try + { + if (_answerReceived) + { + LogManager.Log("New WebRTC candidate available. Sending ice to remote peer..."); + + await _machineProvider.MachineOperator.SendGenericRequest<WebRtcIceCandidateRequest, WebRtcIceCandidateResponse>(new WebRtcIceCandidateRequest() { IceCandidate = e.IceCandidate }, new TransportRequestConfig() + { + Timeout = TimeSpan.FromSeconds(30), + ShouldLog = true + }); + } + else + { + LogManager.Log("New WebRTC candidate available. Will be sent after an answer is received..."); + + _iceCandidates.Add(e.IceCandidate); + } + } + catch (Exception ex) + { + LogManager.Log(ex, "Error sending ice candidate to remote peer."); + } + } + + private void _webRtcClient_FrameReceived(object sender, VideoFrameReceivedEventArgs e) + { + try + { + RasterFrame frame = new RasterFrame(e.Bitmap); + OnFrameReceived(frame.ToBitmapSource(), DesktopFrameReceivedEventArgs.FrameOrigin.WebRTC); + frame.Dispose(); + } + catch (Exception ex) + { + LogManager.Log(ex, "Error on WebRTC client frame received."); + } + } + + #endregion + + #region OnFailed + + private void OnFailed(Exception exception) + { + LogManager.Log(exception, "Remote desktop session failed."); + + InSession = false; + OnFrameReceived(null); + DisposeWebRtc(); + + if (!(exception is TransporterDisconnectedException)) + { + NotificationProvider.PushSnackbarItem(MessageType.Error, "Remote desktop session terminated unexpectedly.", true, null, TimeSpan.FromSeconds(5)); + } + } + + #endregion } } diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj index 04d0e12d6..7c6679549 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/Tango.FSE.UI.csproj @@ -40,6 +40,9 @@ <Reference Include="ControlzEx, Version=3.0.2.4, Culture=neutral, processorArchitecture=MSIL"> <HintPath>..\..\packages\ControlzEx.3.0.2.4\lib\net45\ControlzEx.dll</HintPath> </Reference> + <Reference Include="Dragablz, Version=0.0.3.203, Culture=neutral, processorArchitecture=MSIL"> + <HintPath>..\..\packages\Dragablz.0.0.3.203\lib\net45\Dragablz.dll</HintPath> + </Reference> <Reference Include="EntityFramework, Version=6.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089, processorArchitecture=MSIL"> <HintPath>..\..\packages\EntityFramework.6.2.0\lib\net45\EntityFramework.dll</HintPath> </Reference> @@ -332,6 +335,10 @@ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> <Name>Tango.Transport</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.WebRTC\Tango.WebRTC.csproj"> + <Project>{09f81a12-0f77-4336-854d-9e0a74a17f9e}</Project> + <Name>Tango.WebRTC</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.Web\Tango.Web.csproj"> <Project>{5001990f-977b-48ff-b217-0236a5022ad8}</Project> <Name>Tango.Web</Name> diff --git a/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config b/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config index d17a56d7d..c795da787 100644 --- a/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config +++ b/Software/Visual_Studio/FSE/Tango.FSE.UI/packages.config @@ -1,6 +1,7 @@ <?xml version="1.0" encoding="utf-8"?> <packages> <package id="ControlzEx" version="3.0.2.4" targetFramework="net461" /> + <package id="Dragablz" version="0.0.3.203" targetFramework="net461" /> <package id="EntityFramework" version="6.2.0" targetFramework="net461" /> <package id="Google.Protobuf" version="3.4.1" targetFramework="net461" /> <package id="MahApps.Metro" version="1.6.5" targetFramework="net461" /> diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs index 0d5bd8559..ae33bbfce 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/RemoteDesktop/DefaultRemoteDesktopService.cs @@ -19,6 +19,7 @@ using Tango.RemoteDesktop.Input; using Tango.RemoteDesktop.Network; using Tango.Settings; using Tango.Transport; +using Tango.WebRTC; using static Tango.RemoteDesktop.Input.MouseController; namespace Tango.PPC.Common.RemoteDesktop @@ -31,6 +32,8 @@ namespace Tango.PPC.Common.RemoteDesktop public String Token { get; set; } public ExternalBridgeReceiver Receiver { get; set; } public bool InitialPacketSent { get; set; } + public WebRtcClient WebRtcClient { get; set; } + public bool IsWebRtcReady { get; set; } } private RemoteDesktopPacket _initialPacket; @@ -65,19 +68,19 @@ namespace Tango.PPC.Common.RemoteDesktop { _engine.CaptureRegion = new CaptureRegion() { - Left = (int)mainWindow.Left, - Top = (int)mainWindow.Top, - Width = (int)mainWindow.Width, - Height = (int)mainWindow.Height + Left = (int)mainWindow.Left + 10, + Top = (int)mainWindow.Top + 5, + Width = (int)mainWindow.Width - 20, + Height = (int)mainWindow.Height - 15 }; }; _engine.CaptureRegion = new CaptureRegion() { - Left = (int)mainWindow.Left, - Top = (int)mainWindow.Top, - Width = (int)mainWindow.Width, - Height = (int)mainWindow.Height + Left = (int)mainWindow.Left + 10, + Top = (int)mainWindow.Top + 5, + Width = (int)mainWindow.Width - 20, + Height = (int)mainWindow.Height - 15 }; _engine.CaptureMethod = new GdiScreenCapture(); #endif @@ -102,11 +105,11 @@ namespace Tango.PPC.Common.RemoteDesktop _clients.Remove(client); } - _clients.Add(new RemoteDesktopClient() - { - Receiver = receiver, - Token = token - }); + RemoteDesktopClient newClient = new RemoteDesktopClient(); + newClient.Receiver = receiver; + newClient.Token = token; + newClient.WebRtcClient = new WebRtcClient(); + _clients.Add(newClient); await receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() { @@ -122,6 +125,78 @@ namespace Tango.PPC.Common.RemoteDesktop } } + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcIceCandidateRequest))] + public async void OnWebRtcIceCandidateRequestReceived(WebRtcIceCandidateRequest request, String token, ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + try + { + await receiver.SendGenericResponse(new WebRtcIceCandidateResponse() { }, token); + client.WebRtcClient.AddIceCandidate(request.IceCandidate); + } + catch (Exception ex) + { + LogManager.Log($"Error adding WebRTC ice candidate received from the remote connection.\n{ex.FlattenMessage()}"); + } + } + } + + [ExternalBridgeRequestHandlerMethod(typeof(WebRtcOfferRequest))] + public async void OnWebRtcOfferRequestReceived(WebRtcOfferRequest request, String token, ExternalBridgeReceiver receiver) + { + var client = _clients.SingleOrDefault(x => x.Receiver == receiver); + + if (client != null) + { + try + { + + try + { + client.WebRtcClient.NewIceCandidate += async (x, e) => + { + try + { + await receiver.SendGenericRequest<WebRtcIceCandidateRequest, WebRtcIceCandidateResponse>(new WebRtcIceCandidateRequest() { IceCandidate = e.IceCandidate }); + } + catch (Exception ex) + { + LogManager.Log(ex, $"Error sending ice candidate to remote peer.\n{ex.FlattenMessage()}"); + } + }; + client.WebRtcClient.Ready += (x, e) => + { + client.IsWebRtcReady = true; + }; + client.WebRtcClient.Disconnected += (x, e) => + { + client.IsWebRtcReady = false; + }; + + client.WebRtcClient.FrameWidth = 800; + client.WebRtcClient.FrameHeight = 1280; + client.WebRtcClient.FrameRate = _engine.FrameRate; + + await client.WebRtcClient.Init(); + + var answer = await client.WebRtcClient.CreateAnswer(request.Offer); + await receiver.SendGenericResponse(new WebRtcOfferResponse() { Answer = answer }, token); + } + catch (Exception ex) + { + LogManager.Log($"Error initializing the web RTC client.\n{ex.FlattenMessage()}"); + } + } + catch (Exception ex) + { + LogManager.Log($"Error responding to WebRTC offer request.\n{ex.FlattenMessage()}"); + } + } + } + [ExternalBridgeRequestHandlerMethod(typeof(StopRemoteDesktopSessionRequest))] public async void OnStopRemoteDesktopSessionRequestReceived(StopRemoteDesktopSessionRequest request, String token, ExternalBridgeReceiver receiver) { @@ -130,6 +205,11 @@ namespace Tango.PPC.Common.RemoteDesktop if (client != null) { _clients.Remove(client); + + if (client.WebRtcClient != null) + { + client.WebRtcClient.Dispose(); + } } if (_clients.Count == 0) @@ -199,75 +279,103 @@ namespace Tango.PPC.Common.RemoteDesktop Bitmap = e.Frame.ToEncoder<PngEncoder>().ToArray(), }; - foreach (var client in _clients.ToList().Where(x => !x.InitialPacketSent)) + if (_clients.Count > 0) { - try - { - await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() - { - Packet = _initialPacket, - }, client.Token, new TransportResponseConfig() - { - Immediate = false, - }); + bool useWebRTC = _clients.ToList().All(x => x.IsWebRtcReady); - client.InitialPacketSent = true; - } - catch (Exception ex) + if (useWebRTC) { - Debug.WriteLine(ex); - } - } - - if (e.Frame.DifferenceCount > 0) - { - RemoteDesktopPacket packet = null; + _engine.EnableComparer = false; - if (!e.Frame.DifferenceAvailable) - { - Debug.WriteLine("Using Jpeg..."); - packet = new RemoteDesktopPacket() + foreach (var client in _clients.ToList()) { - Bitmap = e.Frame.ToEncoder<TurboJpegEncoder>().ToArray(30) - }; + try + { + client.WebRtcClient.PushFrame(e.Frame.ToBitmap()); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } + + e.Frame.Dispose(); } else { - var diffFrame = e.Frame.ToDifference(); - diffFrame = diffFrame.OptimizeBounds(); + _engine.EnableComparer = true; - packet = new RemoteDesktopPacket() + foreach (var client in _clients.ToList().Where(x => !x.InitialPacketSent)) { - Bitmap = diffFrame.ToEncoder<PngEncoder>().ToArray(), - IsPartial = true, - PartialRegion = new CaptureRegion(diffFrame.Left, diffFrame.Top, diffFrame.Width, diffFrame.Height), - }; - - diffFrame.Dispose(); - } - - Debug.WriteLine($"Bitmap Size: {packet.Bitmap.Length / 1000} kb"); + try + { + await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + { + Packet = _initialPacket, + }, client.Token, new TransportResponseConfig() + { + Immediate = false, + }); - e.Frame.Dispose(); + client.InitialPacketSent = true; + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } - foreach (var client in _clients.ToList().Where(x => x.InitialPacketSent)) - { - try + if (e.Frame.DifferenceCount > 0) { - await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + RemoteDesktopPacket packet = null; + + if (!e.Frame.DifferenceAvailable) { - Packet = packet - }, client.Token, new TransportResponseConfig() + Debug.WriteLine("Using Jpeg..."); + packet = new RemoteDesktopPacket() + { + Bitmap = e.Frame.ToEncoder<TurboJpegEncoder>().ToArray(30) + }; + } + else { - Immediate = false, - }); - } - catch (Exception ex) - { - Debug.WriteLine(ex); + var diffFrame = e.Frame.ToDifference(); + diffFrame = diffFrame.OptimizeBounds(); + + packet = new RemoteDesktopPacket() + { + Bitmap = diffFrame.ToEncoder<PngEncoder>().ToArray(), + IsPartial = true, + PartialRegion = new CaptureRegion(diffFrame.Left, diffFrame.Top, diffFrame.Width, diffFrame.Height), + }; + + diffFrame.Dispose(); + } + + Debug.WriteLine($"Bitmap Size: {packet.Bitmap.Length / 1000} kb"); + + foreach (var client in _clients.ToList().Where(x => x.InitialPacketSent)) + { + try + { + await client.Receiver.SendGenericResponse(new StartRemoteDesktopSessionResponse() + { + Packet = packet + }, client.Token, new TransportResponseConfig() + { + Immediate = false, + }); + } + catch (Exception ex) + { + Debug.WriteLine(ex); + } + } } } } + + e.Frame.Dispose(); } public void OnReceiverDisconnected(ExternalBridgeReceiver receiver) @@ -277,6 +385,18 @@ namespace Tango.PPC.Common.RemoteDesktop if (client != null) { _clients.Remove(client); + + try + { + if (client.WebRtcClient != null) + { + client.WebRtcClient.Dispose(); + } + } + catch (Exception ex) + { + LogManager.Log($"Error disposing the WebRTC client.\n{ex.FlattenMessage()}"); + } } if (_clients.Count == 0) diff --git a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj index 80bcf6ef1..f7b3f9e4c 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj +++ b/Software/Visual_Studio/PPC/Tango.PPC.Common/Tango.PPC.Common.csproj @@ -399,6 +399,10 @@ <Project>{74e700b0-1156-4126-be40-ee450d3c3026}</Project> <Name>Tango.Transport</Name> </ProjectReference> + <ProjectReference Include="..\..\Tango.WebRTC\Tango.WebRTC.csproj"> + <Project>{09f81a12-0f77-4336-854d-9e0a74a17f9e}</Project> + <Name>Tango.WebRTC</Name> + </ProjectReference> <ProjectReference Include="..\..\Tango.Web\Tango.Web.csproj"> <Project>{5001990f-977b-48ff-b217-0236a5022ad8}</Project> <Name>Tango.Web</Name> @@ -433,7 +437,7 @@ </Target> <ProjectExtensions> <VisualStudio> - <UserProperties BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UseGlobalSettings="False" BuildVersion_StartDate="2000/1/1" /> + <UserProperties BuildVersion_StartDate="2000/1/1" BuildVersion_UseGlobalSettings="False" BuildVersion_BuildVersioningStyle="None.None.Increment.TimeStamp" BuildVersion_UpdateAssemblyVersion="True" BuildVersion_AssemblyInfoFilename="Properties\AssemblyInfo.cs" /> </VisualStudio> </ProjectExtensions> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs index fd0e288c8..8ee8f6a1a 100644 --- a/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs +++ b/Software/Visual_Studio/PPC/Tango.PPC.UI/App.xaml.cs @@ -6,6 +6,7 @@ using System.Diagnostics; using System.IO; using System.Linq; using System.Net; +using System.Threading; using System.Threading.Tasks; using System.Windows; using Tango.BL; @@ -38,6 +39,8 @@ namespace Tango.PPC.UI /// <param name="e">A <see cref="T:System.Windows.StartupEventArgs" /> that contains the event data.</param> protected override void OnStartup(StartupEventArgs e) { + ThreadPool.SetMaxThreads(1000, 1000); + //If no debugger is attached and the argument -debug was passed launch the debugger. if (e.Args.Contains("-debug") && !Debugger.IsAttached) { diff --git a/Software/Visual_Studio/SideChains/WebRtc.NET/WebRtc.NET.vcxproj b/Software/Visual_Studio/SideChains/WebRtc.NET/WebRtc.NET.vcxproj index a90ba240a..661997d3f 100644 --- a/Software/Visual_Studio/SideChains/WebRtc.NET/WebRtc.NET.vcxproj +++ b/Software/Visual_Studio/SideChains/WebRtc.NET/WebRtc.NET.vcxproj @@ -102,6 +102,7 @@ <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <MinimalRebuild>false</MinimalRebuild> <BasicRuntimeChecks>Default</BasicRuntimeChecks> + <ExceptionHandling>Async</ExceptionHandling> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> @@ -148,6 +149,7 @@ </AdditionalUsingDirectories> <DebugInformationFormat>ProgramDatabase</DebugInformationFormat> <FavorSizeOrSpeed>Speed</FavorSizeOrSpeed> + <ExceptionHandling>Async</ExceptionHandling> </ClCompile> <Link> <GenerateDebugInformation>true</GenerateDebugInformation> diff --git a/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.cc b/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.cc index 0bca34800..c7c4f3ba5 100644 --- a/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.cc +++ b/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.cc @@ -64,11 +64,11 @@ namespace Native onIceCandidate = nullptr; width_ = 640; - height_ = 360; + height_ = 360; caputureFps = 5; audioEnabled = false; - barcodeEnabled = false; + barcodeEnabled = false; turnServer = nullptr; data_channel = nullptr; @@ -79,43 +79,67 @@ namespace Native void Conductor::Dispose() { - DeletePeerConnection(); - ASSERT(peer_connection_ == nullptr); - - if (turnServer) + if (!_disposed) { - turnServer->disconnect_all(); - } + _disposed = true; - if (stunServer) - { - stunServer->disconnect_all(); - } + try + { + DeletePeerConnection(); + ASSERT(peer_connection_ == nullptr); - if (turnServer || stunServer) - { - rtc::Thread::Current()->Quit(); + if (turnServer) + { + turnServer->disconnect_all(); + } + + if (stunServer) + { + stunServer->disconnect_all(); + } + + if (turnServer || stunServer) + { + rtc::Thread::Current()->Quit(); + } + } + catch (const std::exception&) + { + LOG(WARNING) << "Error in disposing conductor.cc"; + } } } Conductor::~Conductor() { - DeletePeerConnection(); - ASSERT(peer_connection_ == nullptr); - - if (turnServer) + if (!_disposed) { - turnServer->disconnect_all(); - } + _disposed = true; - if (stunServer) - { - stunServer->disconnect_all(); - } + try + { + DeletePeerConnection(); + ASSERT(peer_connection_ == nullptr); - if (turnServer || stunServer) - { - rtc::Thread::Current()->Quit(); + if (turnServer) + { + turnServer->disconnect_all(); + } + + if (stunServer) + { + stunServer->disconnect_all(); + } + + if (turnServer || stunServer) + { + rtc::Thread::Current()->Quit(); + } + } + catch (const std::exception&) + { + LOG(WARNING) << "Error in disposing conductor.cc"; + } } } @@ -137,15 +161,17 @@ namespace Native pc_factory_ = nullptr; - if (data_channel) - { - data_channel->UnregisterObserver(); - data_channel = nullptr; - } - serverConfigs.clear(); + //if (data_channel) + //{ + //data_channel->Close(); + //data_channel->UnregisterObserver(); + //data_channel = nullptr; + //} + + //serverConfigs.clear(); - capturer_internal = nullptr; - capturer = nullptr; + //capturer_internal = nullptr; + //capturer = nullptr; } bool Conductor::InitializePeerConnection() @@ -309,7 +335,7 @@ namespace Native } return device_names; } - + bool Conductor::OpenVideoCaptureDevice(std::string & name) { if (!capturer_internal) @@ -345,7 +371,7 @@ namespace Native if (onRenderLocal) { local_video.reset(new VideoRenderer(*this, false, video_track)); - } + } auto stream = pc_factory_->CreateLocalMediaStream(kStreamLabel); { @@ -464,9 +490,9 @@ namespace Native dc_options.maxRetransmits = 1; dc_options.negotiated = false; dc_options.ordered = false; - + data_channel = peer_connection_->CreateDataChannel(label, &dc_options); - data_channel->RegisterObserver(this); + data_channel->RegisterObserver(this); } void Conductor::OnDataChannel(rtc::scoped_refptr<webrtc::DataChannelInterface> channel) @@ -536,7 +562,7 @@ namespace Native } bool Conductor::RunTurnServer(const std::string & bindIp, const std::string & ip, - const std::string & realm, const std::string & authFile) + const std::string & realm, const std::string & authFile) { rtc::SocketAddress int_addr; if (!int_addr.FromString(bindIp)) @@ -576,7 +602,7 @@ namespace Native t->set_auth_hook(auth); t->AddInternalSocket(int_socket, cricket::PROTO_UDP); t->SetExternalSocketFactory(new rtc::BasicPacketSocketFactory(), - rtc::SocketAddress(ext_addr, 0)); + rtc::SocketAddress(ext_addr, 0)); LOG(INFO) << "Listening internally at " << int_addr.ToString() << std::endl; diff --git a/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.h b/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.h index 4f1a216ec..c002bc760 100644 --- a/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.h +++ b/Software/Visual_Studio/SideChains/WebRtc.NET/src/conductor.h @@ -208,6 +208,7 @@ namespace Native private: + bool _disposed; bool CreatePeerConnection(bool dtls); void DeletePeerConnection(); void AddStreams(); diff --git a/Software/Visual_Studio/SideChains/WebRtc.NET/src/managed.cpp b/Software/Visual_Studio/SideChains/WebRtc.NET/src/managed.cpp index 63db79dc2..284fc7e7f 100644 --- a/Software/Visual_Studio/SideChains/WebRtc.NET/src/managed.cpp +++ b/Software/Visual_Studio/SideChains/WebRtc.NET/src/managed.cpp @@ -233,6 +233,8 @@ namespace WebRtc if (m_isDisposed) return; + m_isDisposed = true; + cd->Dispose(); // dispose managed data @@ -246,8 +248,6 @@ namespace WebRtc FreeGCHandle(onDataMessageHandle); //this->!ManagedConductor(); // call finalizer - - m_isDisposed = true; } static void InitializeSSL() @@ -405,11 +405,11 @@ namespace WebRtc !ManagedConductor() { // free unmanaged data - if (cd != NULL) - { - delete cd; - } - cd = NULL; + //if (cd != NULL) + //{ + // delete cd; + //} + //cd = NULL; } }; } diff --git a/Software/Visual_Studio/Tango.PMR/MessageFactory.cs b/Software/Visual_Studio/Tango.PMR/MessageFactory.cs index 75f0bb0a5..6a796bf55 100644 --- a/Software/Visual_Studio/Tango.PMR/MessageFactory.cs +++ b/Software/Visual_Studio/Tango.PMR/MessageFactory.cs @@ -6,6 +6,7 @@ using System.Reflection; using System.Text; using System.Threading.Tasks; using Tango.PMR.Common; +using Tango.PMR.Integration; namespace Tango.PMR { diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateRequest.cs b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateRequest.cs new file mode 100644 index 000000000..4d6f933c2 --- /dev/null +++ b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.WebRTC; + +namespace Tango.RemoteDesktop.Network +{ + public class WebRtcIceCandidateRequest + { + public IceCandidate IceCandidate { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateResponse.cs b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateResponse.cs new file mode 100644 index 000000000..e3d926f67 --- /dev/null +++ b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcIceCandidateResponse.cs @@ -0,0 +1,13 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.RemoteDesktop.Network +{ + public class WebRtcIceCandidateResponse + { + + } +} diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferRequest.cs b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferRequest.cs new file mode 100644 index 000000000..28fde6af8 --- /dev/null +++ b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferRequest.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.WebRTC; + +namespace Tango.RemoteDesktop.Network +{ + public class WebRtcOfferRequest + { + public Offer Offer { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferResponse.cs b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferResponse.cs new file mode 100644 index 000000000..1c4698035 --- /dev/null +++ b/Software/Visual_Studio/Tango.RemoteDesktop/Network/WebRtcOfferResponse.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; +using Tango.WebRTC; + +namespace Tango.RemoteDesktop.Network +{ + public class WebRtcOfferResponse + { + public Answer Answer { get; set; } + } +} diff --git a/Software/Visual_Studio/Tango.RemoteDesktop/Tango.RemoteDesktop.csproj b/Software/Visual_Studio/Tango.RemoteDesktop/Tango.RemoteDesktop.csproj index dfffe90ec..8a1d51cf3 100644 --- a/Software/Visual_Studio/Tango.RemoteDesktop/Tango.RemoteDesktop.csproj +++ b/Software/Visual_Studio/Tango.RemoteDesktop/Tango.RemoteDesktop.csproj @@ -100,6 +100,10 @@ <Compile Include="Network\StartRemoteDesktopSessionResponse.cs" /> <Compile Include="Network\StopRemoteDesktopSessionRequest.cs" /> <Compile Include="Network\StopRemoteDesktopSessionResponse.cs" /> + <Compile Include="Network\WebRtcIceCandidateRequest.cs" /> + <Compile Include="Network\WebRtcIceCandidateResponse.cs" /> + <Compile Include="Network\WebRtcOfferRequest.cs" /> + <Compile Include="Network\WebRtcOfferResponse.cs" /> <Compile Include="Quantization\ColorBgra.cs" /> <Compile Include="Quantization\OctreeQuantizer.cs" /> <Compile Include="Quantization\PaletteTable.cs" /> @@ -146,5 +150,11 @@ <ItemGroup> <None Include="packages.config" /> </ItemGroup> + <ItemGroup> + <ProjectReference Include="..\Tango.WebRTC\Tango.WebRTC.csproj"> + <Project>{09f81a12-0f77-4336-854d-9e0a74a17f9e}</Project> + <Name>Tango.WebRTC</Name> + </ProjectReference> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.Transport/IRequestHandler.cs b/Software/Visual_Studio/Tango.Transport/IRequestHandler.cs new file mode 100644 index 000000000..90879f474 --- /dev/null +++ b/Software/Visual_Studio/Tango.Transport/IRequestHandler.cs @@ -0,0 +1,14 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Runtime.Remoting.Messaging; +using System.Text; +using System.Threading.Tasks; + +namespace Tango.Transport +{ + public interface IRequestHandler<T> where T : class + { + void OnRequestReceived(T request); + } +} diff --git a/Software/Visual_Studio/Tango.Transport/ITransporter.cs b/Software/Visual_Studio/Tango.Transport/ITransporter.cs index 78047c080..a3ca5275f 100644 --- a/Software/Visual_Studio/Tango.Transport/ITransporter.cs +++ b/Software/Visual_Studio/Tango.Transport/ITransporter.cs @@ -34,6 +34,10 @@ namespace Tango.Transport /// </summary> Exception FailedStateException { get; } + //void RegisterRequestHandler<T>(IRequestHandler<T> handler) where T: class; + + //void UnregisterRequestHandler<T>(IRequestHandler<T> handler) where T : class; + /// <summary> /// Sends a request. /// </summary> diff --git a/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs b/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs index 927300224..c974f2712 100644 --- a/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs +++ b/Software/Visual_Studio/Tango.Transport/ProtoSerializer.cs @@ -6,6 +6,9 @@ using System.IO; using System.Linq; using System.Text; using System.Threading.Tasks; +using Tango.PMR; +using Tango.PMR.Common; +using Tango.PMR.Integration; namespace Tango.Transport { @@ -72,5 +75,13 @@ namespace Tango.Transport return Deserialize<T>(byteString.ToByteArray()); } + + public static T ExtractGenericRequestFromContainer<T>(MessageContainer container) where T : class + { + var message = MessageFactory.ExtractMessageFromContainer(container); + var genericType = Type.GetType((message as GenericRequest).Type); + var innerMessage = ProtoSerializer.DeserializeFromByteString(genericType, (message as GenericRequest).Data); + return innerMessage as T; + } } } diff --git a/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj b/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj index 8c71f80e7..c4663290a 100644 --- a/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj +++ b/Software/Visual_Studio/Tango.Transport/Tango.Transport.csproj @@ -116,6 +116,7 @@ <Compile Include="Discovery\UsbCommunicationScanner.cs" /> <Compile Include="Encoders\ProtoEncoder.cs" /> <Compile Include="ExtensionMethods\TcpClientExtensions.cs" /> + <Compile Include="IRequestHandler.cs" /> <Compile Include="ITransportComponent.cs" /> <Compile Include="ITransportAdapter.cs" /> <Compile Include="Adapters\TcpTransportAdapter.cs" /> diff --git a/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj b/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj index 0d85bb902..d9cea42dc 100644 --- a/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj +++ b/Software/Visual_Studio/Tango.WebRTC/Tango.WebRTC.csproj @@ -59,6 +59,10 @@ <Project>{a07e6cb4-0132-4eb1-9a38-c8c057884dc2}</Project> <Name>WebRtc.NET</Name> </ProjectReference> + <ProjectReference Include="..\Tango.Core\Tango.Core.csproj"> + <Project>{a34ee0f0-649d-41c8-8489-b6f1cc6924ee}</Project> + <Name>Tango.Core</Name> + </ProjectReference> </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/Tango.WebRTC/WebRtcClient.cs b/Software/Visual_Studio/Tango.WebRTC/WebRtcClient.cs index 9866395ae..bbbabb4e4 100644 --- a/Software/Visual_Studio/Tango.WebRTC/WebRtcClient.cs +++ b/Software/Visual_Studio/Tango.WebRTC/WebRtcClient.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Text; using System.Threading; using System.Threading.Tasks; +using Tango.Core.Threading; using WebRtc.NET; namespace Tango.WebRTC @@ -192,14 +193,15 @@ namespace Tango.WebRTC completion.SetResult(true); - Stopwatch watch = new Stopwatch(); - watch.Start(); + //Stopwatch watch = new Stopwatch(); + //watch.Start(); while (!_isDisposed) { - watch.Restart(); + //watch.Restart(); _conductor.ProcessMessages(1000); - Thread.Sleep(Math.Max(10, (int)watch.ElapsedMilliseconds)); + Thread.Sleep(10); + //Thread.Sleep(Math.Max(10, (int)watch.ElapsedMilliseconds)); } IsInitialized = false; @@ -211,9 +213,35 @@ namespace Tango.WebRTC _conductor.OnFailure -= _conductor_OnFailure; _conductor.OnIceStateChanged -= _conductor_OnIceStateChanged; + unsafe + { + _conductor.OnRenderRemote -= _conductor_OnRenderRemote; + } + _conductor.Dispose(); + + try + { + if (_sendFrame != null) + { + _sendFrame.Dispose(); + } + + } + catch { } + + + try + { + if (_bufHandle != null) + { + _bufHandle.Free(); + } + } + catch { } }); + _conductorThread.SetApartmentState(ApartmentState.STA); _conductorThread.IsBackground = true; _conductorThread.Start(); @@ -320,16 +348,14 @@ namespace Tango.WebRTC _conductor.OnSuccessOffer += del; - Task.Factory.StartNew(async () => + TimeoutTask.StartNew(() => { - await Task.Delay(10000); - if (!completed) { completed = true; completion.SetException(new TimeoutException("The offer was not created within the given time.")); } - }); + }, TimeSpan.FromSeconds(10)); _conductor.CreateOffer(); @@ -358,16 +384,14 @@ namespace Tango.WebRTC _conductor.OnSuccessAnswer += del; - Task.Factory.StartNew(async () => + TimeoutTask.StartNew(() => { - await Task.Delay(10000); - if (!completed) { completed = true; completion.SetException(new TimeoutException("The answer was not created within the given time.")); } - }); + }, TimeSpan.FromSeconds(10)); _conductor.OnOfferRequest(offer.Sdp); @@ -392,7 +416,7 @@ namespace Tango.WebRTC { EnsureInitialized(); - Task.Factory.StartNew(() => + ThreadFactory.StartNew(() => { _conductor.AddIceCandidate(ice.SdpMid, ice.SdpMLineIndex, ice.Sdp); }); @@ -437,16 +461,14 @@ namespace Tango.WebRTC { if (timeout != null) { - Task.Factory.StartNew(async () => + TimeoutTask.StartNew(() => { - await Task.Delay(timeout.Value); - if (!IsReady) { _readyCompletionSource.SetException(new TimeoutException("The connection was not ready within the given time.")); _readyCompletionSource = null; } - }); + }, timeout.Value); } _readyCompletionSource = new TaskCompletionSource<bool>(); @@ -463,26 +485,6 @@ namespace Tango.WebRTC if (!_isDisposed) { _isDisposed = true; - - try - { - if (_sendFrame != null) - { - _sendFrame.Dispose(); - } - - } - catch { } - - - try - { - if (_bufHandle != null) - { - _bufHandle.Free(); - } - } - catch { } } } |
