/// <summary> /// Initialize the media element for playback /// </summary> /// <param name="streamConfig">Object containing stream configuration details</param> void InitializeMediaPlayer(MoonlightStreamConfiguration streamConfig, AvStreamSource streamSource) { this._streamSource = streamSource; // This code is based upon the MS FFmpegInterop project on GitHub VideoEncodingProperties videoProps = VideoEncodingProperties.CreateH264(); videoProps.ProfileId = H264ProfileIds.High; videoProps.Width = (uint)streamConfig.GetWidth(); videoProps.Height = (uint)streamConfig.GetHeight(); videoProps.Bitrate = (uint)streamConfig.GetBitrate(); _videoMss = new MediaStreamSource(new VideoStreamDescriptor(videoProps)); _videoMss.BufferTime = TimeSpan.Zero; _videoMss.CanSeek = false; _videoMss.Duration = TimeSpan.Zero; _videoMss.SampleRequested += _videoMss_SampleRequested; XAudio2 xaudio = new XAudio2(); MasteringVoice masteringVoice = new MasteringVoice(xaudio, 2, 48000); WaveFormat format = new WaveFormat(48000, 16, 2); // Set for low latency playback StreamDisplay.RealTimePlayback = true; // Render on the full window to avoid extra compositing StreamDisplay.IsFullWindow = true; // Disable built-in transport controls StreamDisplay.AreTransportControlsEnabled = false; StreamDisplay.SetMediaStreamSource(_videoMss); AvStream.SetSourceVoice(new SourceVoice(xaudio, format)); }
/// <summary> /// Create start HTTP request /// </summary> private async Task<bool> StartOrResumeApp(NvHttp nv, MoonlightStreamConfiguration streamConfig) { XmlQuery serverInfo = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId()); string currentGameString = await serverInfo.ReadXmlElement("currentgame"); if (currentGameString == null) { return false; } string versionString = await serverInfo.ReadXmlElement("appversion"); if (versionString == null) { return false; } serverMajorVersion = Convert.ToInt32(versionString.Substring(0, 1)); byte[] aesIv = streamConfig.GetRiAesIv(); int riKeyId = (int)(((aesIv[0] << 24) & 0xFF000000U) | ((aesIv[1] << 16) & 0xFF0000U) | ((aesIv[2] << 8) & 0xFF00U) | (aesIv[3] & 0xFFU)); string riConfigString = "&rikey=" + PairingCryptoHelpers.BytesToHex(streamConfig.GetRiAesKey()) + "&rikeyid=" + riKeyId; // Launch a new game if nothing is running if (currentGameString == null || currentGameString.Equals("0")) { XmlQuery x = new XmlQuery(nv.BaseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + context.appId + "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() + "&additionalStates=1&sops=1" + // FIXME: make sops configurable riConfigString); string sessionStr = await x.ReadXmlElement("gamesession"); if (sessionStr == null || sessionStr.Equals("0")) { return false; } return true; } else { // A game was already running, so resume it // FIXME: Quit and relaunch if it's not the game we came to start XmlQuery x = new XmlQuery(nv.BaseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString); string resumeStr = await x.ReadXmlElement("resume"); if (resumeStr == null || resumeStr.Equals("0")) { return false; } return true; } }
/// <summary> /// Create start HTTP request /// </summary> private async Task <bool> StartOrResumeApp(NvHttp nv, MoonlightStreamConfiguration streamConfig) { XmlQuery serverInfo = new XmlQuery(nv.BaseUrl + "/serverinfo?uniqueid=" + nv.GetUniqueId()); string currentGameString = await serverInfo.ReadXmlElement("currentgame"); if (currentGameString == null) { return(false); } string versionString = await serverInfo.ReadXmlElement("appversion"); if (versionString == null) { return(false); } serverMajorVersion = Convert.ToInt32(versionString.Substring(0, 1)); byte[] aesIv = streamConfig.GetRiAesIv(); int riKeyId = (int)(((aesIv[0] << 24) & 0xFF000000U) | ((aesIv[1] << 16) & 0xFF0000U) | ((aesIv[2] << 8) & 0xFF00U) | (aesIv[3] & 0xFFU)); string riConfigString = "&rikey=" + PairingCryptoHelpers.BytesToHex(streamConfig.GetRiAesKey()) + "&rikeyid=" + riKeyId; // Launch a new game if nothing is running if (currentGameString == null || currentGameString.Equals("0")) { XmlQuery x = new XmlQuery(nv.BaseUrl + "/launch?uniqueid=" + nv.GetUniqueId() + "&appid=" + context.appId + "&mode=" + streamConfig.GetWidth() + "x" + streamConfig.GetHeight() + "x" + streamConfig.GetFps() + "&additionalStates=1&sops=1" + // FIXME: make sops configurable riConfigString); string sessionStr = await x.ReadXmlElement("gamesession"); if (sessionStr == null || sessionStr.Equals("0")) { return(false); } return(true); } else { // A game was already running, so resume it // FIXME: Quit and relaunch if it's not the game we came to start XmlQuery x = new XmlQuery(nv.BaseUrl + "/resume?uniqueid=" + nv.GetUniqueId() + riConfigString); string resumeStr = await x.ReadXmlElement("resume"); if (resumeStr == null || resumeStr.Equals("0")) { return(false); } return(true); } }