├── .editorconfig ├── .github └── workflows │ └── build.yml ├── .gitignore ├── .vscode ├── launch.json ├── settings.json ├── solution-explorer │ ├── class.cs-template │ ├── class.ts-template │ ├── class.vb-template │ ├── default.ts-template │ ├── enum.cs-template │ ├── interface.cs-template │ ├── interface.ts-template │ ├── template-list.json │ └── template-parameters.js └── tasks.json ├── CHANGELOG.md ├── LICENSE ├── README.md ├── SmartGlass.Cli ├── AuthenticateCommand.cs ├── BinaryExtensions.cs ├── BroadcastCommand.cs ├── ConnectCommand.cs ├── DiscoverCommand.cs ├── EnumerableExtensions.cs ├── MainCommandType.cs ├── PcapCommand.cs ├── PingCommand.cs ├── PowerOnCommand.cs ├── Program.cs ├── ProgramArguments.cs ├── Session │ ├── MediaCommand.cs │ ├── PowerOffCommand.cs │ ├── PressCommand.cs │ ├── RecordCommand.cs │ ├── SessionCommandType.cs │ └── TitleChannelCommand.cs └── SmartGlass.Cli.csproj ├── SmartGlass.Tests ├── AsyncLazyTests.cs ├── AttributeTypeMappingTests.cs ├── DateTimeHelperTests.cs ├── DeviceTests.cs ├── EndianReaderTests.cs ├── EndianWriterTests.cs ├── Resources │ ├── Json │ │ ├── console.json │ │ ├── console_list.json │ │ ├── gamestream_enabled.json │ │ ├── gamestream_preview_status.json │ │ ├── gamestream_start_stream.json │ │ ├── gamestream_state_init.json │ │ ├── gamestream_state_invalid.json │ │ ├── gamestream_state_started.json │ │ └── gamestream_state_stopped.json │ ├── Misc │ │ ├── selfsigned_cert.bin │ │ └── sg_capture.pcap │ ├── Nano │ │ ├── tcp_audio_client_handshake.bin │ │ ├── tcp_audio_control.bin │ │ ├── tcp_audio_server_handshake.bin │ │ ├── tcp_channel_close.bin │ │ ├── tcp_channel_create.bin │ │ ├── tcp_channel_open_no_flags.bin │ │ ├── tcp_channel_open_with_flags.bin │ │ ├── tcp_control_handshake.bin │ │ ├── tcp_control_msg_with_header_change_video_quality.bin │ │ ├── tcp_control_msg_with_header_realtime_telemetry.bin │ │ ├── tcp_input_client_handshake.bin │ │ ├── tcp_input_server_handshake.bin │ │ ├── tcp_video_client_handshake.bin │ │ ├── tcp_video_control.bin │ │ ├── tcp_video_server_handshake.bin │ │ ├── udp_audio_data.bin │ │ ├── udp_handshake.bin │ │ ├── udp_input_frame.bin │ │ ├── udp_input_frame_ack.bin │ │ └── udp_video_data.bin │ ├── ResourcesProvider.cs │ └── SmartGlass │ │ ├── acknowledge.bin │ │ ├── active_surface_change.bin │ │ ├── auxiliary_stream_connection_info.bin │ │ ├── auxiliary_stream_hello.bin │ │ ├── connect_request.bin │ │ ├── connect_response.bin │ │ ├── console_status.bin │ │ ├── disconnect.bin │ │ ├── fragment_media_state_0.bin │ │ ├── fragment_media_state_1.bin │ │ ├── fragment_media_state_2.bin │ │ ├── gamedvr_record.bin │ │ ├── gamepad.bin │ │ ├── json.bin │ │ ├── local_join.bin │ │ ├── media_command.bin │ │ ├── media_state.bin │ │ ├── paired_identity_state_changed.bin │ │ ├── power_off.bin │ │ ├── poweron.bin │ │ ├── presence_request.bin │ │ ├── presence_response.bin │ │ ├── start_channel_request.bin │ │ ├── start_channel_request_title_channel.bin │ │ ├── start_channel_response.bin │ │ ├── system_text_acknowledge.bin │ │ ├── system_text_configuration.bin │ │ ├── system_text_done.bin │ │ ├── system_text_input.bin │ │ ├── system_touch.bin │ │ └── title_launch.bin ├── SmartGlass.Tests.csproj ├── TestBroadcastJson.cs ├── TestCertificate.cs ├── TestCrypto.cs ├── TestMessageExtensions.cs ├── TestMessageFixture.cs ├── TestNanoPacketParsing.cs ├── TestSgPacketAssembly.cs └── TestTaskExtensions.cs ├── SmartGlass.sln └── SmartGlass ├── ActiveTitle.cs ├── Analysis ├── MessageAnalyzer.cs └── MessageInfo.cs ├── Channels ├── AuxiliaryStreamClient.cs ├── AuxiliaryStreamCryptoContext.cs ├── AuxiliaryStreamDataReceivedEventArgs.cs ├── Broadcast │ ├── BroadcastMessageJsonConverter.cs │ ├── BroadcastMessageType.cs │ ├── BroadcastMessageTypeAttribute.cs │ ├── GamestreamConfigurationJsonConverter.cs │ ├── GamestreamError.cs │ ├── GamestreamException.cs │ ├── GamestreamStateMessageType.cs │ ├── GamestreamStateMessageTypeAttribute.cs │ └── Messages │ │ ├── BroadcastBaseMessage.cs │ │ ├── GamestreamEnabledMessage.cs │ │ ├── GamestreamErrorMessage.cs │ │ ├── GamestreamPreviewStatusMessage.cs │ │ ├── GamestreamStartMessage.cs │ │ ├── GamestreamStateBaseMessage.cs │ │ ├── GamestreamStateInitializingMessage.cs │ │ ├── GamestreamStatePausedMessage.cs │ │ ├── GamestreamStateStartedMessage.cs │ │ ├── GamestreamStateStoppedMessage.cs │ │ └── GamestreamStopMessage.cs ├── BroadcastChannel.cs ├── ChannelJsonSerializerSettings.cs ├── ChannelMessageTransport.cs ├── InputChannel.cs ├── InputTVRemoteChannel.cs ├── JsonBaseMessage.cs ├── JsonMessageTransport.cs ├── MediaChannel.cs ├── TextChannel.cs └── TitleChannel.cs ├── Common ├── AppDirs.cs ├── AsyncLazy.cs ├── AttributeTypeMapping.cs ├── DateTimeHelper.cs ├── DisposableAsyncLazy.cs ├── EndianReader.cs ├── EndianWriter.cs ├── EnumerableExtensions.cs ├── GamestreamConfiguration.cs ├── GamestreamSession.cs ├── IConvertToException.cs ├── IMessageTransport.cs ├── ISerializable.cs ├── Logging.cs ├── MessageExtensions.cs ├── MessageReceivedEventArgs.cs ├── Padding.cs ├── SocketExtensions.cs ├── StreamExtensions.cs ├── TaskExtensions.cs └── TypeExtensions.cs ├── Connection ├── CertificateExtensions.cs ├── ConnectionInfo.cs ├── CryptoContext.cs └── CryptoExtensions.cs ├── ConsoleConfiguration.cs ├── ConsoleStatus.cs ├── ConsoleStatusChangedEventArgs.cs ├── Device.cs ├── Enums ├── ActiveSurfaceType.cs ├── ActiveTitleLocation.cs ├── DeviceCapabilities.cs ├── DeviceFlags.cs ├── DeviceState.cs ├── DeviceType.cs ├── DisconnectReason.cs ├── GamepadButtons.cs ├── MediaControlCommands.cs ├── MediaPlaybackStatus.cs ├── MediaSoundLevel.cs ├── MediaType.cs ├── PairedIdentityState.cs ├── PublicKeyType.cs ├── TextInputScope.cs ├── TextOption.cs ├── TextResult.cs └── TouchAction.cs ├── GamepadState.cs ├── GlobalConfiguration.cs ├── IRCommandState.cs ├── IRDevice.cs ├── Json ├── GuidConverter.cs └── IPAddressConverter.cs ├── MediaCommandState.cs ├── MediaMetadata.cs ├── MediaState.cs ├── MediaStateChangedEventArgs.cs ├── Messaging ├── Connection │ ├── ConnectRequestMessage.cs │ ├── ConnectResponseMessage.cs │ ├── ConnectionMessageHeader.cs │ └── ConnectionResult.cs ├── Discovery │ ├── DiscoveryMessageHeader.cs │ ├── PresenceRequestMessage.cs │ └── PresenceResponseMessage.cs ├── ICryptoMessage.cs ├── IMessage.cs ├── IMessageHeader.cs ├── IProtectedMessageHeader.cs ├── MessageBase.cs ├── MessageTransport.cs ├── MessageType.cs ├── MessageTypeAttribute.cs ├── Power │ ├── PowerOnMessage.cs │ └── PowerOnMessageHeader.cs ├── ProtectedMessageBase.cs └── Session │ ├── FragmentMessageManager.cs │ ├── JsonFragmentManager.cs │ ├── Messages │ ├── AccelerometerMessage.cs │ ├── AckMessage.cs │ ├── ActiveSurfaceChangeMessage.cs │ ├── AuxiliaryStreamConnectionInfo.cs │ ├── AuxiliaryStreamEndpoint.cs │ ├── AuxiliaryStreamMessage.cs │ ├── CompassMessage.cs │ ├── ConsoleStatusMessage.cs │ ├── DisconnectMessage.cs │ ├── FragmentMessage.cs │ ├── GameDvrRecordMessage.cs │ ├── GamepadMessage.cs │ ├── GyrometerMessage.cs │ ├── InclinometerMessage.cs │ ├── JsonMessage.cs │ ├── LocalJoinMessage.cs │ ├── MediaCommandMessage.cs │ ├── MediaCommandResultMessage.cs │ ├── MediaControllerRemovedMessage.cs │ ├── MediaStateMessage.cs │ ├── OrientationMessage.cs │ ├── PairedIdentityStateChangedMessage.cs │ ├── PowerOffMessage.cs │ ├── StartChannelRequestMessage.cs │ ├── StartChannelResponseMessage.cs │ ├── StopChannelMessage.cs │ ├── StreamerConfiguration.cs │ ├── SystemTextAcknowledgeMessage.cs │ ├── SystemTextConfigurationMessage.cs │ ├── SystemTextDoneMessage.cs │ ├── SystemTextInputMessage.cs │ ├── SystemTouchMessage.cs │ ├── TextConfiguration.cs │ ├── TitleLaunchMessage.cs │ ├── TitleTextConfigurationMessage.cs │ ├── TitleTextInputMessage.cs │ ├── TitleTextSelectionMessage.cs │ ├── TitleTouchMessage.cs │ ├── TouchMessage.cs │ ├── UnknownMessage.cs │ └── UnsnapMessage.cs │ ├── ServiceType.cs │ ├── SessionFragmentMessage.cs │ ├── SessionFragmentMessageHeader.cs │ ├── SessionInfo.cs │ ├── SessionMessageBase.cs │ ├── SessionMessageHeader.cs │ ├── SessionMessageTransport.cs │ ├── SessionMessageType.cs │ └── SessionMessageTypeAttribute.cs ├── Nano ├── Channels │ ├── AudioChannel.cs │ ├── AudioChannelBase.cs │ ├── ChatAudioChannel.cs │ ├── ControlChannel.cs │ ├── IStreamingChannel.cs │ ├── InputChannel.cs │ ├── InputChannelBase.cs │ ├── InputFeedbackChannel.cs │ ├── StreamingChannel.cs │ └── VideoChannel.cs ├── Consumer │ ├── AACFrame.cs │ ├── AudioAssembler.cs │ ├── FileConsumer.cs │ ├── H264Frame.cs │ ├── IConsumer.cs │ └── VideoAssembler.cs ├── Enums │ ├── Attributes │ │ ├── AudioPayloadTypeAttribute.cs │ │ ├── ChannelControlTypeAttribute.cs │ │ ├── ControlOpCodeAttribute.cs │ │ ├── InputPayloadTypeAttribute.cs │ │ ├── NanoPayloadTypeAttribute.cs │ │ └── VideoPayloadTypeAttribute.cs │ ├── AudioCodec.cs │ ├── AudioControlFlags.cs │ ├── AudioPayloadType.cs │ ├── ChannelControlType.cs │ ├── ControlHandshakeType.cs │ ├── ControlOpCode.cs │ ├── ControllerEventType.cs │ ├── InputPayloadType.cs │ ├── NanoChannel.cs │ ├── NanoGamepadAxis.cs │ ├── NanoGamepadButton.cs │ ├── NanoPayloadType.cs │ ├── StreamerFlags.cs │ ├── VideoCodec.cs │ ├── VideoControlFlags.cs │ └── VideoPayloadType.cs ├── NanoChannelClass.cs ├── NanoChannelContext.cs ├── NanoClient.cs ├── NanoEventArgs.cs ├── NanoException.cs ├── NanoPacketFactory.cs ├── NanoPackingException.cs ├── Network │ └── NanoRdpTransport.cs └── Packets │ ├── Audio │ ├── AudioClientHandshake.cs │ ├── AudioControl.cs │ ├── AudioData.cs │ ├── AudioFormat.cs │ └── AudioServerHandshake.cs │ ├── ChannelControl │ ├── ChannelClose.cs │ ├── ChannelCreate.cs │ └── ChannelOpen.cs │ ├── ChannelControlMessage.cs │ ├── Control │ ├── ChangeVideoQuality.cs │ ├── ControllerEvent.cs │ ├── InitiateNetworkTest.cs │ ├── NetworkInformation.cs │ ├── NetworkTestResponse.cs │ ├── RealtimeTelemetry.cs │ ├── SessionCreate.cs │ ├── SessionCreateResponse.cs │ ├── SessionDestroy.cs │ ├── SessionInit.cs │ └── VideoStatistics.cs │ ├── ControlHandshake.cs │ ├── INanoPacket.cs │ ├── IStreamerMessage.cs │ ├── Input │ ├── InputAnalogue.cs │ ├── InputButtons.cs │ ├── InputClientHandshake.cs │ ├── InputExtension.cs │ ├── InputFrame.cs │ ├── InputFrameAck.cs │ └── InputServerHandshake.cs │ ├── RtpHeader.cs │ ├── StreamerControlHeader.cs │ ├── StreamerHeader.cs │ ├── StreamerMessage.cs │ ├── StreamerMessageWithHeader.cs │ ├── UdpHandshake.cs │ └── Video │ ├── VideoClientHandshake.cs │ ├── VideoControl.cs │ ├── VideoData.cs │ ├── VideoFormat.cs │ └── VideoServerHandshake.cs ├── SmartGlass.csproj ├── SmartGlassClient.cs ├── SmartGlassException.cs ├── TextDelta.cs └── TouchPoint.cs /.editorconfig: -------------------------------------------------------------------------------- 1 | # EditorConfig is awesome: http://EditorConfig.org 2 | 3 | # top-most EditorConfig file 4 | root = true 5 | 6 | # Unix-style newlines with a newline ending every file 7 | [*] 8 | end_of_line = lf 9 | insert_final_newline = true 10 | 11 | [*.cs] 12 | # 4 space indentation 13 | indent_style = space 14 | indent_size = 4 15 | 16 | 17 | csharp_new_line_before_catch = true 18 | csharp_new_line_before_else = true 19 | csharp_new_line_before_finally = true 20 | csharp_new_line_before_members_in_anonymous_types = true 21 | csharp_new_line_before_members_in_object_initializers = true 22 | csharp_new_line_before_open_brace = all 23 | csharp_new_line_between_query_expression_clauses = true 24 | -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | steps: 9 | - uses: actions/checkout@v2 10 | - name: Setup .NET Core 11 | uses: actions/setup-dotnet@v1 12 | with: 13 | dotnet-version: 5.0.102 14 | - name: Install dependencies 15 | run: dotnet restore 16 | - name: Build 17 | run: dotnet build --configuration Release --no-restore 18 | - name: Test 19 | run: dotnet test --no-restore --verbosity normal 20 | - name: Publish 21 | run: dotnet publish --configuration Release 22 | - name: Upload SmartGlass.Cli Artifact 23 | if: ${{ success() && github.ref == 'refs/heads/master' && github.event_name == 'push' }} 24 | uses: actions/upload-artifact@v2 25 | with: 26 | name: SmartGlass.Cli 27 | path: SmartGlass.Cli/bin/Release/net5.0/publish/ 28 | - name: Create tag and publish to nuget 29 | if: ${{ success() && github.ref == 'refs/heads/master' && github.event_name == 'push' }} 30 | id: publish_nuget 31 | uses: rohith/publish-nuget@v2 32 | with: 33 | PROJECT_FILE_PATH: SmartGlass/SmartGlass.csproj 34 | NUGET_KEY: ${{secrets.NUGET_API_KEY}} 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | ._.DS_Store 3 | bin 4 | obj 5 | .vs 6 | packages 7 | *.raw 8 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "files.exclude": { 3 | "**/obj": true 4 | }, 5 | "search.exclude": { 6 | "**/obj": true 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/solution-explorer/class.cs-template: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace {{namespace}} 4 | { 5 | public class {{name}} 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/solution-explorer/class.ts-template: -------------------------------------------------------------------------------- 1 | export class {{name}} { 2 | 3 | } -------------------------------------------------------------------------------- /.vscode/solution-explorer/class.vb-template: -------------------------------------------------------------------------------- 1 | Imports System 2 | 3 | Namespace {{namespace}} 4 | 5 | Public Class {{name}} 6 | 7 | End Class 8 | 9 | End Namespace 10 | -------------------------------------------------------------------------------- /.vscode/solution-explorer/default.ts-template: -------------------------------------------------------------------------------- 1 | export default {{name}} { 2 | 3 | } -------------------------------------------------------------------------------- /.vscode/solution-explorer/enum.cs-template: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace {{namespace}} 4 | { 5 | public enum {{name}} 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/solution-explorer/interface.cs-template: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace {{namespace}} 4 | { 5 | public interface {{name}} 6 | { 7 | } 8 | } 9 | -------------------------------------------------------------------------------- /.vscode/solution-explorer/interface.ts-template: -------------------------------------------------------------------------------- 1 | export interface {{name}} { 2 | 3 | } -------------------------------------------------------------------------------- /.vscode/solution-explorer/template-list.json: -------------------------------------------------------------------------------- 1 | { 2 | "templates": [ 3 | { 4 | "name": "Class", 5 | "extension": "cs", 6 | "file": "./class.cs-template", 7 | "parameters": "./template-parameters.js" 8 | }, 9 | { 10 | "name": "Interface", 11 | "extension": "cs", 12 | "file": "./interface.cs-template", 13 | "parameters": "./template-parameters.js" 14 | }, 15 | { 16 | "name": "Enum", 17 | "extension": "cs", 18 | "file": "./enum.cs-template", 19 | "parameters": "./template-parameters.js" 20 | }, 21 | { 22 | "name": "Class", 23 | "extension": "ts", 24 | "file": "./class.ts-template", 25 | "parameters": "./template-parameters.js" 26 | }, 27 | { 28 | "name": "Interface", 29 | "extension": "ts", 30 | "file": "./interface.ts-template", 31 | "parameters": "./template-parameters.js" 32 | }, 33 | { 34 | "name": "Default", 35 | "extension": "ts", 36 | "file": "./default.ts-template", 37 | "parameters": "./template-parameters.js" 38 | }, 39 | { 40 | "name": "Class", 41 | "extension": "vb", 42 | "file": "./class.vb-template", 43 | "parameters": "./template-parameters.js" 44 | } 45 | ] 46 | } -------------------------------------------------------------------------------- /.vscode/solution-explorer/template-parameters.js: -------------------------------------------------------------------------------- 1 | var path = require("path"); 2 | 3 | module.exports = function(filename, projectPath, folderPath) { 4 | var namespace = "Unknown"; 5 | if (projectPath) { 6 | namespace = path.basename(projectPath, path.extname(projectPath)); 7 | if (folderPath) { 8 | namespace += "." + folderPath.replace(path.dirname(projectPath), "").substring(1).replace(/[\\\/]/g, "."); 9 | } 10 | } 11 | 12 | return { 13 | namespace: namespace, 14 | name: path.basename(filename, path.extname(filename)) 15 | } 16 | }; -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "2.0.0", 3 | "tasks": [ 4 | { 5 | "label": "Build Library", 6 | "type": "shell", 7 | "group": "build", 8 | "command": "dotnet", 9 | "args": ["build", "${workspaceRoot}/SmartGlass/SmartGlass.csproj"], 10 | "problemMatcher": "$msCompile" 11 | }, 12 | { 13 | "label": "Build Cli", 14 | "type": "shell", 15 | "group": "build", 16 | "command": "dotnet", 17 | "args": ["build", "${workspaceRoot}/SmartGlass.Cli/SmartGlass.Cli.csproj"], 18 | "problemMatcher": "$msCompile" 19 | } 20 | ] 21 | } 22 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # CHANGELOG 2 | 3 | ## v1.0.4 (2018-12-12) 4 | - Correct timestamping 5 | - Generate codec specific data in H264Frame 6 | 7 | ## v1.0.3 (2018-12-08) 8 | - Update input structs 9 | 10 | ## v1.0.2 (2018-12-03) 11 | - Major refactor 12 | 13 | ## v1.0.1 (2018-11-14) 14 | - Introduce OpenXbox.SmartGlass.Common as own package 15 | - Nano: Implement IProvider 16 | - Refactoring 17 | 18 | ## v1.0.0 (2018-11-12) 19 | - Initial push to NuGet / OpenXbox 20 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright (c) 2020 OpenXbox 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /SmartGlass.Cli/AuthenticateCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | using XboxWebApi.Authentication; 6 | using XboxWebApi.Authentication.Model; 7 | 8 | 9 | namespace SmartGlass.Cli 10 | { 11 | internal class AuthenticateCommand : Command 12 | { 13 | [PositionalArgument(ArgumentFlags.Required, Position = 0)] 14 | public string TokenFilePath { get; set; } 15 | 16 | #pragma warning disable 1998 17 | public override async Task ExecuteAsync(CancellationToken cancel) 18 | { 19 | string authUrl = AuthenticationService.GetWindowsLiveAuthenticationUrl(); 20 | 21 | Console.WriteLine($"Go to following URL and authenticate: {authUrl}"); 22 | Console.WriteLine("Paste the returned URL and press ENTER: "); 23 | 24 | string redirectUrl = Console.ReadLine(); 25 | 26 | try 27 | { 28 | var response = AuthenticationService 29 | .ParseWindowsLiveResponse(redirectUrl); 30 | 31 | var authService = new AuthenticationService(response); 32 | 33 | await authService.AuthenticateAsync(); 34 | await authService.DumpToJsonFileAsync(TokenFilePath); 35 | } 36 | catch (Exception e) 37 | { 38 | Console.WriteLine($"Authentication failed! {e.Message}"); 39 | return CommandResult.RuntimeFailure; 40 | } 41 | 42 | Console.WriteLine($"Authentication succeeded, tokens saved to {TokenFilePath}"); 43 | return CommandResult.Success; 44 | } 45 | #pragma warning restore 1998 46 | } 47 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/BinaryExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Globalization; 3 | using System.Linq; 4 | 5 | namespace SmartGlass.Cli 6 | { 7 | internal static class BinaryExtensions 8 | { 9 | public static byte[] HexToBytes(this string hex) 10 | { 11 | return hex.Split(2).Select(c => 12 | byte.Parse(new string(c.ToArray()), NumberStyles.HexNumber)).ToArray(); 13 | } 14 | 15 | public static string ToHex(this byte[] bytes) 16 | { 17 | return BitConverter.ToString(bytes).Replace("-", "").ToLower(); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/DiscoverCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | 6 | namespace SmartGlass.Cli 7 | { 8 | internal class DiscoverCommand : Command 9 | { 10 | public override async Task ExecuteAsync(CancellationToken cancel) 11 | { 12 | var devices = await Device.DiscoverAsync(); 13 | 14 | foreach (var device in devices) 15 | { 16 | Console.WriteLine($"{device.Name} ({device.HardwareId}) {device.Address} {device.LiveId}"); 17 | } 18 | 19 | return CommandResult.Success; 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/MainCommandType.cs: -------------------------------------------------------------------------------- 1 | using NClap.Metadata; 2 | 3 | namespace SmartGlass.Cli 4 | { 5 | internal enum MainCommandType 6 | { 7 | [Command( 8 | typeof(AuthenticateCommand), 9 | Description = "Authenticate to Xbox Live via Microsoft Account.")] 10 | Authenticate, 11 | 12 | [Command( 13 | typeof(ConnectCommand), 14 | Description = "Opens a connection to an Xbox One console.")] 15 | Connect, 16 | 17 | [Command( 18 | typeof(BroadcastCommand), 19 | Description = "Connect and start a broadcast session.")] 20 | Broadcast, 21 | 22 | [Command( 23 | typeof(DiscoverCommand), 24 | Description = "Discover and list Xbox One consoles on the local network.")] 25 | Discover, 26 | 27 | [Command( 28 | typeof(PcapCommand), 29 | Description = "Decrypt captured messages.")] 30 | Pcap, 31 | 32 | [Command( 33 | typeof(PingCommand), 34 | Description = "Ping and output details of an Xbox One console.")] 35 | Ping, 36 | 37 | [Command( 38 | typeof(PowerOnCommand), 39 | Description = "Power on Xbox One console.")] 40 | PowerOn 41 | } 42 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/PingCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using NClap.Metadata; 6 | 7 | namespace SmartGlass.Cli 8 | { 9 | internal class PingCommand : Command 10 | { 11 | [PositionalArgument(ArgumentFlags.AtLeastOnce, Position = 0)] 12 | public string[] Hostnames { get; set; } 13 | 14 | public override async Task ExecuteAsync(CancellationToken cancel) 15 | { 16 | await Task.WhenAll(Hostnames.Select(async hostname => 17 | { 18 | try 19 | { 20 | var device = await Device.PingAsync(hostname); 21 | Console.WriteLine($"{device.Name} ({device.HardwareId}) {device.Address}"); 22 | } 23 | catch (TimeoutException) 24 | { 25 | Console.WriteLine($"No response from {hostname}"); 26 | } 27 | })); 28 | 29 | return CommandResult.Success; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/PowerOnCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Linq; 3 | using System.Threading; 4 | using System.Threading.Tasks; 5 | using NClap.Metadata; 6 | 7 | namespace SmartGlass.Cli 8 | { 9 | internal class PowerOnCommand : Command 10 | { 11 | [PositionalArgument(ArgumentFlags.Required, Position = 0)] 12 | public string LiveId { get; set; } 13 | 14 | public override async Task ExecuteAsync(CancellationToken cancel) 15 | { 16 | Console.WriteLine($"Powering on {LiveId}..."); 17 | 18 | Device device = null; 19 | try 20 | { 21 | device = await Device.PowerOnAsync(LiveId); 22 | Console.WriteLine($"{device.Name} ({device.HardwareId}) {device.Address}"); 23 | } 24 | catch (TimeoutException) 25 | { 26 | Console.WriteLine($"Failed to power on. No response from {LiveId}."); 27 | return CommandResult.RuntimeFailure; 28 | } 29 | if (device == null) 30 | { 31 | return CommandResult.RuntimeFailure; 32 | } 33 | 34 | return CommandResult.Success; 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SmartGlass.Cli/Program.cs: -------------------------------------------------------------------------------- 1 | using NClap; 2 | 3 | namespace SmartGlass.Cli 4 | { 5 | internal class Program 6 | { 7 | static int Main(string[] args) 8 | { 9 | var programArgs = new ProgramArguments(); 10 | if (!CommandLineParser.TryParse(args, out programArgs)) 11 | { 12 | return -1; 13 | } 14 | 15 | return (int)programArgs.Command.Execute(); 16 | } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass.Cli/ProgramArguments.cs: -------------------------------------------------------------------------------- 1 | using NClap.Metadata; 2 | 3 | namespace SmartGlass.Cli 4 | { 5 | [ArgumentSet( 6 | AnswerFileArgumentPrefix = null, 7 | Style = ArgumentSetStyle.GetOpt, 8 | NameGenerationFlags = ArgumentNameGenerationFlags.GenerateHyphenatedLowerCaseLongNames | 9 | ArgumentNameGenerationFlags.PreferLowerCaseForShortNames, 10 | Description = "Discover and control Xbox One consoles.")] 11 | internal class ProgramArguments : HelpArgumentsBase 12 | { 13 | [PositionalArgument(ArgumentFlags.Required, Position = 0)] 14 | public CommandGroup Command { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/Session/MediaCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | 6 | namespace SmartGlass.Cli.Session 7 | { 8 | using System.Linq; 9 | 10 | internal class MediaCommand : Command 11 | { 12 | [PositionalArgument(ArgumentFlags.AtMostOnce, Position = 0)] 13 | public string Command { get; set; } 14 | 15 | public override async Task ExecuteAsync(CancellationToken cancel) { 16 | var activeTitle = 17 | ConnectCommand.Client 18 | .CurrentConsoleStatus 19 | .ActiveTitles 20 | .FirstOrDefault() 21 | ?.TitleId ?? 0U; 22 | 23 | if (activeTitle == 0) { 24 | Console.WriteLine("Don't know the active title; skipping..."); 25 | return CommandResult.RuntimeFailure; 26 | } 27 | 28 | var state = new MediaCommandState(); 29 | state.TitleId = activeTitle; 30 | 31 | var parsed = Enum.TryParse(Command, true, out state.Command); 32 | if (!parsed) 33 | { 34 | return CommandResult.UsageError; 35 | } 36 | 37 | try 38 | { 39 | var mediaChannel = ConnectCommand.Client.MediaChannel; 40 | 41 | await mediaChannel.SendMediaCommandStateAsync(state); 42 | } 43 | catch (Exception e) 44 | { 45 | Console.WriteLine(e.Message); 46 | return CommandResult.RuntimeFailure; 47 | } 48 | 49 | return CommandResult.Success; 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /SmartGlass.Cli/Session/PowerOffCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | 6 | namespace SmartGlass.Cli.Session 7 | { 8 | internal class PowerOffCommand : Command 9 | { 10 | public override async Task ExecuteAsync(CancellationToken cancel) 11 | { 12 | try 13 | { 14 | await ConnectCommand.Client.PowerOffAsync(); 15 | } 16 | catch (Exception e) 17 | { 18 | Console.WriteLine(e.Message); 19 | return CommandResult.RuntimeFailure; 20 | } 21 | 22 | return CommandResult.Success; 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/Session/PressCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | 6 | namespace SmartGlass.Cli.Session 7 | { 8 | internal class PressCommand : Command 9 | { 10 | [PositionalArgument(ArgumentFlags.AtLeastOnce, Position = 0)] 11 | public string[] Buttons { get; set; } 12 | 13 | public override async Task ExecuteAsync(CancellationToken cancel) 14 | { 15 | var state = new GamepadState(); 16 | 17 | var parsed = Enum.TryParse(string.Join(", ", Buttons), true, out state.Buttons); 18 | if (!parsed) 19 | { 20 | return CommandResult.UsageError; 21 | } 22 | 23 | try 24 | { 25 | var inputChannel = ConnectCommand.Client.InputChannel; 26 | 27 | await inputChannel.SendGamepadStateAsync(state); 28 | await Task.Delay(100); 29 | await inputChannel.SendGamepadStateAsync(new GamepadState() 30 | { 31 | Buttons = GamepadButtons.Clear 32 | }); 33 | } 34 | catch (Exception e) 35 | { 36 | Console.WriteLine(e.Message); 37 | return CommandResult.RuntimeFailure; 38 | } 39 | 40 | return CommandResult.Success; 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SmartGlass.Cli/Session/RecordCommand.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading; 3 | using System.Threading.Tasks; 4 | using NClap.Metadata; 5 | 6 | namespace SmartGlass.Cli.Session 7 | { 8 | internal class RecordCommand : Command 9 | { 10 | [PositionalArgument(ArgumentFlags.Optional, Position = 0)] 11 | public int LastSeconds { get; set; } = 60; 12 | 13 | public override async Task ExecuteAsync(CancellationToken cancel) 14 | { 15 | try 16 | { 17 | await ConnectCommand.Client.GameDvrRecord(LastSeconds); 18 | } 19 | catch (Exception e) 20 | { 21 | Console.WriteLine(e.Message); 22 | return CommandResult.RuntimeFailure; 23 | } 24 | 25 | return CommandResult.Success; 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/Session/SessionCommandType.cs: -------------------------------------------------------------------------------- 1 | using NClap.Metadata; 2 | 3 | namespace SmartGlass.Cli.Session 4 | { 5 | internal enum SessionCommandType 6 | { 7 | [Command( 8 | typeof(ExitCommand), 9 | Description = "Disconnect from the console.")] 10 | Exit, 11 | 12 | [Command(typeof(MediaCommand))] 13 | Media, 14 | 15 | [Command(typeof(PressCommand))] 16 | Press, 17 | 18 | [Command(typeof(TitleChannelCommand))] 19 | TitleChannel, 20 | 21 | [Command(typeof(RecordCommand))] 22 | Record, 23 | 24 | [Command(typeof(PowerOffCommand))] 25 | PowerOff, 26 | 27 | [HelpCommand] 28 | Help 29 | } 30 | } -------------------------------------------------------------------------------- /SmartGlass.Cli/SmartGlass.Cli.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | Exe 4 | net5.0 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /SmartGlass.Tests/AsyncLazyTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using SmartGlass.Common; 3 | using Xunit; 4 | 5 | namespace SmartGlass.Tests 6 | { 7 | public class AsyncLazyTests 8 | { 9 | [Fact] 10 | public void TestAsyncLazy() 11 | { 12 | int tmpInt = 99; 13 | 14 | AsyncLazy cls = new AsyncLazy(() => 15 | { 16 | return Task.Run(() => { tmpInt = 42; return tmpInt; }); 17 | }); 18 | 19 | Assert.Equal(99, tmpInt); 20 | int result42 = cls.GetAsync().GetAwaiter().GetResult(); 21 | 22 | Assert.Equal(42, tmpInt); 23 | Assert.Equal(42, result42); 24 | } 25 | 26 | [Fact] 27 | public void TestAsyncLazyException() 28 | { 29 | AsyncLazy cls = new AsyncLazy(() => 30 | { 31 | throw new System.DivideByZeroException(""); 32 | }); 33 | 34 | Assert.ThrowsAsync(cls.GetAsync); 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/AttributeTypeMappingTests.cs: -------------------------------------------------------------------------------- 1 | using System.Threading.Tasks; 2 | using SmartGlass.Common; 3 | using Xunit; 4 | 5 | namespace SmartGlass.Tests 6 | { 7 | public class AttributeTypeMappingTests 8 | { 9 | [Fact] 10 | public void Test() 11 | { 12 | } 13 | } 14 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/console.json: -------------------------------------------------------------------------------- 1 | { 2 | "address": "192.168.1.3", 3 | "type": 1, 4 | "name": "XboxOne", 5 | "liveid": "FD0123456789", 6 | "uuid": "de305d54-75b4-431b-adb2-eb6b9e546014" 7 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/console_list.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "address": "192.168.1.3", 4 | "type": 1, 5 | "name": "XboxOne", 6 | "liveid": "FD0123456789", 7 | "uuid": "de305d54-75b4-431b-adb2-eb6b9e546014" 8 | }, 9 | { 10 | "address": "192.168.1.23", 11 | "type": 1, 12 | "name": "SecondXbox", 13 | "liveid": "ABEBEDAFSAS", 14 | "uuid": "fe508d34-75b4-431b-adb2-eb6b9e546012" 15 | } 16 | ] -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_enabled.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 4, 3 | "enabled": true, 4 | "canBeEnabled": true, 5 | "majorProtocolVersion": 6, 6 | "minorProtocolVersion": 0 7 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_preview_status.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 7, 3 | "isPublicPreview": false, 4 | "isInternalPreview": false 5 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_start_stream.json: -------------------------------------------------------------------------------- 1 | { 2 | "configuration": { 3 | "urcpType": "0", 4 | "urcpFixedRate": "-1", 5 | "urcpMaximumWindow": "1310720", 6 | "urcpMinimumRate": "256000", 7 | "urcpMaximumRate": "10000000", 8 | "urcpKeepAliveTimeoutMs": "0", 9 | "audioFecType": "0", 10 | "videoFecType": "0", 11 | "videoFecLevel": "3", 12 | "videoPacketUtilization": "0", 13 | "enableDynamicBitrate": "false", 14 | "dynamicBitrateScaleFactor": "1", 15 | "dynamicBitrateUpdateMs": "5000", 16 | "sendKeyframesOverTCP": "false", 17 | "videoMaximumWidth": "1280", 18 | "videoMaximumHeight": "720", 19 | "videoMaximumFrameRate": "60", 20 | "videoPacketDefragTimeoutMs": "16", 21 | "enableVideoFrameAcks": "false", 22 | "enableAudioChat": "true", 23 | "audioBufferLengthHns": "10000000", 24 | "audioSyncPolicy": "1", 25 | "audioSyncMinLatency": "10", 26 | "audioSyncDesiredLatency": "40", 27 | "audioSyncMaxLatency": "170", 28 | "audioSyncCompressLatency": "100", 29 | "audioSyncCompressFactor": "0.99", 30 | "audioSyncLengthenFactor": "1.01", 31 | "enableOpusAudio": "false", 32 | "enableOpusChatAudio": "true", 33 | "inputReadsPerSecond": "120", 34 | "udpMaxSendPacketsInWinsock": "250", 35 | "udpSubBurstGroups": "0", 36 | "udpBurstDurationMs": "12" 37 | }, 38 | "reQueryPreviewStatus": false, 39 | "type": 1 40 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_state_init.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 3, 3 | "state": 1, 4 | "sessionId": "{14608F3C-1C4A-4F32-9DA6-179CE1001E4A}", 5 | "udpPort": 49665, 6 | "tcpPort": 53394 7 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_state_invalid.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 3, 3 | "state": 0, 4 | "sessionId": "" 5 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_state_started.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 3, 3 | "state": 2, 4 | "sessionId": "{14608F3C-1C4A-4F32-9DA6-179CE1001E4A}", 5 | "isWirelessConnection": false, 6 | "wirelessChannel": 0, 7 | "transmitLinkSpeed": 1000000000 8 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Json/gamestream_state_stopped.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": 3, 3 | "state": 3, 4 | "sessionId": "{14608F3C-1C4A-4F32-9DA6-179CE1001E4A}" 5 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Misc/selfsigned_cert.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Misc/selfsigned_cert.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Misc/sg_capture.pcap: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Misc/sg_capture.pcap -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_audio_client_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_audio_client_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_audio_control.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_audio_control.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_audio_server_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_audio_server_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_channel_close.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_channel_close.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_channel_create.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_channel_create.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_channel_open_no_flags.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_channel_open_no_flags.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_channel_open_with_flags.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_channel_open_with_flags.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_control_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_control_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_control_msg_with_header_change_video_quality.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_control_msg_with_header_change_video_quality.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_control_msg_with_header_realtime_telemetry.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_control_msg_with_header_realtime_telemetry.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_input_client_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_input_client_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_input_server_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_input_server_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_video_client_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_video_client_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_video_control.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_video_control.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/tcp_video_server_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/tcp_video_server_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/udp_audio_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/udp_audio_data.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/udp_handshake.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/udp_handshake.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/udp_input_frame.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/udp_input_frame.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/udp_input_frame_ack.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/udp_input_frame_ack.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/Nano/udp_video_data.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/Nano/udp_video_data.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/ResourcesProvider.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Collections.Generic; 4 | using Xunit; 5 | using System.Threading.Tasks; 6 | 7 | namespace SmartGlass.Tests.Resources 8 | { 9 | public enum ResourceType 10 | { 11 | Json, 12 | Misc, 13 | Nano, 14 | SmartGlass, 15 | } 16 | 17 | public class ResourcesProvider 18 | { 19 | static readonly string ResourcePath = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "../../../Resources"); 20 | 21 | public static byte[] GetBytes(string fileName, ResourceType type = ResourceType.Misc) 22 | { 23 | var file = $"{ResourcePath}/{type}/{fileName}"; 24 | if (File.Exists(file)) 25 | { 26 | return File.ReadAllBytes(file); 27 | } 28 | throw new FileNotFoundException(file); 29 | } 30 | 31 | public static async Task GetBytesAsync(string fileName, ResourceType type = ResourceType.Misc) 32 | { 33 | var file = $"{ResourcePath}/{type}/{fileName}"; 34 | if (File.Exists(file)) 35 | { 36 | return await File.ReadAllBytesAsync(file); 37 | } 38 | throw new FileNotFoundException(file); 39 | } 40 | public static string GetString(string fileName, ResourceType type = ResourceType.Misc) 41 | { 42 | var file = $"{ResourcePath}/{type}/{fileName}"; 43 | if (File.Exists(file)) 44 | { 45 | return System.Text.Encoding.UTF8.GetString( 46 | File.ReadAllBytes(file) 47 | ); 48 | } 49 | throw new FileNotFoundException(file); 50 | } 51 | } 52 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/acknowledge.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/acknowledge.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/active_surface_change.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/active_surface_change.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/auxiliary_stream_connection_info.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/auxiliary_stream_connection_info.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/auxiliary_stream_hello.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/auxiliary_stream_hello.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/connect_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/connect_request.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/connect_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/connect_response.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/console_status.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/console_status.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/disconnect.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/disconnect.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_0.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_0.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_1.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_1.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_2.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/fragment_media_state_2.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/gamedvr_record.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/gamedvr_record.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/gamepad.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/gamepad.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/json.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/json.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/local_join.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/local_join.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/media_command.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/media_command.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/media_state.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/media_state.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/paired_identity_state_changed.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/paired_identity_state_changed.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/power_off.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/power_off.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/poweron.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/poweron.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/presence_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/presence_request.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/presence_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/presence_response.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/start_channel_request.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/start_channel_request.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/start_channel_request_title_channel.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/start_channel_request_title_channel.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/start_channel_response.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/start_channel_response.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/system_text_acknowledge.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/system_text_acknowledge.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/system_text_configuration.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/system_text_configuration.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/system_text_done.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/system_text_done.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/system_text_input.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/system_text_input.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/system_touch.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/system_touch.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/Resources/SmartGlass/title_launch.bin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/OpenXbox/xbox-smartglass-csharp/ad4d81394b6fa1dfeecb4901516ff278e8aeae19/SmartGlass.Tests/Resources/SmartGlass/title_launch.bin -------------------------------------------------------------------------------- /SmartGlass.Tests/SmartGlass.Tests.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | net5.0 5 | true 6 | false 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /SmartGlass.Tests/TestCertificate.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SmartGlass.Common; 3 | using SmartGlass.Connection; 4 | using SmartGlass.Tests.Resources; 5 | using Xunit; 6 | 7 | namespace SmartGlass.Tests 8 | { 9 | public class TestCertificate 10 | { 11 | public TestCertificate() 12 | { 13 | } 14 | 15 | [Fact] 16 | public void TestCertificateDeserialize() 17 | { 18 | byte[] cert = ResourcesProvider.GetBytes("selfsigned_cert.bin", ResourceType.Misc); 19 | var x509 = CryptoExtensions.DeserializeCertificateAsn(cert); 20 | var publicKey = x509.GetPublicKey(); 21 | 22 | Assert.NotNull(x509); 23 | Assert.Equal(3, x509.Version); 24 | Assert.Equal("CN=Rust", x509.IssuerDN.ToString()); 25 | Assert.Equal("CN=FFFFFFFFFFF", x509.SubjectDN.ToString()); 26 | Assert.NotNull(publicKey); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/TestCrypto.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SmartGlass; 3 | using SmartGlass.Common; 4 | using SmartGlass.Connection; 5 | using SmartGlass.Tests.Resources; 6 | using Xunit; 7 | 8 | namespace SmartGlass.Tests 9 | { 10 | public class TestCrypto 11 | { 12 | public TestCrypto() 13 | { 14 | } 15 | 16 | [Fact] 17 | public void TestCryptoSetup() 18 | { 19 | byte[] cert = ResourcesProvider.GetBytes("selfsigned_cert.bin", ResourceType.Misc); 20 | var x509 = CryptoExtensions.DeserializeCertificateAsn(cert); 21 | 22 | CryptoContext context = new CryptoContext(x509); 23 | 24 | Assert.NotNull(context); 25 | Assert.Equal(PublicKeyType.EC_DH_P256, context.PublicKeyType); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/TestMessageFixture.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using SmartGlass.Common; 4 | 5 | namespace SmartGlass.Tests 6 | { 7 | public class TestFixture : IDisposable 8 | { 9 | private bool _disposed = false; 10 | 11 | public TestFixture() 12 | { 13 | } 14 | 15 | /* Test classes start */ 16 | public interface ITestMessage 17 | { 18 | 19 | } 20 | 21 | public class TestMessage1 : ITestMessage 22 | { 23 | public int Number; 24 | } 25 | 26 | public class TestMessage2 : ITestMessage 27 | { 28 | public int Decimal; 29 | } 30 | 31 | public class MessageTransportTestCls : IMessageTransport 32 | { 33 | public event System.EventHandler> MessageReceived; 34 | 35 | public void DummyConsume(ITestMessage msg) 36 | => MessageReceived?.Invoke(this, new MessageReceivedEventArgs(msg)); 37 | 38 | public Task SendAsync(ITestMessage message) 39 | { 40 | throw new System.NotImplementedException(); 41 | } 42 | } 43 | 44 | protected virtual void Dispose(bool disposing) 45 | { 46 | if (!_disposed) 47 | { 48 | if (disposing) 49 | { 50 | } 51 | 52 | _disposed = true; 53 | } 54 | } 55 | 56 | void IDisposable.Dispose() 57 | { 58 | Dispose(true); 59 | } 60 | } 61 | } -------------------------------------------------------------------------------- /SmartGlass.Tests/TestTaskExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Threading.Tasks; 4 | using SmartGlass; 5 | using SmartGlass.Common; 6 | using SmartGlass.Connection; 7 | using SmartGlass.Messaging; 8 | using SmartGlass.Tests.Resources; 9 | using Xunit; 10 | using static SmartGlass.Tests.TestFixture; 11 | using TaskExtensions = SmartGlass.Common.TaskExtensions; 12 | 13 | namespace SmartGlass.Tests 14 | { 15 | public class TestTaskExtensions 16 | { 17 | readonly TimeSpan[] fastRetryPolicy = new TimeSpan[]{ 18 | TimeSpan.FromMilliseconds(100), 19 | TimeSpan.FromMilliseconds(150), 20 | TimeSpan.FromMilliseconds(200), 21 | TimeSpan.FromMilliseconds(250) 22 | }; 23 | 24 | [Fact] 25 | public async void TestWithRetries() 26 | { 27 | var dtNow = DateTime.Now; 28 | await TaskExtensions.WithRetries( 29 | () => Task.Run(() => {}), 30 | fastRetryPolicy, 31 | (t) => true 32 | ); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /SmartGlass/ActiveTitle.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass 5 | { 6 | public class ActiveTitle : ISerializable 7 | { 8 | public uint TitleId { get; private set; } 9 | public ActiveTitleLocation TitleLocation { get; private set; } 10 | public bool HasFocus { get; private set; } 11 | public Guid ProductId { get; private set; } 12 | public Guid SandboxId { get; private set; } 13 | public string AumId { get; private set; } 14 | 15 | void ISerializable.Deserialize(EndianReader reader) 16 | { 17 | TitleId = reader.ReadUInt32BE(); 18 | 19 | ushort titleDisposition = reader.ReadUInt16BE(); 20 | HasFocus = (titleDisposition & 0x8000) == 0x8000; 21 | TitleLocation = (ActiveTitleLocation)(titleDisposition & 0x7FFF); 22 | 23 | ProductId = new Guid(reader.ReadBytes(16)); 24 | SandboxId = new Guid(reader.ReadBytes(16)); 25 | 26 | AumId = reader.ReadUInt16BEPrefixedString(); 27 | } 28 | 29 | void ISerializable.Serialize(EndianWriter writer) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /SmartGlass/Analysis/MessageInfo.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Analysis 2 | { 3 | /// 4 | /// MessageInfo holds basic information about a SmartGlass 5 | /// message in a flat representation. 6 | /// 7 | public class MessageInfo 8 | { 9 | public string MessageType { get; set; } 10 | public ulong ChannelId { get; set; } 11 | public int Version { get; set; } 12 | public byte[] Data { get; set; } 13 | public string Json { get; set; } 14 | public bool RequestAcknowledge { get; set; } 15 | } 16 | } -------------------------------------------------------------------------------- /SmartGlass/Channels/AuxiliaryStreamDataReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Channels 4 | { 5 | /// 6 | /// Auxiliary stream data event arguments. 7 | /// 8 | public class AuxiliaryStreamDataReceivedEventArgs : EventArgs 9 | { 10 | private readonly byte[] _data; 11 | /// 12 | /// Gets the decrypted data chunk. 13 | /// 14 | /// Decrypted data chunk. 15 | public byte[] Data => _data; 16 | 17 | public AuxiliaryStreamDataReceivedEventArgs(byte[] data) 18 | { 19 | _data = data; 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/BroadcastMessageType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Channels.Broadcast 4 | { 5 | /// 6 | /// Broadcast message type. 7 | /// 8 | enum BroadcastMessageType 9 | { 10 | StartGamestream = 1, 11 | StopGamestream, 12 | GamestreamState, 13 | GamestreamEnabled, 14 | GamestreamError, 15 | Telemetry, 16 | PreviewStatus 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/BroadcastMessageTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Channels.Broadcast 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | class BroadcastMessageTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(BroadcastMessageType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static BroadcastMessageType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public BroadcastMessageType MessageType { get; private set; } 26 | 27 | public BroadcastMessageTypeAttribute(BroadcastMessageType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/GamestreamError.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Channels.Broadcast 4 | { 5 | /// 6 | /// Gamestream error. 7 | /// 8 | public enum GamestreamError 9 | { 10 | General = 1, 11 | FailedToInstantiate, 12 | FailedToInitialize, 13 | FailedToStart, 14 | FailedToStop, 15 | NoController, 16 | DifferentMSAactive, 17 | DrmVideo, 18 | HdcpVideo, 19 | KinectTitle, 20 | ProhibitedGame, 21 | PoorNetworkConnection, 22 | StreamingDisabled, 23 | CannotReachConsole, 24 | GenericError, 25 | VersionMismatch, 26 | NoProfile, 27 | BroadcastInProgress 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/GamestreamException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Newtonsoft.Json; 4 | using SmartGlass.Messaging.Session.Messages; 5 | using SmartGlass.Common; 6 | using SmartGlass.Messaging.Session; 7 | using SmartGlass.Channels.Broadcast; 8 | using SmartGlass.Channels.Broadcast.Messages; 9 | using Newtonsoft.Json.Serialization; 10 | 11 | namespace SmartGlass.Channels.Broadcast 12 | { 13 | /// 14 | /// Gamestream exception. 15 | /// 16 | public class GamestreamException : SmartGlassException 17 | { 18 | public GamestreamException(string message, GamestreamError result) 19 | : base(message, (int)result) 20 | { 21 | } 22 | 23 | /// 24 | /// Gets the specific GamestreamError. 25 | /// 26 | /// The error. 27 | public GamestreamError Error => (GamestreamError)HResult; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/GamestreamStateMessageType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Channels.Broadcast 4 | { 5 | /// 6 | /// Gamestream state message type. 7 | /// 8 | enum GamestreamStateMessageType 9 | { 10 | Invalid, 11 | Initializing, 12 | Started, 13 | Stopped, 14 | Paused 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/GamestreamStateMessageTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Channels.Broadcast 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | class GamestreamStateMessageTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(GamestreamStateMessageType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static GamestreamStateMessageType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public GamestreamStateMessageType MessageType { get; private set; } 26 | 27 | public GamestreamStateMessageTypeAttribute(GamestreamStateMessageType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/BroadcastBaseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace SmartGlass.Channels.Broadcast.Messages 6 | { 7 | /// 8 | /// All broadcast messages derive from this 9 | /// 10 | class BroadcastBaseMessage 11 | { 12 | /// 13 | /// Type of Broadcast message 14 | /// 15 | /// Broadcast message type 16 | public BroadcastMessageType Type { get; set; } 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamEnabledMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Informs the client about the availability of gamestream 10 | /// functionality and used protocol version. 11 | /// Sent from console to client when Broadcast channel is opened. 12 | /// 13 | [BroadcastMessageType(BroadcastMessageType.GamestreamEnabled)] 14 | class GamestreamEnabledMessage : BroadcastBaseMessage 15 | { 16 | /// 17 | /// Indicating whether gamestreaming is enabled on the console. 18 | /// 19 | /// true if enabled; otherwise, false. 20 | public bool Enabled { get; set; } 21 | /// 22 | /// Indicating whether gamestreaming can be enabled on the console. 23 | /// 24 | /// true if enabling is possible; otherwise, false. 25 | public bool CanBeEnabled { get; set; } 26 | /// 27 | /// Major version of running Nano protocol. 28 | /// 29 | /// The major protocol version. 30 | public int MajorProtocolVersion { get; set; } 31 | /// 32 | /// Minor version of running Nano protocol. 33 | /// 34 | /// The minor protocol version. 35 | public int MinorProtocolVersion { get; set; } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamErrorMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | using SmartGlass.Messaging.Session; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Serialization; 6 | 7 | namespace SmartGlass.Channels.Broadcast.Messages 8 | { 9 | /// 10 | /// Broadcast error message. 11 | /// Sent from console to client when an error occurs. 12 | /// 13 | [BroadcastMessageType(BroadcastMessageType.GamestreamError)] 14 | class BroadcastErrorMessage : BroadcastBaseMessage, IConvertToException 15 | { 16 | /// 17 | /// Type of error 18 | /// 19 | /// The type of the error. 20 | public int ErrorType { get; set; } 21 | /// 22 | /// Error value 23 | /// 24 | /// The error value. 25 | public GamestreamError ErrorValue { get; set; } 26 | 27 | public Exception ToException() 28 | { 29 | return new GamestreamException("Gamestream error ocurred.", ErrorValue); 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamPreviewStatusMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream preview status message. 10 | /// Sent from console to client. 11 | /// 12 | [BroadcastMessageType(BroadcastMessageType.PreviewStatus)] 13 | class GamestreamPreviewStatusMessage : BroadcastBaseMessage 14 | { 15 | /// 16 | /// Iindicating whether console is running public preview (Nano or OS?). 17 | /// 18 | /// true if running public preview; otherwise, false. 19 | public bool IsPublicPreview { get; set; } 20 | /// 21 | /// Iindicating whether console is running internal preview (Nano or OS?). 22 | /// 23 | /// true if running internal preview; otherwise, false. 24 | public bool IsInternalPreview { get; set; } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStartMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream start message. 10 | /// Sent from client to console to initialize Gamestream. 11 | /// 12 | [BroadcastMessageType(BroadcastMessageType.StartGamestream)] 13 | class GamestreamStartMessage : BroadcastBaseMessage 14 | { 15 | /// 16 | /// Desired Gamestream configuration 17 | /// 18 | /// The configuration. 19 | public GamestreamConfiguration Configuration { get; set; } 20 | /// 21 | /// Indicating whether client wants to re-query console's preview status. 22 | /// 23 | /// 24 | /// true if re-querying preview status is desired, 25 | /// otherwise, false. 26 | /// 27 | public bool ReQueryPreviewStatus { get; set; } 28 | 29 | public GamestreamStartMessage() 30 | { 31 | Type = BroadcastMessageType.StartGamestream; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStateBaseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Channels.Broadcast.Messages 4 | { 5 | /// 6 | /// Gamestream state base message. 7 | /// 8 | class GamestreamStateBaseMessage : BroadcastBaseMessage 9 | { 10 | /// 11 | /// Gamestream state. 12 | /// State messages are sent from console to client. 13 | /// 14 | /// The state. 15 | public GamestreamStateMessageType State { get; set; } 16 | /// 17 | /// Current session identifier. 18 | /// 19 | /// The session identifier. 20 | public Guid SessionId { get; set; } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStateInitializingMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream state initializing message. 10 | /// Sent from console to client when console has finished setting up 11 | /// Nano and is ready for a client connection. 12 | /// 13 | [GamestreamStateMessageType(GamestreamStateMessageType.Initializing)] 14 | class GamestreamStateInitializingMessage : GamestreamStateBaseMessage 15 | { 16 | /// 17 | /// TCP port running the "Control protocol" 18 | /// 19 | /// The TCP port. 20 | public int TcpPort { get; set; } 21 | /// 22 | /// UDP port running the "Streaming protocol" 23 | /// 24 | /// The UDP port. 25 | public int UdpPort { get; set; } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStatePausedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream state paused message. 10 | /// Sent from console to client when gamestreaming is paused. 11 | /// 12 | [GamestreamStateMessageType(GamestreamStateMessageType.Paused)] 13 | class GamestreamStatePausedMessage : GamestreamStateBaseMessage 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStateStartedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream state started message. 10 | /// Sent from console to client when gamestreaming has started. 11 | /// 12 | [GamestreamStateMessageType(GamestreamStateMessageType.Started)] 13 | class GamestreamStateStartedMessage : GamestreamStateBaseMessage 14 | { 15 | /// 16 | /// Indicating whether console is connected to the nework via a wireless connection. 17 | /// 18 | /// true if wireless connection is used; otherwise, false. 19 | public bool IsWirelessConnection { get; set; } 20 | /// 21 | /// Wireless channel the console is connected with, in case of wireless connection. 22 | /// 23 | /// Used wireless channel. 24 | public int WirelessChannel { get; set; } 25 | /// 26 | /// Network transmit link speed. 27 | /// 28 | /// The transmit link speed. 29 | public int TransmitLinkSpeed { get; set; } 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStateStoppedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Messaging.Session; 3 | using Newtonsoft.Json; 4 | using Newtonsoft.Json.Serialization; 5 | 6 | namespace SmartGlass.Channels.Broadcast.Messages 7 | { 8 | /// 9 | /// Gamestream state stopped message. 10 | /// Sent from console to client when gamestreaming is stopped. 11 | /// 12 | [GamestreamStateMessageType(GamestreamStateMessageType.Stopped)] 13 | class GamestreamStateStoppedMessage : GamestreamStateBaseMessage 14 | { 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/Channels/Broadcast/Messages/GamestreamStopMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Newtonsoft.Json; 3 | using Newtonsoft.Json.Serialization; 4 | 5 | namespace SmartGlass.Channels.Broadcast.Messages 6 | { 7 | /// 8 | /// Gamestream stop message. 9 | /// Unsure which participant sends this. 10 | /// Normally disconnecting the Tcp/Udp sockets is sufficient to stop 11 | /// gamestreaming. 12 | /// 13 | class GamestreamStopMessage : BroadcastBaseMessage 14 | { 15 | public GamestreamStopMessage() 16 | { 17 | Type = BroadcastMessageType.StopGamestream; 18 | } 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /SmartGlass/Channels/ChannelJsonSerializerSettings.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using Microsoft.Extensions.Logging; 4 | using Newtonsoft.Json; 5 | using Newtonsoft.Json.Serialization; 6 | using SmartGlass.Json; 7 | using SmartGlass.Channels.Broadcast; 8 | 9 | namespace SmartGlass.Channels 10 | { 11 | /// 12 | /// Json serializer settings for ServiceChannels 13 | /// 14 | static class ChannelJsonSerializerSettings 15 | { 16 | /// 17 | /// Gets the JSON serializer settings for Broadcast channel. 18 | /// 19 | /// JSON serializer settings 20 | public static JsonSerializerSettings GetBroadcastSettings() 21 | { 22 | var serializerSettings = new JsonSerializerSettings() 23 | { 24 | ContractResolver = new CamelCasePropertyNamesContractResolver() 25 | }; 26 | 27 | serializerSettings.Converters.Add(new GuidConverter()); 28 | serializerSettings.Converters.Add(new BroadcastMessageJsonConverter()); 29 | serializerSettings.Converters.Add(new GamestreamConfigurationJsonConverter()); 30 | 31 | return serializerSettings; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartGlass/Channels/InputChannel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | using SmartGlass.Messaging.Session.Messages; 4 | 5 | namespace SmartGlass.Channels 6 | { 7 | /// 8 | /// Input channel. 9 | /// Handles touch / gamepad / sensor input. 10 | /// 11 | public class InputChannel : IDisposable 12 | { 13 | private bool _disposed = false; 14 | private readonly ChannelMessageTransport _transport; 15 | 16 | /// 17 | /// Initializes a new instance of the class. 18 | /// 19 | /// Base transport. 20 | internal InputChannel(ChannelMessageTransport transport) 21 | { 22 | _transport = transport; 23 | } 24 | 25 | /// 26 | /// Sends a gamepad state message. 27 | /// 28 | /// Message send task. 29 | /// Gamepad state. 30 | public async Task SendGamepadStateAsync(GamepadState state) 31 | { 32 | var message = new GamepadMessage(); 33 | message.State = state; 34 | 35 | await _transport.SendAsync(message); 36 | } 37 | 38 | protected virtual void Dispose(bool disposing) 39 | { 40 | if (!_disposed) 41 | { 42 | if (disposing) 43 | { 44 | _transport.Dispose(); 45 | } 46 | _disposed = true; 47 | } 48 | } 49 | 50 | public void Dispose() 51 | { 52 | Dispose(true); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /SmartGlass/Channels/JsonBaseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SmartGlass.Channels.Broadcast.Messages { 6 | public class JsonBaseMessage { 7 | public string msgid { get; set; } 8 | public string request { get; set; } 9 | public object @params { get; set; } 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Common/AsyncLazy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace SmartGlass.Common 5 | { 6 | public class AsyncLazy 7 | { 8 | private readonly object _lockObject = new object(); 9 | protected object LockObject => _lockObject; 10 | 11 | private readonly Func> _createFunc; 12 | 13 | private Task _value; 14 | protected Task Value => _value; 15 | 16 | public AsyncLazy(Func> createFunc) 17 | { 18 | _createFunc = createFunc; 19 | } 20 | 21 | public Task GetAsync() 22 | { 23 | lock (_lockObject) 24 | { 25 | if (_value == null) 26 | { 27 | _value = _createFunc(); 28 | } 29 | } 30 | 31 | return _value; 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /SmartGlass/Common/DisposableAsyncLazy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace SmartGlass.Common 5 | { 6 | /// 7 | /// Disposable async lazy. 8 | /// 9 | public class DisposableAsyncLazy : AsyncLazy, IDisposable 10 | where T : IDisposable 11 | { 12 | private bool _isDisposed; 13 | 14 | public DisposableAsyncLazy(Func> createFunc) 15 | : base(createFunc) 16 | { 17 | } 18 | 19 | public void Dispose() 20 | { 21 | lock (LockObject) 22 | { 23 | if (_isDisposed) 24 | { 25 | return; 26 | } 27 | 28 | _isDisposed = true; 29 | } 30 | 31 | if (Value != null) 32 | { 33 | Value.When().Wait(); 34 | 35 | if (Value.Status == TaskStatus.RanToCompletion) 36 | { 37 | Value.Result.Dispose(); 38 | } 39 | } 40 | } 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /SmartGlass/Common/EnumerableExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | 5 | namespace SmartGlass.Common 6 | { 7 | /// 8 | /// Enumerable extensions. 9 | /// 10 | public static class EnumerableExtensions 11 | { 12 | public static IEnumerable DistinctBy(this IEnumerable enumerable, Func keySelector) 13 | { 14 | return enumerable.GroupBy(keySelector).Select(g => g.First()); 15 | } 16 | 17 | public static IEnumerable EnumerableOf(params T[] items) 18 | { 19 | return items; 20 | } 21 | 22 | public static IEnumerable OfRange(int first, int last) 23 | { 24 | if (first > last) 25 | { 26 | throw new ArgumentException("The start of the range must be equal to or less than the end."); 27 | } 28 | 29 | for (var i = first; i <= last; i++) 30 | { 31 | yield return i; 32 | } 33 | } 34 | 35 | public static IEnumerable EnumerableOf(T item, int size) 36 | { 37 | if (size == 0) 38 | { 39 | return new T[] { }; 40 | } 41 | 42 | return OfRange(0, size - 1).Select(i => item).ToArray(); 43 | } 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /SmartGlass/Common/GamestreamSession.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Common 5 | { 6 | /// 7 | /// Gamestream session. 8 | /// Returned by BroadcastChannel when gamestreaming is initialized 9 | /// successfully. 10 | /// TODO: Error events. 11 | /// 12 | public class GamestreamSession 13 | { 14 | public Guid SessionId { get; private set; } 15 | public GamestreamConfiguration Config { get; private set; } 16 | public int TcpPort { get; private set; } 17 | public int UdpPort { get; private set; } 18 | 19 | /// 20 | /// Initializes a new instance of the class. 21 | /// 22 | /// TCP port. 23 | /// UDP port. 24 | /// Used gamestreaming configuration. 25 | /// Identifier of gamestream session. 26 | public GamestreamSession(int tcpPort, int udpPort, GamestreamConfiguration config, Guid sessionId) 27 | { 28 | Config = config; 29 | SessionId = sessionId; 30 | TcpPort = tcpPort; 31 | UdpPort = udpPort; 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartGlass/Common/IConvertToException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Common 4 | { 5 | /// 6 | /// Convert to exception. 7 | /// 8 | public interface IConvertToException 9 | { 10 | Exception ToException(); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SmartGlass/Common/IMessageTransport.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Threading.Tasks; 3 | 4 | namespace SmartGlass.Common 5 | { 6 | public interface IMessageTransport 7 | { 8 | event EventHandler> MessageReceived; 9 | 10 | Task SendAsync(TMessage message); 11 | } 12 | } -------------------------------------------------------------------------------- /SmartGlass/Common/ISerializable.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | 3 | namespace SmartGlass.Common 4 | { 5 | /// 6 | /// Serializable interface 7 | /// 8 | public interface ISerializable 9 | { 10 | void Deserialize(EndianReader reader); 11 | void Serialize(EndianWriter writer); 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SmartGlass/Common/Logging.cs: -------------------------------------------------------------------------------- 1 | 2 | 3 | using Microsoft.Extensions.Logging; 4 | using Microsoft.Extensions.Logging.Debug; 5 | 6 | namespace SmartGlass.Common 7 | { 8 | /// 9 | /// Logging factory. 10 | /// 11 | public class Logging 12 | { 13 | public static ILoggerFactory Factory { get; private set; } = 14 | LoggerFactory.Create(builder => builder.AddDebug().SetMinimumLevel(LogLevel.Trace)); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/Common/MessageReceivedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Common 4 | { 5 | /// 6 | /// Message received event arguments. 7 | /// 8 | public class MessageReceivedEventArgs : EventArgs 9 | { 10 | private readonly TMessage _message; 11 | /// 12 | /// Received message. 13 | /// 14 | /// The message. 15 | public TMessage Message => _message; 16 | 17 | /// 18 | /// Initializes a new instance of the class. 19 | /// 20 | /// Message. 21 | public MessageReceivedEventArgs(TMessage message) 22 | { 23 | _message = message; 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartGlass/Common/StreamExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Linq; 4 | using System.IO; 5 | 6 | namespace SmartGlass.Common 7 | { 8 | /// 9 | /// BinaryReader/Writer extensions. 10 | /// 11 | public static class StreamExtensions 12 | { 13 | public static byte[] ToBytes(this Stream stream) 14 | { 15 | var memoryStream = stream as MemoryStream ?? new MemoryStream(); 16 | if (memoryStream != stream) 17 | { 18 | stream.CopyTo(memoryStream); 19 | } 20 | return memoryStream.ToArray(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SmartGlass/Common/TypeExtensions.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Common 4 | { 5 | /// 6 | /// Type extensions. 7 | /// 8 | public static class TypeExtensions 9 | { 10 | /// 11 | /// Checks if one object is assignable to another. 12 | /// 13 | /// 14 | /// true, if object is assignable to provided type, false otherwise. 15 | /// 16 | /// Type to assigning. 17 | /// Object to check. 18 | public static bool IsAssignableTo(this Type type, Type c) 19 | { 20 | return c.IsAssignableFrom(type); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SmartGlass/Connection/CertificateExtensions.cs: -------------------------------------------------------------------------------- 1 | using System.IO; 2 | using Org.BouncyCastle.Asn1; 3 | using Org.BouncyCastle.Asn1.X509; 4 | using Org.BouncyCastle.Crypto.Parameters; 5 | using Org.BouncyCastle.X509; 6 | 7 | namespace SmartGlass.Connection 8 | { 9 | /// 10 | /// Certificate extensions. 11 | /// 12 | internal static class CertificateExtensions 13 | { 14 | /// 15 | /// Gets the LiveID from a X509 certificate. 16 | /// It assumes that the ID is contained in "SubjectDN" field. 17 | /// 18 | /// The LiveID. 19 | /// Certificate received with DiscoveryResponse. 20 | public static string GetLiveId(this X509Certificate cert) 21 | { 22 | var subjectDnValues = cert.SubjectDN.GetValueList(); 23 | if (subjectDnValues.Count < 1) 24 | throw new InvalidDataException("Certificate does not contain SubjectDN"); 25 | 26 | return (string)subjectDnValues[0]; 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SmartGlass/Connection/ConnectionInfo.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Connection 2 | { 3 | /// 4 | /// Connection info. 5 | /// 6 | internal class ConnectionInfo 7 | { 8 | /// 9 | /// Device. 10 | /// 11 | /// The device. 12 | public Device Device { get; set; } 13 | /// 14 | /// Participant Id. 15 | /// 16 | /// The participant identifier. 17 | public uint ParticipantId { get; set; } 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SmartGlass/ConsoleConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass 5 | { 6 | public record ConsoleConfiguration : ISerializable 7 | { 8 | public uint LiveTVProvider { get; private set; } 9 | public uint MajorVersion { get; private set; } 10 | public uint MinorVersion { get; private set; } 11 | public uint BuildNumber { get; private set; } 12 | public string Locale { get; private set; } 13 | 14 | void ISerializable.Deserialize(EndianReader reader) 15 | { 16 | LiveTVProvider = reader.ReadUInt32BE(); 17 | MajorVersion = reader.ReadUInt32BE(); 18 | MinorVersion = reader.ReadUInt32BE(); 19 | BuildNumber = reader.ReadUInt32BE(); 20 | Locale = reader.ReadUInt16BEPrefixedString(); 21 | } 22 | 23 | void ISerializable.Serialize(EndianWriter writer) 24 | { 25 | throw new NotImplementedException(); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /SmartGlass/ConsoleStatus.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | 3 | namespace SmartGlass 4 | { 5 | public record ConsoleStatus 6 | { 7 | public ConsoleConfiguration Configuration { get; internal set; } 8 | public IReadOnlyCollection ActiveTitles { get; internal set; } 9 | } 10 | } -------------------------------------------------------------------------------- /SmartGlass/ConsoleStatusChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | public class ConsoleStatusChangedEventArgs : EventArgs 6 | { 7 | private readonly ConsoleStatus _status; 8 | public ConsoleStatus Status => _status; 9 | 10 | public ConsoleStatusChangedEventArgs(ConsoleStatus status) 11 | { 12 | _status = status; 13 | } 14 | } 15 | } -------------------------------------------------------------------------------- /SmartGlass/Enums/ActiveSurfaceType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Active surface type. 5 | /// 6 | enum ActiveSurfaceType 7 | { 8 | Blank, 9 | Direct, 10 | Html, 11 | TitleTextEntry 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SmartGlass/Enums/ActiveTitleLocation.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Active title location. 5 | /// 6 | public enum ActiveTitleLocation : ushort 7 | { 8 | Full, 9 | Fill, 10 | Snapped, 11 | StartView, 12 | SystemUI, 13 | Default 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SmartGlass/Enums/DeviceCapabilities.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Device capabilities. 5 | /// 6 | enum DeviceCapabilities : long 7 | { 8 | SupportsAll = -1, 9 | SupportsNone = 0, 10 | SupportsStreaming = 1, 11 | SupportsAudio = 2, 12 | SupportsAccelerometer = 4, 13 | SupportsCompass = 8, 14 | SupportsGyrometer = 16, 15 | SupportsInclinometer = 32, 16 | SupportsOrientation = 64 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Enums/DeviceFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Device flags contained in PresenceResponse. 7 | /// 8 | [Flags] 9 | public enum DeviceFlags 10 | { 11 | None, 12 | AllowConsoleUsers = 1, 13 | AllowAuthenticatedUsers = 2, 14 | AllowAnonymousUsers = 4, 15 | CertificateRequestPending = 8 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SmartGlass/Enums/DeviceState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Device state. 7 | /// 8 | public enum DeviceState 9 | { 10 | Available, 11 | Unavailable 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SmartGlass/Enums/DeviceType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Device type. 5 | /// 6 | public enum DeviceType 7 | { 8 | Unknown, 9 | XboxOne, 10 | Xbox360, 11 | WindowsDesktop, 12 | WindowsStore, 13 | WindowsPhone, 14 | iPhone, 15 | iPad, 16 | Android 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Enums/DisconnectReason.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Disconnect reason. 5 | /// 6 | enum DisconnectReason 7 | { 8 | Unspecified, 9 | Error, 10 | PowerOff, 11 | Maintenance, 12 | AppClose, 13 | SignOut, 14 | Reboot, 15 | Disabled, 16 | LowPower 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Enums/GamepadButtons.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Gamepad buttons. 5 | /// Used by InputChannel. 6 | /// 7 | public enum GamepadButtons : ushort 8 | { 9 | Clear = 0x0000, 10 | Nexus = 0x0002, 11 | Menu = 0x0004, 12 | View = 0x0008, 13 | A = 0x0010, 14 | B = 0x0020, 15 | X = 0x0040, 16 | Y = 0x0080, 17 | DPadUp = 0x0100, 18 | DPadDown = 0x0200, 19 | DPadLeft = 0x0400, 20 | DPadRight = 0x0800, 21 | LeftShoulder = 0x1000, 22 | RightShoulder = 0x2000, 23 | LeftThumbStick = 0x4000, 24 | RightThumbStick = 0x8000 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartGlass/Enums/MediaControlCommands.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Media control commands. 7 | /// Used by MediaChannel. 8 | /// 9 | [Flags] 10 | public enum MediaControlCommands : uint 11 | { 12 | None = 0x0000, 13 | Play = 0x0002, 14 | Pause = 0x0004, 15 | PlayPauseToggle = 0x0008, 16 | Stop = 0x0010, 17 | Record = 0x0020, 18 | NextTrack = 0x0040, 19 | PreviousTrack = 0x0080, 20 | FastForward = 0x0100, 21 | Rewind = 0x0200, 22 | ChannelUp = 0x0400, 23 | ChannelDown = 0x0800, 24 | Back = 0x1000, 25 | View = 0x2000, 26 | Menu = 0x4000, 27 | Seek = 0x8000, 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /SmartGlass/Enums/MediaPlaybackStatus.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Media playback status. 5 | /// Used by MediaChannel. 6 | /// 7 | public enum MediaPlaybackStatus : uint 8 | { 9 | Closed = 0x00, 10 | Changing = 0x01, 11 | Stopped = 0x02, 12 | Playing = 0x03, 13 | Paused = 0x04 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SmartGlass/Enums/MediaSoundLevel.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Media sound level. 5 | /// Used by MediaChannel. 6 | /// 7 | public enum MediaSoundLevel : ushort 8 | { 9 | Muted = 0x00, 10 | Low = 0x01, 11 | Full = 0x02 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SmartGlass/Enums/MediaType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | /// 4 | /// Media type. 5 | /// Used by MediaChannel. 6 | /// 7 | public enum MediaType : ushort 8 | { 9 | NoMedia = 0x00, 10 | Music = 0x01, 11 | Video = 0x02, 12 | Image = 0x03, 13 | Conversation = 0x04, 14 | Game = 0x05 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/Enums/PairedIdentityState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass 3 | { 4 | /// 5 | /// Paired identity state. 6 | /// 7 | public enum PairedIdentityState : ushort 8 | { 9 | NotPaired, 10 | Paired 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SmartGlass/Enums/PublicKeyType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Public key type. 7 | /// Used in CryptoContext. 8 | /// 9 | public enum PublicKeyType : ushort 10 | { 11 | EC_DH_P256, 12 | EC_DH_P384, 13 | EC_DH_P521 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SmartGlass/Enums/TextOption.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | [Flags] 6 | public enum TextOption 7 | { 8 | Default = 0x0000, 9 | AcceptsReturn = 0x0001, 10 | Password = 0x0002, 11 | MultiLine = 0x0004, 12 | SpellCheckEnabled = 0x0008, 13 | PredictionEnabled = 0x0010, 14 | RTL = 0x0020, 15 | Dismiss = 0x4000 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /SmartGlass/Enums/TextResult.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Text result. 7 | /// Used by TextChannel. 8 | /// 9 | public enum TextResult 10 | { 11 | Cancel, 12 | Accept 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SmartGlass/Enums/TouchAction.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Touch action. 7 | /// Used by InputChannel. 8 | /// 9 | public enum TouchAction : ushort 10 | { 11 | Down = 1, 12 | Move, 13 | Up, 14 | Cancel 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /SmartGlass/GamepadState.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | public struct GamepadState 4 | { 5 | public GamepadButtons Buttons; 6 | 7 | public float LeftTrigger; 8 | public float RightTrigger; 9 | public float LeftThumbstickX; 10 | public float LeftThumbstickY; 11 | public float RightThumbstickX; 12 | public float RightThumbstickY; 13 | 14 | public long Timestamp; 15 | } 16 | } -------------------------------------------------------------------------------- /SmartGlass/GlobalConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System.Net; 2 | 3 | namespace SmartGlass 4 | { 5 | /// 6 | /// Storage of global configuration values, used by the whole SmartGlass library 7 | /// 8 | public static class GlobalConfiguration 9 | { 10 | /// 11 | /// Set bind address before any network interaction happens in case 12 | /// binding to a specific interface/address is required 13 | /// 14 | /// Defaults to IPAddress.Any 15 | /// 16 | /// Local address to bind socket to 17 | public static IPAddress BindAddress { get; set; } = IPAddress.Any; 18 | } 19 | } -------------------------------------------------------------------------------- /SmartGlass/IRCommandState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SmartGlass { 6 | 7 | public struct IRCommandState { 8 | public string cmd; 9 | public string stump_device; 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/IRDevice.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Text; 5 | 6 | namespace SmartGlass { 7 | public class IRDevice { 8 | public string device_id; 9 | public string device_type; 10 | public string device_brand; 11 | public string device_model; 12 | [JsonProperty("buttons")] 13 | public Dictionary button_to_standard_bind; 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SmartGlass/Json/IPAddressConverter.cs: -------------------------------------------------------------------------------- 1 | using Newtonsoft.Json; 2 | using System; 3 | using System.Collections.Generic; 4 | using System.Net; 5 | using System.Text; 6 | 7 | namespace SmartGlass.Json 8 | { 9 | class IPAddressConverter : JsonConverter 10 | { 11 | public override bool CanConvert(Type objectType) 12 | { 13 | return (objectType == typeof(IPAddress)); 14 | } 15 | 16 | public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) 17 | { 18 | writer.WriteValue(value.ToString()); 19 | } 20 | 21 | public override object ReadJson(JsonReader reader, Type objectType, object existingValue, JsonSerializer serializer) 22 | { 23 | return IPAddress.Parse((string)reader.Value); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartGlass/MediaCommandState.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass 2 | { 3 | public struct MediaCommandState 4 | { 5 | public uint TitleId; 6 | public MediaControlCommands Command; 7 | public uint SeekPosition; 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartGlass/MediaMetadata.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass 5 | { 6 | internal class MediaMetadata : ISerializable 7 | { 8 | public string Name { get; set; } 9 | public string Value { get; set; } 10 | 11 | public void Deserialize(EndianReader reader) 12 | { 13 | Name = reader.ReadUInt16BEPrefixedString(); 14 | Value = reader.ReadUInt16BEPrefixedString(); 15 | } 16 | 17 | public void Serialize(EndianWriter writer) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | } 22 | } 23 | -------------------------------------------------------------------------------- /SmartGlass/MediaState.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Collections.Generic; 3 | using System.Text; 4 | 5 | namespace SmartGlass 6 | { 7 | 8 | public class MediaState 9 | { 10 | public MediaState() 11 | { 12 | AsOf = DateTime.Now; 13 | } 14 | public DateTime AsOf { get; internal set; } 15 | public uint TitleId { get; internal set; } 16 | public string AumId { get; internal set; } 17 | public string AssetId { get; internal set; } 18 | public MediaType MediaType { get; internal set; } 19 | public MediaSoundLevel SoundLevel { get; internal set; } 20 | public MediaControlCommands EnabledCommands { get; internal set; } 21 | public MediaPlaybackStatus PlaybackStatus { get; internal set; } 22 | public float PlaybackRate { get; internal set; } 23 | public TimeSpan Position { get; internal set; } 24 | public TimeSpan MediaStart { get; internal set; } 25 | public TimeSpan MediaEnd { get; internal set; } 26 | public TimeSpan MinimumSeek { get; internal set; } 27 | public TimeSpan MaximumSeek { get; internal set; } 28 | 29 | public IReadOnlyDictionary Metadata { get; internal set; } 30 | 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartGlass/MediaStateChangedEventArgs.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | public class MediaStateChangedEventArgs : EventArgs 6 | { 7 | public MediaState State { get; private set; } 8 | 9 | public MediaStateChangedEventArgs(MediaState state) 10 | { 11 | State = state; 12 | } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Connection/ConnectResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Connection 5 | { 6 | /// 7 | /// Connect response message. 8 | /// Sent from console to client on successful connection. 9 | /// 10 | [MessageType(MessageType.ConnectResponse)] 11 | internal class ConnectResponseMessage : ProtectedMessageBase 12 | { 13 | public ConnectionResult Result { get; set; } 14 | public PairedIdentityState PairingState { get; set; } 15 | public uint ParticipantId { get; set; } 16 | 17 | protected override void DeserializePayload(EndianReader reader) 18 | { 19 | InitVector = reader.ReadBytes(16); 20 | } 21 | 22 | protected override void DeserializeProtectedPayload(EndianReader reader) 23 | { 24 | Result = (ConnectionResult)reader.ReadUInt16BE(); 25 | PairingState = (PairedIdentityState)reader.ReadUInt16BE(); 26 | ParticipantId = reader.ReadUInt32BE(); 27 | } 28 | 29 | protected override void SerializePayload(EndianWriter writer) 30 | { 31 | throw new NotImplementedException(); 32 | } 33 | 34 | protected override void SerializeProtectedPayload(EndianWriter writer) 35 | { 36 | throw new NotImplementedException(); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Connection/ConnectionMessageHeader.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Connection 4 | { 5 | /// 6 | /// Message header used by ConnectRequest and ConnectResponse. 7 | /// 8 | internal class ConnectionMessageHeader : IProtectedMessageHeader 9 | { 10 | public MessageType Type { get; set; } 11 | 12 | public ushort PayloadLength { get; set; } 13 | 14 | public ushort ProtectedPayloadLength { get; set; } 15 | 16 | public ushort Version { get; set; } = 2; 17 | 18 | public void Deserialize(EndianReader reader) 19 | { 20 | Type = (MessageType)reader.ReadUInt16BE(); 21 | PayloadLength = reader.ReadUInt16BE(); 22 | ProtectedPayloadLength = reader.ReadUInt16BE(); 23 | Version = reader.ReadUInt16BE(); 24 | } 25 | 26 | public void Serialize(EndianWriter writer) 27 | { 28 | writer.WriteBE((ushort)Type); 29 | writer.WriteBE(PayloadLength); 30 | writer.WriteBE(ProtectedPayloadLength); 31 | writer.WriteBE(Version); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Connection/ConnectionResult.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging.Connection 2 | { 3 | /// 4 | /// Connection result returned in ConnectResponse. 5 | /// 6 | enum ConnectionResult : ushort 7 | { 8 | Success, 9 | Pending, 10 | FailureUnknown, 11 | FailureAnonymousConnectionsDisabled, 12 | FailureDeviceLimitExceeded, 13 | FailureSmartGlassDisabled, 14 | FailureUserAuthFailed, 15 | FailureUserSignInFailed, 16 | FailureUserSignInTimeOut, 17 | FailureUserSignInRequired 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Discovery/DiscoveryMessageHeader.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Discovery 4 | { 5 | /// 6 | /// Discovery message header, used by PresenceRequest and PresenceResponse. 7 | /// 8 | internal class DiscoveryMessageHeader : IMessageHeader 9 | { 10 | public MessageType Type { get; set; } 11 | 12 | public ushort PayloadLength { get; set; } 13 | 14 | public ushort Version { get; set; } 15 | 16 | public void Deserialize(EndianReader reader) 17 | { 18 | Type = (MessageType)reader.ReadUInt16BE(); 19 | PayloadLength = reader.ReadUInt16BE(); 20 | Version = reader.ReadUInt16BE(); 21 | } 22 | 23 | public void Serialize(EndianWriter writer) 24 | { 25 | writer.WriteBE((ushort)Type); 26 | writer.WriteBE(PayloadLength); 27 | writer.WriteBE(Version); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Discovery/PresenceRequestMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Discovery 4 | { 5 | /// 6 | /// Presence request message. 7 | /// Send from client to multicast / broadcast. 8 | /// Active consoles will respond with PresenceResponse. 9 | /// 10 | [MessageType(MessageType.PresenceRequest)] 11 | internal class PresenceRequestMessage : MessageBase 12 | { 13 | public uint Flags { get; set; } 14 | public DeviceType DeviceType { get; set; } = DeviceType.WindowsStore; 15 | public ushort MinVersion { get; set; } = 0; 16 | public ushort MaxVersion { get; set; } = 2; 17 | 18 | protected override void DeserializePayload(EndianReader reader) 19 | { 20 | Flags = reader.ReadUInt32BE(); 21 | DeviceType = (DeviceType)reader.ReadUInt16BE(); 22 | MinVersion = reader.ReadUInt16BE(); 23 | MaxVersion = reader.ReadUInt16BE(); 24 | } 25 | 26 | protected override void SerializePayload(EndianWriter writer) 27 | { 28 | writer.WriteBE(Flags); 29 | writer.WriteBE((ushort)DeviceType); 30 | writer.WriteBE(MinVersion); 31 | writer.WriteBE(MaxVersion); 32 | } 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Discovery/PresenceResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Connection; 3 | using SmartGlass.Common; 4 | using Org.BouncyCastle.X509; 5 | 6 | namespace SmartGlass.Messaging.Discovery 7 | { 8 | /// 9 | /// Presence response message. 10 | /// Sent from console to client as response to PresenceRequest. 11 | /// 12 | [MessageType(MessageType.PresenceResponse)] 13 | internal class PresenceResponseMessage : MessageBase 14 | { 15 | public DeviceFlags Flags { get; set; } 16 | public DeviceType DeviceType { get; set; } 17 | public string Name { get; set; } 18 | public Guid HardwareId { get; set; } 19 | public uint LastError { get; set; } 20 | public X509Certificate Certificate { get; set; } 21 | 22 | protected override void DeserializePayload(EndianReader reader) 23 | { 24 | Flags = (DeviceFlags)reader.ReadUInt32BE(); 25 | DeviceType = (DeviceType)reader.ReadUInt16BE(); 26 | Name = reader.ReadUInt16BEPrefixedString(); 27 | HardwareId = Guid.Parse(reader.ReadUInt16BEPrefixedString()); 28 | LastError = reader.ReadUInt32BE(); 29 | Certificate = CryptoExtensions 30 | .DeserializeCertificateAsn(reader.ReadUInt16BEPrefixedBlob()); 31 | } 32 | 33 | protected override void SerializePayload(EndianWriter writer) 34 | { 35 | throw new NotImplementedException(); 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/ICryptoMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Connection; 2 | 3 | namespace SmartGlass.Messaging 4 | { 5 | /// 6 | /// Crypto message. 7 | /// 8 | interface ICryptoMessage 9 | { 10 | CryptoContext Crypto { get; set; } 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/IMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using SmartGlass.Common; 4 | 5 | namespace SmartGlass.Messaging 6 | { 7 | /// 8 | /// Base interface all SmartGlass messages derive from. 9 | /// 10 | interface IMessage : IMessage where THeader : IMessageHeader 11 | { 12 | new THeader Header { get; set; } 13 | } 14 | 15 | interface IMessage : ISerializable 16 | { 17 | DateTime ClientReceivedTimestamp { get; set; } 18 | IPEndPoint Origin { get; set; } 19 | IMessageHeader Header { get; } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/IMessageHeader.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging 4 | { 5 | /// 6 | /// Message header. 7 | /// 8 | interface IMessageHeader : ISerializable 9 | { 10 | MessageType Type { get; set; } 11 | ushort PayloadLength { get; set; } 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/IProtectedMessageHeader.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging 2 | { 3 | /// 4 | /// Protected message header. 5 | /// 6 | interface IProtectedMessageHeader : IMessageHeader 7 | { 8 | ushort ProtectedPayloadLength { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/MessageBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.Net; 3 | using SmartGlass.Common; 4 | using Newtonsoft.Json; 5 | 6 | namespace SmartGlass.Messaging 7 | { 8 | /// 9 | /// Message base. 10 | /// 11 | abstract class MessageBase : IMessage 12 | where THeader : IMessageHeader, new() 13 | { 14 | public string TypeName => GetType().Name; 15 | 16 | public THeader Header { get; set; } 17 | 18 | IMessageHeader IMessage.Header => Header; 19 | 20 | [JsonIgnore] 21 | public IPEndPoint Origin { get; set; } 22 | 23 | public DateTime ClientReceivedTimestamp { get; set; } 24 | 25 | public MessageBase() 26 | { 27 | Header = new THeader() 28 | { 29 | Type = MessageTypeAttribute.GetMessageTypeForType(GetType()) 30 | }; 31 | } 32 | 33 | protected abstract void SerializePayload(EndianWriter writer); 34 | 35 | protected abstract void DeserializePayload(EndianReader reader); 36 | 37 | public virtual void Serialize(EndianWriter writer) 38 | { 39 | var payloadWriter = new EndianWriter(); 40 | SerializePayload(payloadWriter); 41 | 42 | var payload = payloadWriter.ToBytes(); 43 | Header.PayloadLength = (ushort)payload.Length; 44 | 45 | Header.Serialize(writer); 46 | writer.Write(payload); 47 | } 48 | 49 | public virtual void Deserialize(EndianReader reader) 50 | { 51 | Header.Deserialize(reader); 52 | DeserializePayload(reader.CreateChild(Header.PayloadLength)); 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/MessageType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging 2 | { 3 | /// 4 | /// Message type. 5 | /// 6 | enum MessageType : ushort 7 | { 8 | SessionMessage = 0xD00D, 9 | 10 | ConnectRequest = 0xCC00, 11 | ConnectResponse = 0xCC01, 12 | 13 | PresenceRequest = 0xDD00, 14 | PresenceResponse = 0xDD01, 15 | 16 | PowerOn = 0xDD02 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/MessageTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class MessageTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(MessageType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static MessageType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public MessageType MessageType { get; private set; } 26 | 27 | public MessageTypeAttribute(MessageType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Power/PowerOnMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Power 4 | { 5 | /// 6 | /// Power on message. 7 | /// 8 | [MessageType(MessageType.PowerOn)] 9 | internal class PowerOnMessage : MessageBase 10 | { 11 | /// 12 | /// Live ID of console to be powered on. 13 | /// 14 | /// The live identifier. 15 | public string LiveId { get; set; } 16 | 17 | protected override void DeserializePayload(EndianReader reader) 18 | { 19 | LiveId = reader.ReadUInt16BEPrefixedString(); 20 | } 21 | 22 | protected override void SerializePayload(EndianWriter writer) 23 | { 24 | writer.WriteUInt16BEPrefixed(LiveId); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Power/PowerOnMessageHeader.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Power 4 | { 5 | /// 6 | /// Power on message header. 7 | /// 8 | internal class PowerOnMessageHeader : IMessageHeader 9 | { 10 | public MessageType Type { get; set; } 11 | 12 | public ushort PayloadLength { get; set; } 13 | 14 | public ushort Version { get; set; } 15 | 16 | public void Deserialize(EndianReader reader) 17 | { 18 | Type = (MessageType)reader.ReadUInt16BE(); 19 | PayloadLength = reader.ReadUInt16BE(); 20 | Version = reader.ReadUInt16BE(); 21 | } 22 | 23 | public void Serialize(EndianWriter writer) 24 | { 25 | writer.WriteBE((ushort)Type); 26 | writer.WriteBE(PayloadLength); 27 | writer.WriteBE(Version); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/JsonFragmentManager.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Messaging.Session; 2 | using SmartGlass.Messaging.Session.Messages; 3 | using System; 4 | using System.Collections.Concurrent; 5 | using System.Collections.Generic; 6 | using System.Linq; 7 | using System.Text; 8 | 9 | namespace SmartGlass.Messaging.Session { 10 | public class JsonMessageFragment { 11 | public int datagram_size; 12 | public int datagram_id; 13 | public int fragment_offset; 14 | public int fragment_length; 15 | public string fragment_data; 16 | 17 | } 18 | class JsonFragmentManager { 19 | public ConcurrentDictionary> datagram_id_to_message_fragments = new ConcurrentDictionary>(); 20 | public JsonMessage HandleMessage(JsonMessageFragment msg) { 21 | var list = datagram_id_to_message_fragments.GetOrAdd(msg.datagram_id, (_) => new List()); 22 | lock (list) { 23 | if (list.Any(a => a.fragment_offset == msg.fragment_offset)) 24 | return null; 25 | list.Add(msg); 26 | if (list.Count == 1)//first cant be done 27 | return null; 28 | 29 | if (list.Sum(a => a.fragment_length) != msg.datagram_size)//not yet done 30 | return null; 31 | var data = String.Join("", list.OrderBy(a => a.fragment_offset).Select(a => a.fragment_data)); 32 | data = Encoding.UTF8.GetString(Convert.FromBase64String(data)); 33 | datagram_id_to_message_fragments.TryRemove(msg.datagram_id, out _); 34 | return new JsonMessage { Json = data}; 35 | 36 | } 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/AccelerometerMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Accelerometer)] 7 | internal record AccelerometerMessage : SessionMessageBase 8 | { 9 | public ulong Timestamp { get; set; } 10 | public float AccelerationX { get; set; } 11 | public float AccelerationY { get; set; } 12 | public float AccelerationZ { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | Timestamp = reader.ReadUInt64BE(); 17 | AccelerationX = reader.ReadInt32BE(); 18 | AccelerationY = reader.ReadInt32BE(); 19 | AccelerationZ = reader.ReadInt32BE(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(Timestamp); 25 | writer.WriteBE(AccelerationX); 26 | writer.WriteBE(AccelerationY); 27 | writer.WriteBE(AccelerationZ); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/AckMessage.cs: -------------------------------------------------------------------------------- 1 | using System.Collections.Generic; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Ack)] 7 | internal record AckMessage : SessionMessageBase 8 | { 9 | public uint LowWatermark { get; set; } 10 | public HashSet ProcessedList { get; set; } 11 | public HashSet RejectedList { get; set; } 12 | 13 | public override void Deserialize(EndianReader reader) 14 | { 15 | LowWatermark = reader.ReadUInt32BE(); 16 | ProcessedList = new HashSet(reader.ReadUInt32BEArray()); 17 | RejectedList = new HashSet(reader.ReadUInt32BEArray()); 18 | } 19 | 20 | public override void Serialize(EndianWriter writer) 21 | { 22 | writer.WriteBE(LowWatermark); 23 | writer.WriteBE(ProcessedList); 24 | writer.WriteBE(RejectedList); 25 | } 26 | } 27 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/ActiveSurfaceChangeMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.ActiveSurfaceChange)] 7 | internal record ActiveSurfaceChangeMessage : SessionMessageBase 8 | { 9 | public ActiveSurfaceType SurfaceType { get; set; } 10 | 11 | public StreamerConfiguration StreamerConfiguration { get; set; } 12 | 13 | public override void Deserialize(EndianReader reader) 14 | { 15 | SurfaceType = (ActiveSurfaceType)reader.ReadUInt16BE(); 16 | 17 | StreamerConfiguration = new StreamerConfiguration(); 18 | StreamerConfiguration.Deserialize(reader); 19 | } 20 | 21 | public override void Serialize(EndianWriter writer) 22 | { 23 | throw new NotSupportedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/AuxiliaryStreamConnectionInfo.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | internal record AuxiliaryStreamConnectionInfo : ISerializable 7 | { 8 | public byte[] CryptoKey { get; set; } 9 | public byte[] ServerInitVector { get; set; } 10 | public byte[] ClientInitVector { get; set; } 11 | public byte[] SignHash { get; set; } 12 | 13 | public AuxiliaryStreamEndpoint[] Endpoints { get; set; } 14 | 15 | public void Deserialize(EndianReader reader) 16 | { 17 | CryptoKey = reader.ReadUInt16BEPrefixedBlob(); 18 | ServerInitVector = reader.ReadUInt16BEPrefixedBlob(); 19 | ClientInitVector = reader.ReadUInt16BEPrefixedBlob(); 20 | SignHash = reader.ReadUInt16BEPrefixedBlob(); 21 | 22 | Endpoints = reader.ReadUInt16BEPrefixedArray(); 23 | } 24 | 25 | public void Serialize(EndianWriter writer) 26 | { 27 | throw new NotSupportedException(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/AuxiliaryStreamEndpoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | internal record AuxiliaryStreamEndpoint : ISerializable 7 | { 8 | public string Host { get; set; } 9 | public string Service { get; set; } 10 | 11 | public void Deserialize(EndianReader reader) 12 | { 13 | Host = reader.ReadUInt16BEPrefixedString(); 14 | Service = reader.ReadUInt16BEPrefixedString(); 15 | } 16 | 17 | public void Serialize(EndianWriter writer) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/AuxiliaryStreamMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session.Messages 4 | { 5 | [SessionMessageType(SessionMessageType.AuxiliaryStream)] 6 | internal record AuxiliaryStreamMessage : SessionMessageBase 7 | { 8 | public AuxiliaryStreamConnectionInfo ConnectionInfo { get; set; } 9 | 10 | public override void Deserialize(EndianReader reader) 11 | { 12 | if (reader.ReadByte() == 1) 13 | { 14 | ConnectionInfo = new AuxiliaryStreamConnectionInfo(); 15 | ConnectionInfo.Deserialize(reader); 16 | } 17 | } 18 | 19 | public override void Serialize(EndianWriter writer) 20 | { 21 | writer.Write((byte)0); 22 | } 23 | } 24 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/CompassMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Compass)] 7 | internal record CompassMessage : SessionMessageBase 8 | { 9 | public ulong Timestamp { get; set; } 10 | public float MagneticNorth { get; set; } 11 | public float TrueNorth { get; set; } 12 | 13 | public override void Deserialize(EndianReader reader) 14 | { 15 | Timestamp = reader.ReadUInt64BE(); 16 | MagneticNorth = reader.ReadInt32BE(); 17 | TrueNorth = reader.ReadInt32BE(); 18 | } 19 | 20 | public override void Serialize(EndianWriter writer) 21 | { 22 | writer.WriteBE(Timestamp); 23 | writer.WriteBE(MagneticNorth); 24 | writer.WriteBE(TrueNorth); 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/ConsoleStatusMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.ConsoleStatus)] 7 | internal record ConsoleStatusMessage : SessionMessageBase 8 | { 9 | public ConsoleConfiguration Configuration { get; set; } 10 | public ActiveTitle[] ActiveTitles { get; set; } 11 | 12 | public override void Deserialize(EndianReader reader) 13 | { 14 | Configuration = new ConsoleConfiguration(); 15 | ((ISerializable)Configuration).Deserialize(reader); 16 | 17 | ActiveTitles = reader.ReadUInt16BEPrefixedArray(); 18 | } 19 | 20 | public override void Serialize(EndianWriter writer) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/DisconnectMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session.Messages 4 | { 5 | [SessionMessageType(SessionMessageType.Disconnect)] 6 | internal record DisconnectMessage : SessionMessageBase 7 | { 8 | public DisconnectReason Reason { get; set; } 9 | public uint ErrorCode { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | throw new System.NotImplementedException(); 14 | } 15 | 16 | public override void Serialize(EndianWriter writer) 17 | { 18 | writer.WriteBE((uint)Reason); 19 | writer.WriteBE(ErrorCode); 20 | } 21 | } 22 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/FragmentMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session.Messages 4 | { 5 | // Determined by IsFragment-flag in SessionFragmentMessageHeader 6 | // Data content depends on SessionMessageType 7 | internal record FragmentMessage : SessionMessageBase 8 | { 9 | public uint SequenceBegin { get; set; } 10 | public uint SequenceEnd { get; set; } 11 | // Data: Plaintext SessionFragmentMessage payload 12 | public byte[] Data { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | SequenceBegin = reader.ReadUInt32BE(); 17 | SequenceEnd = reader.ReadUInt32BE(); 18 | Data = reader.ReadUInt16BEPrefixedBlob(); 19 | } 20 | 21 | public override void Serialize(EndianWriter writer) 22 | { 23 | writer.WriteBE(SequenceBegin); 24 | writer.WriteBE(SequenceEnd); 25 | writer.WriteBE((ushort)Data.Length); 26 | writer.Write(Data); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/GameDvrRecordMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.GameDvrRecord)] 7 | internal record GameDvrRecordMessage : SessionMessageBase 8 | { 9 | public int StartTimeDelta { get; set; } 10 | public int EndTimeDelta { get; set; } 11 | 12 | public GameDvrRecordMessage() 13 | { 14 | Header.RequestAcknowledge = true; 15 | } 16 | 17 | public override void Deserialize(EndianReader reader) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(StartTimeDelta); 25 | writer.WriteBE(EndTimeDelta); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/GamepadMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Gamepad)] 7 | internal record GamepadMessage : SessionMessageBase 8 | { 9 | public GamepadState State { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | throw new NotImplementedException(); 14 | } 15 | 16 | public override void Serialize(EndianWriter writer) 17 | { 18 | writer.WriteBE(State.Timestamp); 19 | 20 | writer.WriteBE((ushort)State.Buttons); 21 | 22 | writer.WriteBE(State.LeftTrigger); 23 | writer.WriteBE(State.RightTrigger); 24 | 25 | writer.WriteBE(State.LeftThumbstickX); 26 | writer.WriteBE(State.LeftThumbstickY); 27 | 28 | writer.WriteBE(State.RightThumbstickX); 29 | writer.WriteBE(State.RightThumbstickY); 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/GyrometerMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Gyrometer)] 7 | internal record GyrometerMessage : SessionMessageBase 8 | { 9 | public ulong Timestamp { get; set; } 10 | public float AngularVelocityX { get; set; } 11 | public float AngularVelocityY { get; set; } 12 | public float AngularVelocityZ { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | Timestamp = reader.ReadUInt64BE(); 17 | AngularVelocityX = reader.ReadInt32BE(); 18 | AngularVelocityY = reader.ReadInt32BE(); 19 | AngularVelocityZ = reader.ReadInt32BE(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(Timestamp); 25 | writer.WriteBE(AngularVelocityX); 26 | writer.WriteBE(AngularVelocityY); 27 | writer.WriteBE(AngularVelocityZ); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/InclinometerMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Inclinometer)] 7 | internal record InclinometerMessage : SessionMessageBase 8 | { 9 | public ulong Timestamp { get; set; } 10 | public float Pitch { get; set; } 11 | public float Roll { get; set; } 12 | public float Yaw { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | Timestamp = reader.ReadUInt64BE(); 17 | Pitch = reader.ReadInt32BE(); 18 | Roll = reader.ReadInt32BE(); 19 | Yaw = reader.ReadInt32BE(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(Timestamp); 25 | writer.WriteBE(Pitch); 26 | writer.WriteBE(Roll); 27 | writer.WriteBE(Yaw); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/JsonMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session.Messages 4 | { 5 | [SessionMessageType(SessionMessageType.Json)] 6 | internal record JsonMessage : SessionMessageBase 7 | { 8 | public JsonMessage() 9 | { 10 | Header.RequestAcknowledge = true; 11 | } 12 | 13 | public string Json { get; set; } 14 | 15 | public override void Deserialize(EndianReader reader) 16 | { 17 | Json = reader.ReadUInt16BEPrefixedString(); 18 | } 19 | 20 | public override void Serialize(EndianWriter writer) 21 | { 22 | writer.WriteUInt16BEPrefixed(Json); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/MediaCommandMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.MediaCommand)] 7 | internal record MediaCommandMessage : SessionMessageBase 8 | { 9 | private static ulong requestId = 0; 10 | 11 | public MediaCommandState State { get; set; } 12 | 13 | public override void Deserialize(EndianReader reader) 14 | { 15 | throw new NotImplementedException(); 16 | } 17 | 18 | public override void Serialize(EndianWriter writer) 19 | { 20 | var id = requestId++; 21 | 22 | writer.WriteBE(id); 23 | writer.WriteBE(State.TitleId); 24 | writer.WriteBE((uint)State.Command); 25 | 26 | if (State.Command == MediaControlCommands.Seek) 27 | { 28 | writer.WriteBE(State.SeekPosition); 29 | } 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/MediaCommandResultMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.MediaCommandResult)] 7 | internal record MediaCommandResultMessage : SessionMessageBase 8 | { 9 | public ulong RequestId { get; set; } 10 | public uint Result { get; set; } 11 | 12 | public override void Deserialize(EndianReader reader) 13 | { 14 | RequestId = reader.ReadUInt64BE(); 15 | Result = reader.ReadUInt32BE(); 16 | } 17 | 18 | public override void Serialize(EndianWriter writer) 19 | { 20 | throw new NotSupportedException(); 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/MediaControllerRemovedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.MediaControllerRemoved)] 7 | internal record MediaControllerRemovedMessage : SessionMessageBase 8 | { 9 | public uint TitleId { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | TitleId = reader.ReadUInt32BE(); 14 | } 15 | 16 | public override void Serialize(EndianWriter writer) 17 | { 18 | writer.WriteBE(TitleId); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/OrientationMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Orientation)] 7 | internal record OrientationMessage : SessionMessageBase 8 | { 9 | public ulong Timestamp { get; set; } 10 | public float RotationMatrixValue { get; set; } 11 | public float RotationW { get; set; } 12 | public float RotationX { get; set; } 13 | public float RotationY { get; set; } 14 | public float RotationZ { get; set; } 15 | 16 | public override void Deserialize(EndianReader reader) 17 | { 18 | Timestamp = reader.ReadUInt64BE(); 19 | RotationMatrixValue = reader.ReadInt32BE(); 20 | RotationW = reader.ReadInt32BE(); 21 | RotationX = reader.ReadInt32BE(); 22 | RotationY = reader.ReadInt32BE(); 23 | RotationZ = reader.ReadInt32BE(); 24 | } 25 | 26 | public override void Serialize(EndianWriter writer) 27 | { 28 | writer.WriteBE(Timestamp); 29 | writer.WriteBE(RotationMatrixValue); 30 | writer.WriteBE(RotationW); 31 | writer.WriteBE(RotationX); 32 | writer.WriteBE(RotationY); 33 | writer.WriteBE(RotationZ); 34 | } 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/PairedIdentityStateChangedMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.PairedIdentityStateChanged)] 7 | internal record PairedIdentityStateChangedMessage : SessionMessageBase 8 | { 9 | public PairedIdentityState State { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | State = (PairedIdentityState)reader.ReadUInt16BE(); 14 | } 15 | 16 | public override void Serialize(EndianWriter writer) 17 | { 18 | throw new NotSupportedException(); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/PowerOffMessage.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session.Messages 4 | { 5 | [SessionMessageType(SessionMessageType.PowerOff)] 6 | internal record PowerOffMessage : SessionMessageBase 7 | { 8 | public string LiveId { get; set; } 9 | 10 | public override void Deserialize(EndianReader reader) 11 | { 12 | throw new System.NotImplementedException(); 13 | } 14 | 15 | public override void Serialize(EndianWriter writer) 16 | { 17 | writer.WriteUInt16BEPrefixed(LiveId); 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/StartChannelResponseMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.StartChannelResponse)] 7 | internal record StartChannelResponseMessage : SessionMessageBase 8 | { 9 | public uint ChannelRequestId { get; set; } 10 | public ulong ChannelId { get; set; } 11 | public int Result { get; set; } 12 | 13 | public override void Deserialize(EndianReader reader) 14 | { 15 | ChannelRequestId = reader.ReadUInt32BE(); 16 | ChannelId = reader.ReadUInt64BE(); 17 | Result = reader.ReadInt32BE(); 18 | } 19 | 20 | public override void Serialize(EndianWriter writer) 21 | { 22 | throw new NotImplementedException(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/StopChannelMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.StopChannel)] 7 | internal record StopChannelMessage : SessionMessageBase 8 | { 9 | public StopChannelMessage() 10 | { 11 | Header.RequestAcknowledge = true; 12 | } 13 | 14 | public ulong ChannelIdToStop { get; set; } 15 | 16 | public override void Deserialize(EndianReader reader) 17 | { 18 | throw new NotSupportedException(); 19 | } 20 | 21 | public override void Serialize(EndianWriter writer) 22 | { 23 | writer.WriteBE(ChannelIdToStop); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/StreamerConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | record StreamerConfiguration : ISerializable 7 | { 8 | public ushort ServerTcpPort { get; set; } 9 | public ushort ServerUdpPort { get; set; } 10 | public Guid SessionId { get; set; } 11 | public ushort RenderWidth { get; set; } 12 | public ushort RenderHeight { get; set; } 13 | public byte[] MasterSessionKey { get; set; } 14 | 15 | public void Deserialize(EndianReader reader) 16 | { 17 | ServerTcpPort = reader.ReadUInt16BE(); 18 | ServerUdpPort = reader.ReadUInt16BE(); 19 | SessionId = new Guid(reader.ReadBytes(16)); 20 | RenderWidth = reader.ReadUInt16BE(); 21 | RenderHeight = reader.ReadUInt16BE(); 22 | MasterSessionKey = reader.ReadBytes(32); 23 | } 24 | 25 | public void Serialize(EndianWriter writer) 26 | { 27 | throw new NotSupportedException(); 28 | } 29 | } 30 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/SystemTextAcknowledgeMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.SystemTextAcknowledge)] 7 | internal record SystemTextAcknowledgeMessage : SessionMessageBase 8 | { 9 | public uint TextSessionId { get; set; } 10 | public uint TextVersionAck { get; set; } 11 | 12 | public SystemTextAcknowledgeMessage() 13 | { 14 | Header.RequestAcknowledge = true; 15 | } 16 | 17 | public override void Deserialize(EndianReader reader) 18 | { 19 | TextSessionId = reader.ReadUInt32BE(); 20 | TextVersionAck = reader.ReadUInt32BE(); 21 | } 22 | 23 | public override void Serialize(EndianWriter writer) 24 | { 25 | writer.WriteBE(TextSessionId); 26 | writer.WriteBE(TextVersionAck); 27 | } 28 | } 29 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/SystemTextConfigurationMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.SystemTextConfiguration)] 7 | internal record SystemTextConfigurationMessage : TextConfiguration 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/SystemTextDoneMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.SystemTextDone)] 7 | internal record SystemTextDoneMessage : SessionMessageBase 8 | { 9 | public uint TextSessionId; 10 | public uint TextVersion; 11 | public uint Flags; 12 | public TextResult Result; 13 | 14 | public SystemTextDoneMessage() 15 | { 16 | Header.RequestAcknowledge = true; 17 | } 18 | 19 | public override void Deserialize(EndianReader reader) 20 | { 21 | TextSessionId = reader.ReadUInt32BE(); 22 | TextVersion = reader.ReadUInt32BE(); 23 | Flags = reader.ReadUInt32BE(); 24 | Result = (TextResult)reader.ReadUInt32BE(); 25 | } 26 | 27 | public override void Serialize(EndianWriter writer) 28 | { 29 | writer.WriteBE(TextSessionId); 30 | writer.WriteBE(TextVersion); 31 | writer.WriteBE(Flags); 32 | writer.WriteBE((uint)Result); 33 | } 34 | } 35 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/SystemTouchMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.SystemTouch)] 7 | internal record SystemTouchMessage : TouchMessage 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TextConfiguration.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | internal record TextConfiguration : SessionMessageBase 7 | { 8 | public ulong TextSessionId { get; set; } 9 | public uint TextBufferVersion { get; set; } 10 | public TextOption TextOptions { get; set; } 11 | public TextInputScope InputScope { get; set; } 12 | public uint MaxTextLength { get; set; } 13 | public string Locale { get; set; } 14 | public string Prompt { get; set; } 15 | 16 | public TextConfiguration() 17 | { 18 | Header.RequestAcknowledge = true; 19 | } 20 | 21 | public override void Deserialize(EndianReader reader) 22 | { 23 | TextSessionId = reader.ReadUInt64BE(); 24 | TextBufferVersion = reader.ReadUInt32BE(); 25 | TextOptions = (TextOption)reader.ReadUInt32BE(); 26 | InputScope = (TextInputScope)reader.ReadUInt32BE(); 27 | MaxTextLength = reader.ReadUInt32BE(); 28 | Locale = reader.ReadUInt16BEPrefixedString(); 29 | Prompt = reader.ReadUInt16BEPrefixedString(); 30 | } 31 | 32 | public override void Serialize(EndianWriter writer) 33 | { 34 | throw new NotSupportedException(); 35 | } 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TitleLaunchMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.TitleLaunch)] 7 | internal record TitleLaunchMessage : SessionMessageBase 8 | { 9 | public TitleLaunchMessage() 10 | { 11 | Header.RequestAcknowledge = true; 12 | } 13 | 14 | public ActiveTitleLocation Location { get; set; } 15 | public string Uri { get; set; } 16 | 17 | public override void Deserialize(EndianReader reader) 18 | { 19 | throw new NotSupportedException(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE((ushort)Location); 25 | writer.WriteUInt16BEPrefixed(Uri); 26 | } 27 | } 28 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TitleTextConfigurationMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.TitleTextConfiguration)] 7 | internal record TitleTextConfigurationMessage : TextConfiguration 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TitleTextInputMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.TitleTextInput)] 7 | internal record TitleTextInput : SessionMessageBase 8 | { 9 | public ulong TextSessionId { get; set; } 10 | public uint TextBufferVersion { get; set; } 11 | public TextResult Result { get; set; } 12 | public string Text { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | TextSessionId = reader.ReadUInt64BE(); 17 | TextBufferVersion = reader.ReadUInt32BE(); 18 | Result = (TextResult)reader.ReadUInt16BE(); 19 | Text = reader.ReadUInt16BEPrefixedString(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(TextSessionId); 25 | writer.WriteBE(TextBufferVersion); 26 | writer.WriteBE((ushort)Result); 27 | writer.WriteUInt16BEPrefixed(Text); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TitleTextSelectionMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.TitleTextSelection)] 7 | internal record TitleTextSelection : SessionMessageBase 8 | { 9 | public ulong TextSessionId { get; set; } 10 | public uint TextBufferVersion { get; set; } 11 | public uint Start { get; set; } 12 | public uint Length { get; set; } 13 | 14 | public override void Deserialize(EndianReader reader) 15 | { 16 | TextSessionId = reader.ReadUInt64BE(); 17 | TextBufferVersion = reader.ReadUInt32BE(); 18 | Start = reader.ReadUInt32BE(); 19 | Length = reader.ReadUInt32BE(); 20 | } 21 | 22 | public override void Serialize(EndianWriter writer) 23 | { 24 | writer.WriteBE(TextSessionId); 25 | writer.WriteBE(TextBufferVersion); 26 | writer.WriteBE(Start); 27 | writer.WriteBE(Length); 28 | } 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TitleTouchMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.TitleTouch)] 7 | internal record TitleTouchMessage : TouchMessage 8 | { 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/TouchMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | internal record TouchMessage : SessionMessageBase 7 | { 8 | public uint Timestamp { get; set; } 9 | public TouchPoint[] Touchpoints { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | Timestamp = reader.ReadUInt32BE(); 14 | Touchpoints = reader.ReadUInt16BEPrefixedArray(); 15 | } 16 | 17 | public override void Serialize(EndianWriter writer) 18 | { 19 | writer.WriteBE(Timestamp); 20 | writer.WriteBE((ushort)Touchpoints.Length); 21 | foreach (TouchPoint p in Touchpoints) 22 | ((ISerializable)p).Serialize(writer); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/UnknownMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | internal record UnknownMessage : SessionMessageBase 7 | { 8 | public override void Deserialize(EndianReader reader) 9 | { 10 | 11 | } 12 | 13 | public override void Serialize(EndianWriter writer) 14 | { 15 | throw new InvalidOperationException(); 16 | } 17 | } 18 | } -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/Messages/UnsnapMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session.Messages 5 | { 6 | [SessionMessageType(SessionMessageType.Unsnap)] 7 | internal record UnsnapMessage : SessionMessageBase 8 | { 9 | public byte Unknown { get; set; } 10 | 11 | public override void Deserialize(EndianReader reader) 12 | { 13 | Unknown = reader.ReadByte(); 14 | } 15 | 16 | public override void Serialize(EndianWriter writer) 17 | { 18 | writer.Write(Unknown); 19 | } 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/ServiceType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging.Session 2 | { 3 | /// 4 | /// Service type. 5 | /// 6 | enum ServiceType : ushort 7 | { 8 | None, 9 | SystemInput, 10 | SystemInputTVRemote, 11 | SystemMedia, 12 | SystemText, 13 | SystemBroadcast 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/SessionInfo.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging.Session 2 | { 3 | /// 4 | /// Session info. 5 | /// 6 | internal class SessionInfo 7 | { 8 | public uint ParticipantId { get; set; } 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/SessionMessageBase.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Common; 2 | 3 | namespace SmartGlass.Messaging.Session 4 | { 5 | /// 6 | /// Session message base. 7 | /// 8 | abstract record SessionMessageBase : ISerializable 9 | { 10 | public SessionMessageHeader Header { get; set; } 11 | 12 | public SessionMessageBase() 13 | { 14 | Header = new SessionMessageHeader() 15 | { 16 | SessionMessageType = SessionMessageTypeAttribute.GetMessageTypeForType(GetType()), 17 | Version = 2 18 | }; 19 | } 20 | 21 | public abstract void Deserialize(EndianReader reader); 22 | public abstract void Serialize(EndianWriter writer); 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/SessionMessageHeader.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging.Session 2 | { 3 | /// 4 | /// Session message header. 5 | /// 6 | internal class SessionMessageHeader 7 | { 8 | public SessionMessageType SessionMessageType { get; set; } 9 | public bool RequestAcknowledge { get; set; } 10 | public bool IsFragment { get; set; } 11 | public ushort Version { get; set; } 12 | public ulong ChannelId { get; set; } 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/SessionMessageType.cs: -------------------------------------------------------------------------------- 1 | namespace SmartGlass.Messaging.Session 2 | { 3 | /// 4 | /// Session message type. 5 | /// 6 | enum SessionMessageType : ushort 7 | { 8 | Ack = 0x01, 9 | Group = 0x02, // Unused 10 | LocalJoin = 0x03, 11 | StopActivity = 0x05, // Unused 12 | AuxiliaryStream = 0x19, 13 | ActiveSurfaceChange = 0x1A, 14 | Navigate = 0x1B, // Unused 15 | Json = 0x1C, 16 | Tunnel = 0x1D, // Unused 17 | ConsoleStatus = 0x1E, 18 | TitleTextConfiguration = 0x1F, 19 | TitleTextInput = 0x20, 20 | TitleTextSelection = 0x21, 21 | MirroringRequest = 0x22, 22 | TitleLaunch = 0x23, 23 | StartChannelRequest = 0x26, 24 | StartChannelResponse = 0x27, 25 | StopChannel = 0x28, 26 | System = 0x29, // Unused 27 | Disconnect = 0x2A, 28 | TitleTouch = 0x2E, 29 | Accelerometer = 0x2F, 30 | Gyrometer = 0x30, 31 | Inclinometer = 0x31, 32 | Compass = 0x32, 33 | Orientation = 0x33, 34 | PairedIdentityStateChanged = 0x36, 35 | Unsnap = 0x37, // Unused 36 | GameDvrRecord = 0x38, 37 | PowerOff = 0x39, 38 | 39 | MediaControllerRemoved = 0xF00, 40 | MediaCommand = 0xF01, 41 | MediaCommandResult = 0xF02, 42 | MediaState = 0xF03, 43 | Gamepad = 0xF0A, 44 | SystemTextConfiguration = 0xF2B, 45 | SystemTextInput = 0xF2C, 46 | SystemTouch = 0xF2E, 47 | SystemTextAcknowledge = 0xF34, 48 | SystemTextDone = 0xF35 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /SmartGlass/Messaging/Session/SessionMessageTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Messaging.Session 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class SessionMessageTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(SessionMessageType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static SessionMessageType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public SessionMessageType MessageType { get; private set; } 26 | 27 | public SessionMessageTypeAttribute(SessionMessageType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Channels/AudioChannelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano.Packets; 5 | 6 | namespace SmartGlass.Nano.Channels 7 | { 8 | public abstract class AudioChannelBase : StreamingChannel, IStreamingChannel 9 | { 10 | private static readonly ILogger logger = Logging.Factory.CreateLogger(); 11 | 12 | public abstract void OnControl(AudioControl control); 13 | public abstract void OnData(AudioData data); 14 | 15 | internal AudioChannelBase(NanoRdpTransport transport, ChannelOpen openPacket) 16 | : base(transport, openPacket) 17 | { 18 | MessageReceived += OnMessage; 19 | } 20 | 21 | public void OnMessage(object sender, MessageReceivedEventArgs args) 22 | { 23 | IStreamerMessage packet = args.Message as IStreamerMessage; 24 | if (packet == null) 25 | { 26 | logger.LogTrace($"Not handling packet {args.Message.Header.PayloadType}"); 27 | return; 28 | } 29 | 30 | switch ((AudioPayloadType)packet.StreamerHeader.PacketType) 31 | { 32 | case AudioPayloadType.Control: 33 | OnControl((AudioControl)packet); 34 | break; 35 | case AudioPayloadType.Data: 36 | OnData((AudioData)packet); 37 | break; 38 | } 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Channels/IStreamingChannel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | using SmartGlass.Nano.Packets; 4 | 5 | namespace SmartGlass.Nano.Channels 6 | { 7 | public interface IStreamingChannel 8 | { 9 | void OnMessage(object sender, MessageReceivedEventArgs args); 10 | } 11 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Channels/InputChannelBase.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using Microsoft.Extensions.Logging; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano.Packets; 5 | 6 | namespace SmartGlass.Nano.Channels 7 | { 8 | public abstract class InputChannelBase : StreamingChannel, IStreamingChannel 9 | { 10 | private static readonly ILogger logger = Logging.Factory.CreateLogger(); 11 | public uint MaxTouches { get; internal set; } 12 | public uint DesktopWidth { get; internal set; } 13 | public uint DesktopHeight { get; internal set; } 14 | public abstract void OnFrame(InputFrame frame); 15 | public abstract void OnFrameAck(InputFrameAck ack); 16 | 17 | internal InputChannelBase(NanoRdpTransport transport, ChannelOpen openPacket) 18 | : base(transport, openPacket) 19 | { 20 | MessageReceived += OnMessage; 21 | } 22 | 23 | public void OnMessage(object sender, MessageReceivedEventArgs args) 24 | { 25 | IStreamerMessage packet = args.Message as IStreamerMessage; 26 | if (packet == null) 27 | { 28 | logger.LogTrace($"Not handling packet {args.Message.Header.PayloadType}"); 29 | return; 30 | } 31 | 32 | switch ((InputPayloadType)packet.StreamerHeader.PacketType) 33 | { 34 | case InputPayloadType.Frame: 35 | OnFrame((InputFrame)packet); 36 | break; 37 | case InputPayloadType.FrameAck: 38 | OnFrameAck((InputFrameAck)packet); 39 | break; 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Consumer/AudioAssembler.cs: -------------------------------------------------------------------------------- 1 | using SmartGlass.Nano.Packets; 2 | 3 | namespace SmartGlass.Nano.Consumer 4 | { 5 | public class AudioAssembler 6 | { 7 | private ulong _lastProcessedTimestamp; 8 | 9 | public AACFrame AssembleAudioFrame(AudioData data, AACProfile profile, 10 | int samplingFreq, byte channels) 11 | { 12 | AACFrame aacFrame = null; 13 | ulong timestamp = data.Timestamp; 14 | 15 | 16 | if (timestamp > _lastProcessedTimestamp) 17 | { 18 | // Only process new audio frames 19 | aacFrame = new AACFrame(data.Data, data.Timestamp, data.FrameId, data.Flags, 20 | profile, samplingFreq, channels); 21 | _lastProcessedTimestamp = timestamp; 22 | } 23 | 24 | return aacFrame; 25 | } 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Consumer/IConsumer.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Nano.Packets; 3 | 4 | namespace SmartGlass.Nano.Consumer 5 | { 6 | public interface IAudioConsumer 7 | { 8 | void ConsumeAudioData(object sender, AudioDataEventArgs args); 9 | } 10 | 11 | public interface IVideoConsumer 12 | { 13 | void ConsumeVideoData(object sender, VideoDataEventArgs args); 14 | } 15 | 16 | public interface IInputFeedbackConsumer 17 | { 18 | void ConsumeInputFeedbackFrame(object sender, InputFrameEventArgs args); 19 | } 20 | 21 | public interface IConsumer 22 | : IAudioConsumer, IVideoConsumer, IInputFeedbackConsumer 23 | { 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/AudioPayloadTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class AudioPayloadTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(AudioPayloadType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static AudioPayloadType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public AudioPayloadType MessageType { get; private set; } 26 | 27 | public AudioPayloadTypeAttribute(AudioPayloadType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/ChannelControlTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class ChannelControlTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(ChannelControlType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static ChannelControlType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public ChannelControlType MessageType { get; private set; } 26 | 27 | public ChannelControlTypeAttribute(ChannelControlType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/ControlOpCodeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class ControlOpCodeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(ControlOpCode messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static ControlOpCode GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public ControlOpCode MessageType { get; private set; } 26 | 27 | public ControlOpCodeAttribute(ControlOpCode messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/InputPayloadTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class InputPayloadTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(InputPayloadType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static InputPayloadType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public InputPayloadType MessageType { get; private set; } 26 | 27 | public InputPayloadTypeAttribute(InputPayloadType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/NanoPayloadTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class NanoPayloadTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(NanoPayloadType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static NanoPayloadType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public NanoPayloadType MessageType { get; private set; } 26 | 27 | public NanoPayloadTypeAttribute(NanoPayloadType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/Attributes/VideoPayloadTypeAttribute.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano 5 | { 6 | [AttributeUsage( 7 | AttributeTargets.Class, 8 | AllowMultiple = false, 9 | Inherited = false)] 10 | internal class VideoPayloadTypeAttribute : Attribute 11 | { 12 | private static AttributeTypeMapping _typeMapping = 13 | new AttributeTypeMapping(a => a.MessageType); 14 | 15 | public static Type GetTypeForMessageType(VideoPayloadType messageType) 16 | { 17 | return _typeMapping.GetTypeForKey(messageType); 18 | } 19 | 20 | public static VideoPayloadType GetMessageTypeForType(Type type) 21 | { 22 | return _typeMapping.GetKeyForType(type); 23 | } 24 | 25 | public VideoPayloadType MessageType { get; private set; } 26 | 27 | public VideoPayloadTypeAttribute(VideoPayloadType messageType) 28 | { 29 | MessageType = messageType; 30 | } 31 | } 32 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/AudioCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum AudioCodec : uint 5 | { 6 | Opus, 7 | AAC, 8 | PCM 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/AudioControlFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | [Flags] 5 | public enum AudioControlFlags : uint 6 | { 7 | StopStream = 0x8, 8 | StartStream = 0x10, 9 | Reinitialize = 0x20 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/AudioPayloadType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum AudioPayloadType : uint 5 | { 6 | ServerHandshake = 1, 7 | ClientHandshake, 8 | Control, 9 | Data 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/ChannelControlType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum ChannelControlType : uint 5 | { 6 | Create = 2, 7 | Open, 8 | Close 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/ControlHandshakeType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum ControlHandshakeType : byte 5 | { 6 | SYN, 7 | ACK 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/ControlOpCode.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum ControlOpCode : ushort 5 | { 6 | SessionInit = 1, 7 | SessionCreate, 8 | SessionCreateResponse, 9 | SessionDestroy, 10 | VideoStatistics, 11 | RealtimeTelemetry, 12 | ChangeVideoQuality, 13 | InitiateNetworkTest, 14 | NetworkInformation, 15 | NetworkTestResponse, 16 | ControllerEvent 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/ControllerEventType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum ControllerEventType : byte 5 | { 6 | Removed, 7 | Added 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/InputPayloadType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum InputPayloadType : uint 5 | { 6 | ServerHandshake = 1, 7 | ClientHandshake, 8 | FrameAck, 9 | Frame 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/NanoChannel.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum NanoChannel 5 | { 6 | Video = 1, 7 | Audio, 8 | ChatAudio, 9 | Control, 10 | Input, 11 | InputFeedback, 12 | TcpBase, 13 | Unknown 14 | } 15 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/NanoGamepadAxis.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Nano 4 | { 5 | public enum NanoGamepadAxis 6 | { 7 | LeftX, 8 | LeftY, 9 | RightX, 10 | RightY, 11 | TriggerLeft, 12 | TriggerRight 13 | } 14 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/NanoGamepadButton.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Nano 4 | { 5 | public enum NanoGamepadButton 6 | { 7 | DPadUp, 8 | DPadDown, 9 | DPadLeft, 10 | DPadRight, 11 | Start, 12 | Back, 13 | LeftThumbstick, 14 | RightThumbstick, 15 | LeftShoulder, 16 | RightShoulder, 17 | Guide, 18 | Unknown, 19 | A, 20 | B, 21 | X, 22 | Y 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/NanoPayloadType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum NanoPayloadType : byte 5 | { 6 | Streamer = 0x23, 7 | ControlHandshake = 0x60, 8 | ChannelControl = 0x61, 9 | UDPHandshake = 0x64 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/StreamerFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | [Flags] 5 | public enum StreamerFlags : uint 6 | { 7 | GotSeqAndPrev = 0x1, 8 | Unknown1 = 0x2 9 | } 10 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/VideoCodec.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum VideoCodec : uint 5 | { 6 | H264, 7 | YUV, 8 | RGB 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/VideoControlFlags.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | [Flags] 5 | public enum VideoControlFlags : uint 6 | { 7 | LastDisplayedFrame = 0x1, 8 | LostFrames = 0x2, 9 | QueueDepth = 0x4, 10 | StopStream = 0x8, 11 | StartStream = 0x10, 12 | RequestKeyframe = 0x20 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Enums/VideoPayloadType.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | namespace SmartGlass.Nano 3 | { 4 | public enum VideoPayloadType : uint 5 | { 6 | ServerHandshake = 1, 7 | ClientHandshake, 8 | Control, 9 | Data 10 | } 11 | } 12 | -------------------------------------------------------------------------------- /SmartGlass/Nano/NanoException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Nano 4 | { 5 | public class NanoException : Exception 6 | { 7 | public NanoException(string message) : base(message) 8 | { 9 | } 10 | 11 | public NanoException(string message, int result) : base(message) 12 | { 13 | HResult = result; 14 | } 15 | 16 | public NanoException(string message, Exception innerException) 17 | : base(message, innerException) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/NanoPackingException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Nano 4 | { 5 | public class NanoPackingException : Exception 6 | { 7 | public NanoPackingException(string message) : base(message) 8 | { 9 | } 10 | 11 | public NanoPackingException(string message, int result) : base(message) 12 | { 13 | HResult = result; 14 | } 15 | 16 | public NanoPackingException(string message, Exception innerException) 17 | : base(message, innerException) 18 | { 19 | } 20 | } 21 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Audio/AudioClientHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [AudioPayloadType(AudioPayloadType.ClientHandshake)] 9 | public class AudioClientHandshake : StreamerMessage 10 | { 11 | public uint InitialFrameID { get; private set; } 12 | public AudioFormat RequestedFormat { get; private set; } 13 | 14 | public AudioClientHandshake() 15 | : base((uint)AudioPayloadType.ClientHandshake) 16 | { 17 | RequestedFormat = new AudioFormat(); 18 | } 19 | 20 | public AudioClientHandshake(uint initialFrameID, AudioFormat requestedFormat) 21 | : base((uint)AudioPayloadType.ClientHandshake) 22 | { 23 | InitialFrameID = initialFrameID; 24 | RequestedFormat = requestedFormat; 25 | } 26 | 27 | internal override void DeserializeStreamer(EndianReader reader) 28 | { 29 | InitialFrameID = reader.ReadUInt32LE(); 30 | ((ISerializable)RequestedFormat).Deserialize(reader); 31 | } 32 | 33 | internal override void SerializeStreamer(EndianWriter writer) 34 | { 35 | writer.WriteLE(InitialFrameID); 36 | ((ISerializable)RequestedFormat).Serialize(writer); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Audio/AudioControl.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [AudioPayloadType(AudioPayloadType.Control)] 9 | public class AudioControl : StreamerMessage 10 | { 11 | public AudioControlFlags Flags { get; private set; } 12 | 13 | public AudioControl() 14 | : base((uint)AudioPayloadType.Control) 15 | { 16 | } 17 | 18 | public AudioControl(AudioControlFlags flags) 19 | : base((uint)AudioPayloadType.Control) 20 | { 21 | Flags = flags; 22 | } 23 | 24 | internal override void DeserializeStreamer(EndianReader reader) 25 | { 26 | Flags = (AudioControlFlags)reader.ReadUInt32LE(); 27 | } 28 | 29 | internal override void SerializeStreamer(EndianWriter writer) 30 | { 31 | writer.WriteLE((uint)Flags); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Audio/AudioData.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [AudioPayloadType(AudioPayloadType.Data)] 9 | public class AudioData : StreamerMessage 10 | { 11 | public uint Flags { get; private set; } 12 | public uint FrameId { get; private set; } 13 | public ulong Timestamp { get; private set; } 14 | public byte[] Data { get; private set; } 15 | 16 | public AudioData() 17 | : base((uint)AudioPayloadType.Data) 18 | { 19 | } 20 | 21 | public AudioData(uint flags, uint frameId, 22 | ulong timestamp, byte[] data) 23 | : base((uint)AudioPayloadType.Data) 24 | { 25 | Flags = flags; 26 | FrameId = frameId; 27 | Timestamp = timestamp; 28 | Data = data; 29 | } 30 | 31 | internal override void DeserializeStreamer(EndianReader reader) 32 | { 33 | Flags = reader.ReadUInt32LE(); 34 | FrameId = reader.ReadUInt32LE(); 35 | Timestamp = reader.ReadUInt64LE(); 36 | Data = reader.ReadUInt32LEPrefixedBlob(); 37 | } 38 | 39 | internal override void SerializeStreamer(EndianWriter writer) 40 | { 41 | writer.WriteLE(Flags); 42 | writer.WriteLE(FrameId); 43 | writer.WriteLE(Timestamp); 44 | writer.WriteUInt32LEPrefixedBlob(Data); 45 | } 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Audio/AudioServerHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [AudioPayloadType(AudioPayloadType.ServerHandshake)] 9 | public class AudioServerHandshake : StreamerMessage 10 | { 11 | public uint ProtocolVersion { get; private set; } 12 | public ulong ReferenceTimestamp { get; private set; } 13 | public AudioFormat[] Formats { get; private set; } 14 | 15 | public AudioServerHandshake() 16 | : base((uint)AudioPayloadType.ServerHandshake) 17 | { 18 | } 19 | 20 | public AudioServerHandshake(uint protocolVersion, ulong refTimestamp, 21 | AudioFormat[] formats) 22 | : base((uint)AudioPayloadType.ServerHandshake) 23 | { 24 | ProtocolVersion = protocolVersion; 25 | ReferenceTimestamp = refTimestamp; 26 | Formats = formats; 27 | } 28 | 29 | internal override void DeserializeStreamer(EndianReader reader) 30 | { 31 | ProtocolVersion = reader.ReadUInt32LE(); 32 | ReferenceTimestamp = reader.ReadUInt64LE(); 33 | Formats = reader.ReadUInt32LEPrefixedArray(); 34 | } 35 | 36 | internal override void SerializeStreamer(EndianWriter writer) 37 | { 38 | writer.WriteLE(ProtocolVersion); 39 | writer.WriteLE(ReferenceTimestamp); 40 | writer.WriteUInt32LEPrefixedArray(Formats); 41 | } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/ChannelControl/ChannelClose.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ChannelControlType(ChannelControlType.Close)] 9 | public class ChannelClose : ChannelControlMessage 10 | { 11 | public uint Flags { get; private set; } 12 | 13 | public ChannelClose() 14 | : base(ChannelControlType.Close) 15 | { 16 | } 17 | 18 | public ChannelClose(uint flags) 19 | : base(ChannelControlType.Close) 20 | { 21 | Flags = flags; 22 | } 23 | 24 | internal override void DeserializeData(EndianReader reader) 25 | { 26 | Flags = reader.ReadUInt32LE(); 27 | } 28 | 29 | internal override void SerializeData(EndianWriter writer) 30 | { 31 | writer.WriteLE(Flags); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/ChannelControl/ChannelCreate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using System.Text; 4 | using SmartGlass.Common; 5 | using SmartGlass.Nano; 6 | 7 | namespace SmartGlass.Nano.Packets 8 | { 9 | [ChannelControlType(ChannelControlType.Create)] 10 | public class ChannelCreate : ChannelControlMessage 11 | { 12 | public string Name { get; private set; } 13 | public uint Flags { get; private set; } 14 | 15 | public ChannelCreate() 16 | : base(ChannelControlType.Create) 17 | { 18 | } 19 | 20 | public ChannelCreate(string name, uint flags) 21 | : base(ChannelControlType.Create) 22 | { 23 | Name = name; 24 | Flags = flags; 25 | } 26 | 27 | internal override void DeserializeData(EndianReader reader) 28 | { 29 | byte[] name = reader.ReadUInt16LEPrefixedBlob(); 30 | Name = Encoding.GetEncoding("utf-8").GetString(name); 31 | Flags = reader.ReadUInt32LE(); 32 | } 33 | 34 | internal override void SerializeData(EndianWriter writer) 35 | { 36 | byte[] name = Encoding.GetEncoding("utf-8").GetBytes(Name); 37 | writer.WriteUInt16LEPrefixedBlob(name); 38 | writer.WriteLE(Flags); 39 | } 40 | } 41 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/ChannelControl/ChannelOpen.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ChannelControlType(ChannelControlType.Open)] 9 | public class ChannelOpen : ChannelControlMessage 10 | { 11 | public byte[] Flags { get; private set; } 12 | 13 | public ChannelOpen() 14 | : base(ChannelControlType.Open) 15 | { 16 | Flags = new byte[0]; 17 | } 18 | 19 | public ChannelOpen(byte[] flags) 20 | : base(ChannelControlType.Open) 21 | { 22 | Flags = flags; 23 | } 24 | 25 | internal override void DeserializeData(EndianReader reader) 26 | { 27 | Flags = reader.ReadUInt32LEPrefixedBlob(); 28 | } 29 | 30 | internal override void SerializeData(EndianWriter writer) 31 | { 32 | if (Flags != null && Flags.Length > 0) 33 | { 34 | writer.WriteLE((uint)Flags.Length); 35 | writer.Write(Flags); 36 | } 37 | else 38 | { 39 | writer.WriteLE((uint)0); 40 | } 41 | } 42 | } 43 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/ChannelControlMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [NanoPayloadType(NanoPayloadType.ChannelControl)] 9 | public abstract class ChannelControlMessage : INanoPacket 10 | { 11 | public NanoChannel Channel { get; set; } 12 | public RtpHeader Header { get; set; } 13 | public ChannelControlType Type { get; set; } 14 | 15 | public ChannelControlMessage() 16 | { 17 | Header = new RtpHeader() 18 | { 19 | PayloadType = NanoPayloadType.ChannelControl 20 | }; 21 | } 22 | 23 | public ChannelControlMessage(ChannelControlType type) 24 | { 25 | Header = new RtpHeader() 26 | { 27 | PayloadType = NanoPayloadType.ChannelControl 28 | }; 29 | Type = type; 30 | } 31 | 32 | public void Deserialize(EndianReader reader) 33 | { 34 | Type = (ChannelControlType)reader.ReadUInt32LE(); 35 | DeserializeData(reader); 36 | } 37 | 38 | public void Serialize(EndianWriter writer) 39 | { 40 | writer.WriteLE((uint)Type); 41 | SerializeData(writer); 42 | } 43 | 44 | internal abstract void DeserializeData(EndianReader reader); 45 | internal abstract void SerializeData(EndianWriter writer); 46 | } 47 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/ControllerEvent.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.ControllerEvent)] 9 | public class ControllerEvent : StreamerMessageWithHeader 10 | { 11 | public ControllerEventType Type { get; private set; } 12 | public byte ControllerIndex { get; private set; } 13 | 14 | public ControllerEvent() 15 | : base(ControlOpCode.ControllerEvent) 16 | { 17 | } 18 | 19 | public ControllerEvent(ControllerEventType controllerEvent, 20 | byte controllerIndex) 21 | : base(ControlOpCode.ControllerEvent) 22 | { 23 | Type = controllerEvent; 24 | ControllerIndex = controllerIndex; 25 | } 26 | 27 | internal override void DeserializeStreamer(EndianReader reader) 28 | { 29 | Type = (ControllerEventType)reader.ReadByte(); 30 | ControllerIndex = reader.ReadByte(); 31 | } 32 | 33 | internal override void SerializeStreamer(EndianWriter writer) 34 | { 35 | writer.Write((byte)Type); 36 | writer.Write(ControllerIndex); 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/InitiateNetworkTest.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.InitiateNetworkTest)] 9 | public class InitiateNetworkTest : StreamerMessageWithHeader 10 | { 11 | public InitiateNetworkTest() 12 | : base(ControlOpCode.InitiateNetworkTest) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/NetworkInformation.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.NetworkInformation)] 9 | public class NetworkInformation : StreamerMessageWithHeader 10 | { 11 | public NetworkInformation() 12 | : base(ControlOpCode.NetworkInformation) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/NetworkTestResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.NetworkTestResponse)] 9 | public class NetworkTestResponse : StreamerMessageWithHeader 10 | { 11 | public NetworkTestResponse() 12 | : base(ControlOpCode.NetworkTestResponse) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/RealtimeTelemetry.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.RealtimeTelemetry)] 9 | public class RealtimeTelemetry : StreamerMessageWithHeader 10 | { 11 | public RealtimeTelemetry() 12 | : base(ControlOpCode.RealtimeTelemetry) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | } 19 | 20 | internal override void SerializeStreamer(EndianWriter writer) 21 | { 22 | throw new NotSupportedException(); 23 | } 24 | } 25 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/SessionCreate.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.SessionCreate)] 9 | public class SessionCreate : StreamerMessageWithHeader 10 | { 11 | public SessionCreate() 12 | : base(ControlOpCode.SessionCreate) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/SessionCreateResponse.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.SessionCreateResponse)] 9 | public class SessionCreateResponse : StreamerMessageWithHeader 10 | { 11 | public SessionCreateResponse() 12 | : base(ControlOpCode.SessionCreateResponse) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/SessionDestroy.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.SessionDestroy)] 9 | public class SessionDestroy : StreamerMessageWithHeader 10 | { 11 | public SessionDestroy() 12 | : base(ControlOpCode.SessionDestroy) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/SessionInit.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.SessionInit)] 9 | public class SessionInit : StreamerMessageWithHeader 10 | { 11 | public SessionInit() 12 | : base(ControlOpCode.SessionInit) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Control/VideoStatistics.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [ControlOpCode(ControlOpCode.VideoStatistics)] 9 | public class VideoStatistics : StreamerMessageWithHeader 10 | { 11 | public VideoStatistics() 12 | : base(ControlOpCode.VideoStatistics) 13 | { 14 | } 15 | 16 | internal override void DeserializeStreamer(EndianReader reader) 17 | { 18 | throw new NotImplementedException(); 19 | } 20 | 21 | internal override void SerializeStreamer(EndianWriter writer) 22 | { 23 | throw new NotImplementedException(); 24 | } 25 | } 26 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/ControlHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [NanoPayloadType(NanoPayloadType.ControlHandshake)] 9 | public class ControlHandshake : INanoPacket 10 | { 11 | public NanoChannel Channel { get; set; } 12 | public RtpHeader Header { get; set; } 13 | public ControlHandshakeType Type { get; internal set; } 14 | public ushort ConnectionId { get; internal set; } 15 | 16 | public ControlHandshake() 17 | { 18 | Header = new RtpHeader() 19 | { 20 | PayloadType = NanoPayloadType.ControlHandshake 21 | }; 22 | } 23 | 24 | public ControlHandshake(ControlHandshakeType type, ushort connectionId) 25 | { 26 | Header = new RtpHeader() 27 | { 28 | PayloadType = NanoPayloadType.ControlHandshake 29 | }; 30 | Type = type; 31 | ConnectionId = connectionId; 32 | } 33 | 34 | public void Deserialize(EndianReader reader) 35 | { 36 | Type = (ControlHandshakeType)reader.ReadByte(); 37 | ConnectionId = reader.ReadUInt16LE(); 38 | } 39 | 40 | public void Serialize(EndianWriter bw) 41 | { 42 | bw.Write((byte)Type); 43 | bw.WriteLE(ConnectionId); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/INanoPacket.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass.Nano.Packets 5 | { 6 | public interface INanoPacket : ISerializable 7 | { 8 | NanoChannel Channel { get; set; } 9 | RtpHeader Header { get; set; } 10 | } 11 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/IStreamerMessage.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass.Nano.Packets 4 | { 5 | public interface IStreamerMessage : INanoPacket 6 | { 7 | StreamerHeader StreamerHeader { get; } 8 | } 9 | } 10 | -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Input/InputClientHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [InputPayloadType(InputPayloadType.ClientHandshake)] 9 | public class InputClientHandshake : StreamerMessage 10 | { 11 | public uint MaxTouches { get; private set; } 12 | public ulong ReferenceTimestamp { get; private set; } 13 | 14 | public InputClientHandshake() 15 | : base((uint)InputPayloadType.ClientHandshake) 16 | { 17 | } 18 | 19 | public InputClientHandshake(uint maxTouches, ulong refTimestamp) 20 | : base((uint)InputPayloadType.ClientHandshake) 21 | { 22 | MaxTouches = maxTouches; 23 | ReferenceTimestamp = refTimestamp; 24 | } 25 | 26 | internal override void DeserializeStreamer(EndianReader reader) 27 | { 28 | MaxTouches = reader.ReadUInt32LE(); 29 | ReferenceTimestamp = reader.ReadUInt64LE(); 30 | } 31 | 32 | internal override void SerializeStreamer(EndianWriter writer) 33 | { 34 | writer.WriteLE(MaxTouches); 35 | writer.WriteLE(ReferenceTimestamp); 36 | } 37 | } 38 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Input/InputFrameAck.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [InputPayloadType(InputPayloadType.FrameAck)] 9 | public class InputFrameAck : StreamerMessage 10 | { 11 | public uint AckedFrame { get; private set; } 12 | 13 | public InputFrameAck() 14 | : base((uint)InputPayloadType.FrameAck) 15 | { 16 | } 17 | 18 | public InputFrameAck(uint ackedFrame) 19 | : base((uint)InputPayloadType.FrameAck) 20 | { 21 | AckedFrame = ackedFrame; 22 | } 23 | 24 | internal override void DeserializeStreamer(EndianReader reader) 25 | { 26 | AckedFrame = reader.ReadUInt32LE(); 27 | } 28 | 29 | internal override void SerializeStreamer(EndianWriter writer) 30 | { 31 | writer.WriteLE(AckedFrame); 32 | } 33 | } 34 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/StreamerControlHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | public class StreamerControlHeader : ISerializable 9 | { 10 | public uint PreviousSequence { get; set; } 11 | public ushort Unknown1 { get; set; } 12 | public ushort Unknown2 { get; set; } 13 | public ControlOpCode OpCode { get; private set; } 14 | 15 | public StreamerControlHeader() 16 | { 17 | } 18 | 19 | public StreamerControlHeader(ControlOpCode opCode) 20 | { 21 | OpCode = opCode; 22 | } 23 | 24 | public void Deserialize(EndianReader br) 25 | { 26 | PreviousSequence = br.ReadUInt32LE(); 27 | Unknown1 = br.ReadUInt16LE(); 28 | Unknown2 = br.ReadUInt16LE(); 29 | OpCode = (ControlOpCode)br.ReadUInt16LE(); 30 | } 31 | 32 | public void Serialize(EndianWriter bw) 33 | { 34 | bw.WriteLE(PreviousSequence); 35 | bw.WriteLE(Unknown1); 36 | bw.WriteLE(Unknown2); 37 | bw.WriteLE((ushort)OpCode); 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/StreamerHeader.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | public class StreamerHeader : ISerializable 9 | { 10 | public StreamerFlags Flags { get; internal set; } 11 | public uint SequenceNumber { get; internal set; } 12 | public uint PreviousSequenceNumber { get; internal set; } 13 | public uint PacketType { get; internal set; } 14 | 15 | public StreamerHeader() 16 | { 17 | } 18 | 19 | public StreamerHeader(uint packetType) 20 | { 21 | PacketType = packetType; 22 | } 23 | 24 | public void Deserialize(EndianReader br) 25 | { 26 | Flags = (StreamerFlags)br.ReadUInt32LE(); 27 | if (Flags.HasFlag(StreamerFlags.GotSeqAndPrev)) 28 | { 29 | SequenceNumber = br.ReadUInt32LE(); 30 | PreviousSequenceNumber = br.ReadUInt32LE(); 31 | } 32 | PacketType = br.ReadUInt32LE(); 33 | } 34 | 35 | public void Serialize(EndianWriter bw) 36 | { 37 | bw.WriteLE((uint)Flags); 38 | if (Flags.HasFlag(StreamerFlags.GotSeqAndPrev)) 39 | { 40 | bw.WriteLE(SequenceNumber); 41 | bw.WriteLE(PreviousSequenceNumber); 42 | } 43 | bw.WriteLE(PacketType); 44 | } 45 | } 46 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/UdpHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [NanoPayloadType(NanoPayloadType.UDPHandshake)] 9 | public class UdpHandshake : INanoPacket 10 | { 11 | public NanoChannel Channel { get; set; } 12 | public RtpHeader Header { get; set; } 13 | public ControlHandshakeType Type { get; private set; } 14 | 15 | public UdpHandshake() 16 | { 17 | Header = new RtpHeader() 18 | { 19 | PayloadType = NanoPayloadType.UDPHandshake 20 | }; 21 | } 22 | 23 | public UdpHandshake(ControlHandshakeType type) 24 | { 25 | Header = new RtpHeader() 26 | { 27 | PayloadType = NanoPayloadType.UDPHandshake 28 | }; 29 | Type = type; 30 | } 31 | 32 | public void Deserialize(EndianReader br) 33 | { 34 | Type = (ControlHandshakeType)br.ReadByte(); 35 | } 36 | 37 | public void Serialize(EndianWriter bw) 38 | { 39 | bw.Write((byte)Type); 40 | } 41 | } 42 | } -------------------------------------------------------------------------------- /SmartGlass/Nano/Packets/Video/VideoClientHandshake.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using System.IO; 3 | using SmartGlass.Common; 4 | using SmartGlass.Nano; 5 | 6 | namespace SmartGlass.Nano.Packets 7 | { 8 | [VideoPayloadType(VideoPayloadType.ClientHandshake)] 9 | public class VideoClientHandshake : StreamerMessage 10 | { 11 | public uint InitialFrameId { get; private set; } 12 | public VideoFormat RequestedFormat { get; private set; } 13 | 14 | public VideoClientHandshake() 15 | : base((uint)VideoPayloadType.ClientHandshake) 16 | { 17 | RequestedFormat = new VideoFormat(); 18 | } 19 | 20 | public VideoClientHandshake(uint initialFrameId, VideoFormat requestedFormat) 21 | : base((uint)VideoPayloadType.ClientHandshake) 22 | { 23 | InitialFrameId = initialFrameId; 24 | RequestedFormat = requestedFormat; 25 | } 26 | 27 | internal override void DeserializeStreamer(EndianReader reader) 28 | { 29 | InitialFrameId = reader.ReadUInt32LE(); 30 | ((ISerializable)RequestedFormat).Deserialize(reader); 31 | } 32 | 33 | internal override void SerializeStreamer(EndianWriter writer) 34 | { 35 | writer.WriteLE(InitialFrameId); 36 | ((ISerializable)RequestedFormat).Serialize(writer); 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /SmartGlass/SmartGlass.csproj: -------------------------------------------------------------------------------- 1 | 2 | 3 | net5.0 4 | OpenXbox.SmartGlass 5 | Joel Day, Team OpenXbox 6 | Xbox One SmartGlass/Arcadia client library for .NET 7 | false 8 | Copyright 2018 (c) Joel Day, Team OpenXbox 9 | xbox smartglass arcadia nano gamestream client 10 | 1.0.5 11 | https://github.com/OpenXbox/xbox-smartglass-csharp 12 | MIT 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | <_Parameter1>SmartGlass.Tests 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /SmartGlass/SmartGlassException.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | 3 | namespace SmartGlass 4 | { 5 | public class SmartGlassException : Exception 6 | { 7 | public SmartGlassException(string message) : base(message) 8 | { 9 | } 10 | 11 | public SmartGlassException(string message, int result) : base(message) 12 | { 13 | HResult = result; 14 | } 15 | 16 | public SmartGlassException(string message, Exception innerException) : base(message, innerException) 17 | { 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /SmartGlass/TextDelta.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass 5 | { 6 | internal class TextDelta : ISerializable 7 | { 8 | public uint Offset { get; set; } 9 | public uint DeleteCount { get; set; } 10 | public string InsertContent { get; set; } 11 | 12 | public void Deserialize(EndianReader reader) 13 | { 14 | Offset = reader.ReadUInt32BE(); 15 | DeleteCount = reader.ReadUInt32BE(); 16 | InsertContent = reader.ReadUInt16BEPrefixedString(); 17 | } 18 | 19 | public void Serialize(EndianWriter writer) 20 | { 21 | writer.WriteBE(Offset); 22 | writer.WriteBE(DeleteCount); 23 | writer.WriteUInt16BEPrefixed(InsertContent); 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /SmartGlass/TouchPoint.cs: -------------------------------------------------------------------------------- 1 | using System; 2 | using SmartGlass.Common; 3 | 4 | namespace SmartGlass 5 | { 6 | public class TouchPoint : ISerializable 7 | { 8 | public uint Id { get; set; } 9 | public TouchAction Action { get; set; } 10 | public uint PointX { get; set; } 11 | public uint PointY { get; set; } 12 | 13 | void ISerializable.Deserialize(EndianReader reader) 14 | { 15 | Id = reader.ReadUInt32BE(); 16 | Action = (TouchAction)reader.ReadUInt16BE(); 17 | PointX = reader.ReadUInt32BE(); 18 | PointY = reader.ReadUInt32BE(); 19 | } 20 | 21 | void ISerializable.Serialize(EndianWriter writer) 22 | { 23 | writer.WriteBE(Id); 24 | writer.WriteBE((ushort)Action); 25 | writer.WriteBE(PointX); 26 | writer.WriteBE(PointY); 27 | } 28 | } 29 | } 30 | --------------------------------------------------------------------------------