/// <summary>Returns the current RTT encoding as an XML element, and then immediately starts a new RTT fragment</summary> public XmlElement GetEncodedRTT() { XmlElement rttEncoded = rtt; rttEncoded.SetAttribute("xmlns", RealTimeText.NAMESPACE); if (newMsg) { // The first RTT element of a new message always has event='new' // (i.e. This rtt element contains the first character of real time text) rttEncoded.SetAttribute("event", "new"); newMsg = false; seq = (uint)random.Next(1000000); // Generates up to a 6-digit random number. XEP-0301 recommends randomization, and keeping numbers compact for bandwidth savings if (redundancy) { redundancyClock.Reset(); redundancyClock.Start(); } } else { // Error recovery/fault tolerance: Automatic retransmission if (redundancy && (redundancyClock.ElapsedMilliseconds > redundancyInterval)) { fullMessageTransmit = true; redundancyClock.Reset(); redundancyClock.Start(); } // Automatic and/or manually forced message retransmission if (fullMessageTransmit) { rttEncoded.SetAttribute("event", "reset"); if ((messagePrevious.CursorPos != -1) && (messagePrevious.CursorPos != messagePrevious.Text.Length)) { // For clients supporting an optional remote cursor position, a blank INSERT TEXT <t/> elements sets the cursor position. XmlElement resetPos = rttEncoded.OwnerDocument.CreateElement("t"); resetPos.SetAttribute("p", messagePrevious.CursorPos.ToString()); rtt.PrependChild(resetPos); } if (messagePrevious.Text.Length > 0) { // Retransmission of full message text in an INSERT TEXT <t/> element. XmlElement resetText = rttEncoded.OwnerDocument.CreateElement("t"); resetText.InnerText = messagePrevious.Text; rtt.PrependChild(resetText); } } } rttEncoded.SetAttribute("seq", seq.ToString()); seq++; fullMessageTransmit = false; messagePrevious = message.Clone(); // Create new RTT element for next message. rtt = doc.CreateElement(RealTimeText.ROOT); if (DEBUG_CONSOLE_XML) Console.WriteLine("outgoing rtt: " + rttEncoded.OuterXml.ToString()); return rttEncoded; }
/// <summary>Encodes RTT fragment for the specified text. This encoder compares this text to the previous state of text, and generates a compact RTT code for this text</summary> /// <param name="text">Current state of message text</param> /// <param name="cursorPos">Current position index within text, for optional remote cursor</param> public void Encode(string text, int cursorPos) { if (text == null) text = message.Text; bool textChanged = (text != message.Text); bool posChanged = (cursorPos != -1) && (cursorPos != message.CursorPos); if (textChanged || posChanged) { // If necessary, generate the 'w' interval action element if (message.KeyIntervalsEnabled) { if (!rtt.HasChildNodes) delayCalculator.Start(); // Delay calculator starts on first rtt element. int milliseconds = delayCalculator.GetMillisecondsSinceLastCall(); if (milliseconds > 0) { if (milliseconds > transmitInterval) milliseconds = transmitInterval; // Limit delays to maximum interval. RealTimeText.AppendElement.WaitInterval(rtt, milliseconds); } } // Encode the text differences since last message, into action elements. RealTimeText.Message newMessage = new RealTimeText.Message(text, cursorPos); RealTimeText.EncodeRawRTT(rtt, message, newMessage); message.Text = text; message.CursorPos = cursorPos; } }