/// <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; } }
/// <summary>Background decode thread</summary> private void DecodeThread() { XmlElement rtt; bool elementsFound = false; int interval = 0; DelayCalculator delayCalculator = new DelayCalculator(); while (true) { lock (rttElementQueue) { if (!enableThread) { break; } elementsFound = (rttElementQueue.Count > 0); if (elementsFound) { // Start the delay calculator on the moment of the first RTT element received into empty queue if (!delayCalculator.IsRunning) { delayCalculator.Start(); } // Loop to decode RTT elements while (enableThread && (rttElementQueue.Count > 0)) { rtt = rttElementQueue[0]; RealTimeText.DecodeRawRTT(rtt, message); if (!rtt.HasChildNodes) { rttElementQueue.RemoveAt(0); } if (message.CurrentKeyInterval != 0) { interval = message.CurrentKeyInterval; break; } } } if (!enableThread) { break; } } // (MUST be outside 'lock' section) Calls the user-defined event for one step of text decode if (elementsFound && (TextUpdated != null)) { TextUpdated(this); } if (interval > 0) { // Calculate the delay interval and then sleep for that interval if needed. // IMPORTANT: This SAVES BATTERY on mobile devices! (avoids unnecessary processing) interval = delayCalculator.GetCompensatedDelay(interval); if (interval > 0) { Thread.Sleep(interval); } interval = 0; } else { // Zero interval. Stop the delay calculator, and suspend this thread until the next RTT element // IMPORTANT: This also SAVES BATTERY on mobile devices! (turns off unnecessary timers when idling with no typing going on) delayCalculator.Stop(); rttElementEvent.WaitOne(IDLE_THREAD_QUIT_INTERVAL); rttElementEvent.Reset(); // Exit thread if we've waited long enough with no elements arrived. Thread will restart automatically. // This saves system resources (and battery life on mobiles) if there's lots of chat windows. lock (rttElementQueue) { if (rttElementQueue.Count == 0) { enableThread = false; break; } } } } Debug.Write("STOPPING rtt decoder thread\n"); }