/// <summary> /// Pair with the hostname in the textbox /// </summary> public async Task Pair(Computer c) { Debug.WriteLine("Pairing "); // Create NvHttp object with the user input as the URL try { nv = new NvHttp(c.IpAddress); } catch (Exception) { var dialog = new MessageDialog("Invalid Hostname", "Pairing Failed"); dialog.ShowAsync(); return; } // Get the server IP address try { await nv.ServerIPAddress(); } catch (Exception e) { var dialog = new MessageDialog("Error resolving hostname " + e.Message , "Pairing Failed"); dialog.ShowAsync(); return; } // "Please don't do this ever, but it's only okay because Cameron said so" -Cameron Gutman getClientCertificate(); // Get the pair state. bool? pairState = await QueryPairState(); if (pairState == true) { var dialog = new MessageDialog("This device is already paired to the host PC", "Already Paired"); dialog.ShowAsync(); Debug.WriteLine("Already paired"); return; } // pairstate = null. We've encountered an error else if (!pairState.HasValue) { var dialog = new MessageDialog("Failed to query pair state", "Pairing failed"); dialog.ShowAsync(); Debug.WriteLine("Query pair state failed"); return; } bool challenge = await Challenges(nv.GetUniqueId()); if (!challenge) { Debug.WriteLine("Challenges failed"); return; } // Otherwise, everything was successful MainPage.SaveComputer(c); var successDialog = new MessageDialog("Pairing successful", "Success"); await successDialog.ShowAsync(); }
/// <summary> /// When the user presses "Start Streaming Steam", first check that they are paired /// </summary> private async Task StreamSetup(Computer computer) { // Resolve the hostname try { nv = new NvHttp(computer.IpAddress); } catch (Exception) { StreamSetupFailed("Invalid Hostname"); return; } // Get the Ip address of the streaming machine try { await nv.ServerIPAddress(); } catch (Exception) { StreamSetupFailed("Unable to get streaming machine's IP addresss"); return; } Pairing p = new Pairing(nv); // HACK: Preload the cert data p.getClientCertificate(); // If we can't get the pair state, return bool? pairState = await p.QueryPairState(); if (!pairState.HasValue) { await StreamSetupFailed("Pair state query failed"); return; } // If we're not paired, return if (pairState == false) { await StreamSetupFailed("Device not paired"); return; } // If we haven't cancelled and don't have the steam ID, query app list to get it if (computer.steamID == 0) { // If queryAppList fails, return computer.steamID = await Task.Run(() => QueryAppList()); if (computer.steamID == 0) { await StreamSetupFailed("App list query failed"); return; } } await StreamSetupComplete(); }
/// <summary> /// Uses mDNS to enumerate the machines on the network eligible to stream from /// </summary> /// <returns></returns> private async Task EnumerateEligibleMachines() { // TODO save previous machines you've connected to // Make a local copy of the computer list // The UI thread will populate the listbox with computerList whenever it pleases, so we don't want it to take the one we're modifying List<Computer> computerListLocal = new List<Computer>(computerList); // Ignore all computers we may have found in the past computerListLocal.Clear(); Debug.WriteLine("Enumerating machines..."); // If there's no network, save time and don't do the time-consuming mDNS if (!InternetAvailable) { Debug.WriteLine("Network not available - skipping mDNS"); } else { // Let Zeroconf do its magic and find everything it can with mDNS ILookup<string, string> domains = null; try { domains = await ZeroconfResolver.BrowseDomainsAsync(); } catch (Exception e) { Debug.WriteLine("Browse Domains Async threw exception: " + e.Message); } IReadOnlyList<IZeroconfHost> responses = null; try { responses = await ZeroconfResolver.ResolveAsync(domains.Select(g => g.Key)); } catch (Exception e) { Debug.WriteLine("Exception in ZeroconfResolver.ResolverAsyc (Expected if BrowseDomainsAsync excepted): " + e.Message); } if (responses != null) { // Go through every response we received and grab only the ones running nvstream foreach (var resp in responses) { if (resp.Services.ContainsKey("_nvstream._tcp.local.")) { Computer toAdd = new Computer(resp.DisplayName, resp.IPAddress); // If we don't have the computer already, add it if (!computerListLocal.Exists(x => x.IpAddress == resp.IPAddress)) { computerListLocal.Add(toAdd); Debug.WriteLine(resp); } } } } } // We're done messing with the list - it's okay for the UI thread to update it now Computer last = LoadComputer(); if (last != null) {// If we don't have the computer already, add it if (!computerListLocal.Exists(x => x.IpAddress == last.IpAddress)) { computerListLocal.Add(last); } } computerList = computerListLocal; if (computerList.Count == 0) { computerPicker.PlaceholderText = "No computers found"; } else if (computerList.Count == 1) { computerPicker.PlaceholderText = "1 computer found..."; } else { computerPicker.PlaceholderText = computerList.Count + " computers found..."; } }
/// <summary> /// Once we freshly pair to a computer, save it /// </summary> /// <param name="c">Computer we've paired to</param> public static void SaveComputer(Computer c) { var settings = ApplicationData.Current.RoamingSettings; settings.Values["computerName"] = c.Name; settings.Values["computerIP"] = c.IpAddress; }
/// <summary> /// Executed when the user presses "Start Streaming Steam!" /// </summary> private async void StreamButton_Click(object sender, RoutedEventArgs e) { Debug.WriteLine("Start Streaming button pressed"); // Stop enumerating machines while we're trying to check pair state mDnsTimer.Stop(); SaveSettings(); // Don't let the user mash the buttons // TODO use a spinner to avoid the appearance of the app being unresponsive PairButton.IsEnabled = false; StreamButton.IsEnabled = false; _60fps_button.IsEnabled = false; _30fps_button.IsEnabled = false; _720p_button.IsEnabled = false; _1080p_button.IsEnabled = false; status_text.Text = "Checking pair state..."; selected = (Computer)computerPicker.SelectedItem; // User hasn't selected a machine if (selected == null) { var dialog = new MessageDialog("No machine selected", "Streaming Failed"); await dialog.ShowAsync(); status_text.Text = ""; } else { await StreamSetup(selected); status_text.Text = ""; } // User can use the buttons again PairButton.IsEnabled = true; StreamButton.IsEnabled = true; _60fps_button.IsEnabled = true; _30fps_button.IsEnabled = true; _720p_button.IsEnabled = true; _1080p_button.IsEnabled = true; }
/// <summary> /// Get the computer information passed from the previous page /// </summary> protected override void OnNavigatedTo(NavigationEventArgs e) { // We only want to stream in landscape DisplayInformation.AutoRotationPreferences = DisplayOrientations.Landscape; selected = (Computer)e.Parameter; Window.Current.CoreWindow.KeyDown += WindowKeyDownHandler; Window.Current.CoreWindow.KeyUp += WindowKeyUpHandler; }
/// <summary> /// Uses mDNS to enumerate the machines on the network eligible to stream from /// </summary> /// <returns></returns> private async Task EnumerateEligibleMachines() { // TODO save previous machines you've connected to // Make a local copy of the computer list // The UI thread will populate the listbox with computerList whenever it pleases, so we don't want it to take the one we're modifying List <Computer> computerListLocal = new List <Computer>(computerList); // Ignore all computers we may have found in the past computerListLocal.Clear(); Debug.WriteLine("Enumerating machines..."); // If there's no network, save time and don't do the time-consuming mDNS if (!InternetAvailable) { Debug.WriteLine("Network not available - skipping mDNS"); } else { // Let Zeroconf do its magic and find everything it can with mDNS ILookup <string, string> domains = null; try { domains = await ZeroconfResolver.BrowseDomainsAsync(); } catch (Exception e) { Debug.WriteLine("Browse Domains Async threw exception: " + e.Message); } IReadOnlyList <IZeroconfHost> responses = null; try { responses = await ZeroconfResolver.ResolveAsync(domains.Select(g => g.Key)); } catch (Exception e) { Debug.WriteLine("Exception in ZeroconfResolver.ResolverAsyc (Expected if BrowseDomainsAsync excepted): " + e.Message); } if (responses != null) { // Go through every response we received and grab only the ones running nvstream foreach (var resp in responses) { if (resp.Services.ContainsKey("_nvstream._tcp.local.")) { Computer toAdd = new Computer(resp.DisplayName, resp.IPAddress, steamId); // If we don't have the computer already, add it if (!computerListLocal.Exists(x => x.IpAddress == resp.IPAddress)) { computerListLocal.Add(toAdd); Debug.WriteLine(resp); } } } } } // We're done messing with the list - it's okay for the UI thread to update it now computerList = computerListLocal; if (computerList.Count == 0) { computerPicker.PlaceholderText = "No computers found"; } else if (computerList.Count == 1) { computerPicker.PlaceholderText = "1 computer found..."; } else { computerPicker.PlaceholderText = computerList.Count + " computers found..."; } }