/// <summary> /// Create start HTTP request /// </summary> private XmlQuery StartOrResumeApp(NvHttp nv, LimelightStreamConfiguration streamConfig) { XmlQuery serverInfo = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId()); string currentGameString = serverInfo.XmlAttribute("currentgame"); byte[] aesIv = streamConfig.GetRiAesIv(); int riKeyId = (int)(((aesIv[0] << 24) & 0xFF000000) | ((aesIv[1] << 16) & 0xFF0000) | ((aesIv[2] << 8) & 0xFF00) | (aesIv[3] & 0xFF)); string riConfigString = "&rikey=" + Pairing.bytesToHex(streamConfig.GetRiAesKey()) + "&rikeyid=" + riKeyId; // Launch a new game if nothing is running if (currentGameString == null || currentGameString.Equals("0")) { return(new XmlQuery(nv.BaseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + selected.steamID + "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() + "&additionalStates=1&sops=1" + // FIXME: make sops configurable riConfigString)); } else { // A game was already running, so resume it // FIXME: Quit and relaunch if it's not the game we came to start return(new XmlQuery(nv.BaseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString)); } }
/// <summary> /// Executed when the user presses "Pair" /// </summary> private async void PairButton_Click(object sender, RoutedEventArgs e) { Computer selected = (Computer)computerPicker.SelectedItem; // User hasn't selected anything if (selected == null) { var dialog = new MessageDialog("No machine selected", "Pairing Failed"); await dialog.ShowAsync(); status_text.Text = ""; return; } nv = new NvHttp(selected.IpAddress); Pairing p = new Pairing(nv); // Stop polling timer while we're pairing mDnsTimer.Stop(); SaveSettings(); await p.Pair(selected); mDnsTimer.Stop(); }
/// <summary> /// Event handler for page loaded event /// </summary> private async void Loaded(object sender, RoutedEventArgs e) { StreamDisplay.Visibility = Visibility.Visible; Waitgrid.Visibility = Visibility.Collapsed; currentStateText.Visibility = Visibility.Collapsed; // Hide the status bar //var statusBar = Windows.UI.ViewManagement.StatusBar.GetForCurrentView(); //await statusBar.HideAsync(); LimelightStreamConfiguration config; byte[] aesKey = Pairing.GenerateRandomBytes(16); // GameStream only uses 4 bytes of a 16 byte IV. Go figure. byte[] aesRiIndex = Pairing.GenerateRandomBytes(4); byte[] aesIv = new byte[16]; Array.ConstrainedCopy(aesRiIndex, 0, aesIv, 0, aesRiIndex.Length); config = new LimelightStreamConfiguration(selected.pixels * (16 / 9), selected.pixels, selected.fps, 5000, 1024, aesKey, aesIv); InitializeMediaPlayer(config, AvStream); //H264FileReaderHackery h = new H264FileReaderHackery(); //Task.Run(() => h.readFile(this)); await StartConnection(config); }
/// <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) { StreamSetupFailed("Pair state query failed"); return; } // If we're not paired, return if (pairState == false) { 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) { StreamSetupFailed("App list query failed"); return; } } StreamSetupComplete(); }
/// <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(); }
/// Get the local device's name /// </summary> /// <returns>Unique ID for the device</returns> public String GetUniqueId() { var token = HardwareIdentification.GetPackageSpecificToken(null); var hardwareId = token.Id; var dataReader = Windows.Storage.Streams.DataReader.FromBuffer(hardwareId); byte[] bytes = new byte[8]; dataReader.ReadBytes(bytes); return(Pairing.bytesToHex(bytes)); }