public static async Task <NanoClient> InitNano(string ipAddress, GamestreamSession session) { NanoClient nano = new NanoClient(ipAddress, session); try { // General Handshaking & Opening channels await nano.InitializeProtocolAsync(); await nano.OpenInputChannelAsync(1280, 720); // Audio & Video client handshaking // Sets desired AV formats _audioFormat = nano.AudioFormats[0]; _videoFormat = nano.VideoFormats[0]; await nano.InitializeStreamAsync(_audioFormat, _videoFormat); // TODO: Send opus audio chat samples to console _chatAudioFormat = new AudioFormat(1, 24000, AudioCodec.Opus); await nano.OpenChatAudioChannelAsync(_chatAudioFormat); // Tell console to start sending AV frames await nano.StartStreamAsync(); } catch (Exception e) { Console.WriteLine($"Failed to init Nano, error: {e}"); return(null); } return(nano); }
/* * Protocol */ public async Task StartStream(SurfaceTexture surface) { System.Diagnostics.Debug.WriteLine($"Connecting to console..."); _smartGlassClient = await SmartGlassClient.ConnectAsync(_hostName); // Get general gamestream configuration var config = GamestreamConfiguration.GetStandardConfig(); /* Modify standard config, if desired */ var broadcastChannel = _smartGlassClient.BroadcastChannel; var session = await broadcastChannel.StartGamestreamAsync(config); System.Diagnostics.Debug.WriteLine( $"Connecting to Nano, TCP: {session.TcpPort}, UDP: {session.UdpPort}"); _nanoClient = new NanoClient(_hostName, session); // General Handshaking & Opening channels await _nanoClient.InitializeProtocolAsync(); // Audio & Video client handshaking // Sets desired AV formats Packets.AudioFormat audioFormat = _nanoClient.AudioFormats[0]; Packets.VideoFormat videoFormat = _nanoClient.VideoFormats[0]; await _nanoClient.InitializeStreamAsync(audioFormat, videoFormat); // Start ChatAudio channel Packets.AudioFormat chatAudioFormat = new Packets.AudioFormat(1, 24000, AudioCodec.Opus); await _nanoClient.OpenChatAudioChannelAsync(chatAudioFormat); _mcConsumer = new MediaCoreConsumer(surface, audioFormat, videoFormat); _nanoClient.AddConsumer(_mcConsumer); // Tell console to start sending AV frames await _nanoClient.StartStreamAsync(); // Start Controller input channel await _nanoClient.OpenInputChannelAsync(1280, 720); System.Diagnostics.Debug.WriteLine($"Nano connected and running."); }
public override async Task <CommandResult> ExecuteAsync(CancellationToken cancel) { if (TokenFilePath != null) { using (FileStream fs = File.Open(TokenFilePath, FileMode.Open)) { AuthService = await AuthenticationService.LoadFromJsonFileStream(fs); await AuthService.AuthenticateAsync(); } await AuthService.DumpToJsonFileAsync(TokenFilePath); } Console.WriteLine($"Connecting to {Hostname}..."); GamestreamSession session = null; SmartGlassClient Client = null; try { Client = await SmartGlassClient.ConnectAsync(Hostname, AuthService == null?null : AuthService.XToken.UserInformation.Userhash, AuthService == null?null : AuthService.XToken.Jwt); } catch (SmartGlassException e) { Console.WriteLine($"Failed to connect: {e.Message}"); return(CommandResult.RuntimeFailure); } catch (TimeoutException) { Console.WriteLine($"Timeout while connecting"); return(CommandResult.RuntimeFailure); } var broadcastChannel = Client.BroadcastChannel; var config = GamestreamConfiguration.GetStandardConfig(); try { session = await broadcastChannel.StartGamestreamAsync(config); } catch (Exception e) { Console.WriteLine($"Failed to send StartGamestream: {e.Message}"); return(CommandResult.RuntimeFailure); } Console.WriteLine($"Connecting to Nano, TCP: {session.TcpPort}, UDP: {session.UdpPort}"); var nano = new NanoClient(Hostname, session); try { Console.WriteLine($"Running protocol init..."); await nano.InitializeProtocolAsync(); await nano.OpenInputChannelAsync(1280, 720); await nano.OpenChatAudioChannelAsync( new Nano.Packets.AudioFormat(1, 24000, AudioCodec.Opus)); Console.WriteLine("Adding FileConsumer"); FileConsumer consumer = new FileConsumer("nanostream"); nano.AddConsumer(consumer); Console.WriteLine("Initializing AV stream (handshaking)..."); await nano.InitializeStreamAsync(nano.AudioFormats[0], nano.VideoFormats[0]); Console.WriteLine("Starting stream..."); await nano.StartStreamAsync(); } catch (Exception e) { Console.WriteLine($"Failed to initialize gamestream: {e}"); return(CommandResult.RuntimeFailure); } Console.WriteLine("Stream is running"); var loop = new Loop(typeof(SessionCommandType)); loop.Execute(); return(CommandResult.Success); }
static void Main(string[] args) { Native.AllocConsole(); if (args.Length > 0) { Config.CurrentMapping.Init(args); _tokenFilePath = Config.CurrentMapping.TokenFilePath; Authenticate(); } else { _tokenFilePath = Shell.WriteReadLine("tokenFilePath: "); Config.CurrentMapping.TokenFilePath = _tokenFilePath; if (File.Exists(_tokenFilePath)) { Authenticate(); } else { Shell.Warning("\'{0}\' file not found.\n", _tokenFilePath); Shell.WriteLine("1) Open following URL in your WebBrowser:\n\n{0}\n\n" + "2) Authenticate with your Microsoft Account\n" + "3) Paste returned URL from addressbar: \n" , AuthenticationService.GetWindowsLiveAuthenticationUrl()); Authenticate(Shell.WriteReadLine()); } if (Config.CurrentMapping.IP.Length == 0) { Shell.WriteLine("{0,-15} {1,-36} {2,-15} {3,-16}", "Name", "HardwareId", "Address", "LiveId"); IEnumerable <Device> devices = Device.DiscoverAsync().GetAwaiter().GetResult(); foreach (Device device in devices) { Shell.WriteLine("{0,-15} {1,-36} {2,-15} {3,-16}" , device.Name , device.HardwareId , device.Address , device.LiveId); } string ip = Shell.WriteReadLine("Input IP Address or hostname: "); Config.CurrentMapping.Init($"{_tokenFilePath} ${ip}"); } } // Get general gamestream configuration GamestreamConfiguration config = GamestreamConfiguration.GetStandardConfig(); // Modify standard config, if desired /* * GAME_STREAMING_VERY_HIGH_QUALITY_SETTINGS: 12000000,1080,60,59,0,10,40,170 * GAME_STREAMING_HIGH_QUALITY_SETTINGS: 8000000,720,60,59,0,10,40,170 * GAME_STREAMING_MEDIUM_QUALITY_SETTINGS: 6000002,720,60,3600,0,40,70,200 * GAME_STREAMING_LOW_QUALITY_SETTINGS: 3000001,480,30,3600,0,40,70,200 * * 12000000 = 12Mbit/s = 12Mbps * * SETTINGS: * Unknown1,Unknown2,Unknown3,Unknown4,Unknown5,Unknown6,Unknown7,Unknown8 * Unknown1 UrcpMaximumRate FIXME: Or AudioBufferLengthHns, both?? * Unknown2 VideoMaximumHeight * Unknown3 VideoMaximumFrameRate * Unknown4 FIXME: Which is Unknown4? * Unknown5 FIXME: Which is Unknown5? * Unknown6 AudioSyncMinLatency * Unknown7 AudioSyncDesiredLatency * Unknown8 AudioSyncMaxLatency * * refer to: https://github.com/OpenXbox/xbox-smartglass-nano-python/issues/7 * standard: GAME_STREAMING_MEDIUM_QUALITY_SETTINGS */ //config.UrcpMaximumRate = 12000000;// 2后面6个0 //config.VideoMaximumHeight = 480; //config.VideoMaximumFrameRate = 30; //config.Unknown4 = 3600; //config.Unknown5 = 0; //config.AudioSyncMinLatency = 40; //config.AudioSyncDesiredLatency = 70; //config.AudioSyncMaxLatency = 200; config.UrcpMaximumRate = Config.CurrentMapping.Quality.Unknown1; config.VideoMaximumHeight = Config.CurrentMapping.Quality.Unknown2; config.VideoMaximumFrameRate = Config.CurrentMapping.Quality.Unknown3; //config.Unknown4 = Config.CurrentMapping.Quality.Unknown4; //config.Unknown5 = Config.CurrentMapping.Quality.Unknown5; config.AudioSyncMinLatency = Config.CurrentMapping.Quality.Unknown6; config.AudioSyncDesiredLatency = Config.CurrentMapping.Quality.Unknown7; config.AudioSyncMaxLatency = Config.CurrentMapping.Quality.Unknown8; config.VideoMaximumWidth = TVResolution.Width(config.VideoMaximumHeight); Shell.WriteLine("Connecting to {0}...", Config.CurrentMapping.IP); GamestreamSession session = ConnectToConsole(Config.CurrentMapping.IP, config); Shell.WriteLine("Connecting to NANO // TCP: {0}, UDP: {1}", session.TcpPort, session.UdpPort); Nano = new NanoClient(Config.CurrentMapping.IP, session); try { // General Handshaking & Opening channels Shell.WriteLine("Running protocol init..."); Nano.InitializeProtocolAsync().Wait(); // Start Controller input channel Nano.OpenInputChannelAsync(Nano.Video.Width, Nano.Video.Height).Wait(); // Audio & Video client handshaking // Sets desired AV formats AudioFormat = Nano.AudioFormats[0]; VideoFormat = Nano.VideoFormats[0]; Shell.WriteLine("Initializing AV stream (handshaking)..."); Nano.InitializeStreamAsync(AudioFormat, VideoFormat).Wait(); // Start ChatAudio channel // TODO: Send opus audio chat samples to console ChatAudioFormat = new AudioFormat(1, 24000, AudioCodec.Opus); Nano.OpenChatAudioChannelAsync(ChatAudioFormat).Wait(); // Tell console to start sending AV frames Shell.WriteLine("Starting stream..."); Nano.StartStreamAsync().Wait(); Shell.Note("Stream is running"); } catch (Exception e) { throw Shell.Log("Failed to init Nano, error: {e.Message}", e, e.Message); } #if !DEBUG Trace.Listeners.Clear(); Trace.Listeners.Add(new Logger(_tokenFilePath)); Native.FreeConsole(); #endif // Run a mainloop, to gather controller input events or similar Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Xstream()); // finally (dirty) Process.GetCurrentProcess().Kill(); }
static void Main() { AllocConsole(); Console.Write("tokenFilePath: "); string tokenFilePath = Console.ReadLine(); AuthenticationService auth; if (!File.Exists(tokenFilePath)) { Shell.WriteLine("Warning: '{0}' file not found.\n", tokenFilePath); string reqURL = AuthenticationService.GetWindowsLiveAuthenticationUrl(); Console.WriteLine("1) Open following URL in your WebBrowser:\n\n{0}\n\n" + "2) Authenticate with your Microsoft Account\n" + "3) Paste returned URL from addressbar: \n", reqURL); // Call requestUrl via WebWidget or manually and authenticate try { string url = Console.ReadLine(); WindowsLiveResponse rep = AuthenticationService.ParseWindowsLiveResponse(url); auth = new AuthenticationService(rep); auth.Authenticate(); } catch (Exception e) { Shell.WriteLine($"Error: Authentication failed, error: {e.Message}"); Shell.PressAnyKeyToContinue(); return; } Console.WriteLine(auth.XToken); Console.WriteLine(auth.UserInformation); // Save token to JSON FileStream tokenOutputFile = null; try { tokenOutputFile = new FileStream(tokenFilePath, FileMode.Create); } catch (Exception e) { Shell.WriteLine("Error: Failed to open token outputfile \'{0}\', error: {1}", tokenOutputFile, e.Message); Shell.PressAnyKeyToContinue(); return; } auth.DumpToFile(tokenOutputFile); tokenOutputFile.Close(); Console.WriteLine("Storing tokens to file \'{0}\' on successful auth", tokenOutputFile.Name); } else { // Load token from JSON FileStream fs = new FileStream(tokenFilePath, FileMode.Open); auth = AuthenticationService.LoadFromFile(fs); try { auth.Authenticate(); } catch (Exception e) { Shell.WriteLine($"Error: Failed to refresh XBL tokens, error: {e.Message}"); Shell.PressAnyKeyToContinue(); return; } fs.Close(); } UserHash = auth.XToken.UserInformation.Userhash; XToken = auth.XToken.Jwt; Discover().Wait(); Console.Write("Input IP Address or hostname: "); string addressOrHostname = Console.ReadLine(); Console.WriteLine($"Connecting to {addressOrHostname}..."); SmartGlassClient client; try { Task <SmartGlassClient> connect = SmartGlassClient.ConnectAsync( addressOrHostname, UserHash, XToken); // 如果Task失败了GetAwaiter()会直接抛出异常,而Task.Wait()会抛出AggregateException client = connect.GetAwaiter().GetResult(); } catch (Exception e) { if (e is SmartGlassException) { Shell.WriteLine($"Error: Failed to connect: {e.Message}"); } else if (e is TimeoutException) { Shell.WriteLine($"Error: Timeout while connecting: {e.Message}"); } else { Shell.WriteLine($"Error: {e}"); } Shell.PressAnyKeyToContinue(); return; } // Get general gamestream configuration GamestreamConfiguration config = GamestreamConfiguration.GetStandardConfig(); // Modify standard config, if desired GamestreamSession session = client.BroadcastChannel.StartGamestreamAsync(config) .GetAwaiter().GetResult(); Console.WriteLine($"Connecting to NANO // TCP: {session.TcpPort}, UDP: {session.UdpPort}"); Console.WriteLine($"Running protocol init..."); Nano = new NanoClient(addressOrHostname, session); try { // General Handshaking & Opening channels Nano.InitializeProtocolAsync().Wait(); // Start Controller input channel Nano.OpenInputChannelAsync(1280, 720).Wait(); //IConsumer consumer = /* initialize consumer */; //nano.AddConsumer(consumer); // Start consumer, if necessary //consumer.Start(); // Audio & Video client handshaking // Sets desired AV formats Console.WriteLine("Initializing AV stream (handshaking)..."); AudioFormat = Nano.AudioFormats[0]; VideoFormat = Nano.VideoFormats[0]; Nano.InitializeStreamAsync(AudioFormat, VideoFormat).Wait(); // Start ChatAudio channel // TODO: Send opus audio chat samples to console ChatAudioFormat = new AudioFormat(1, 24000, AudioCodec.Opus); Nano.OpenChatAudioChannelAsync(ChatAudioFormat).Wait(); // Tell console to start sending AV frames Console.WriteLine("Starting stream..."); Nano.StartStreamAsync().Wait(); Shell.WriteLine("Note: Stream is running"); } catch (Exception e) { Shell.WriteLine($"Error: Failed to init Nano, error: {e}"); Shell.PressAnyKeyToContinue(); return; } // Run a mainloop, to gather controller input events or similar FreeConsole(); Application.SetHighDpiMode(HighDpiMode.SystemAware); Application.EnableVisualStyles(); Application.SetCompatibleTextRenderingDefault(false); Application.Run(new Xstream()); // finally (dirty) Process.GetCurrentProcess().Kill(); }