diff options
Diffstat (limited to 'OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs')
-rw-r--r-- | OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs | 455 |
1 files changed, 230 insertions, 225 deletions
diff --git a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs index 638c765..5f549b5 100644 --- a/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs +++ b/OpenSim/Region/ClientStack/LindenUDP/J2KImage.cs | |||
@@ -38,40 +38,37 @@ using System.Reflection; | |||
38 | namespace OpenSim.Region.ClientStack.LindenUDP | 38 | namespace OpenSim.Region.ClientStack.LindenUDP |
39 | { | 39 | { |
40 | /// <summary> | 40 | /// <summary> |
41 | /// We use this class to store image data and associated request data and attributes | 41 | /// Stores information about a current texture download and a reference to the texture asset |
42 | /// </summary> | 42 | /// </summary> |
43 | public class J2KImage | 43 | public class J2KImage |
44 | { | 44 | { |
45 | private const int IMAGE_PACKET_SIZE = 1000; | ||
46 | private const int FIRST_PACKET_SIZE = 600; | ||
47 | |||
45 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); | 48 | private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); |
46 | 49 | ||
47 | public double m_designatedPriorityKey; | 50 | public uint m_lastSequence; |
48 | public double m_requestedPriority = 0.0d; | 51 | public float m_requestedPriority; |
49 | public uint m_lastSequence = 0; | ||
50 | public uint m_requestedPacketNumber; | 52 | public uint m_requestedPacketNumber; |
51 | public sbyte m_requestedDiscardLevel; | 53 | public sbyte m_requestedDiscardLevel; |
52 | public UUID m_requestedUUID; | 54 | public UUID m_requestedUUID; |
53 | public IJ2KDecoder m_j2kDecodeModule; | 55 | public IJ2KDecoder m_j2kDecodeModule; |
54 | public IAssetService m_assetCache; | 56 | public IAssetService m_assetCache; |
55 | public OpenJPEG.J2KLayerInfo[] Layers = new OpenJPEG.J2KLayerInfo[0]; | 57 | public OpenJPEG.J2KLayerInfo[] m_layers; |
56 | public AssetBase m_MissingSubstitute = null; | 58 | public bool m_decoded; |
57 | public bool m_decoded = false; | 59 | public bool m_hasasset; |
58 | public bool m_completedSendAtCurrentDiscardLevel; | 60 | public C5.IPriorityQueueHandle<J2KImage> m_priorityQueueHandle; |
59 | 61 | ||
60 | private sbyte m_discardLevel=-1; | ||
61 | private uint m_packetNumber; | 62 | private uint m_packetNumber; |
62 | private bool m_decoderequested = false; | 63 | private bool m_decoderequested; |
63 | private bool m_hasasset = false; | 64 | private bool m_asset_requested; |
64 | private bool m_asset_requested = false; | 65 | private bool m_sentinfo; |
65 | private bool m_sentinfo = false; | 66 | private uint m_stopPacket; |
66 | private uint m_stopPacket = 0; | 67 | private AssetBase m_asset; |
67 | private const int cImagePacketSize = 1000; | 68 | private int m_assetDataLength; |
68 | private const int cFirstPacketSize = 600; | 69 | private LLImageManager m_imageManager; |
69 | private AssetBase m_asset = null; | 70 | |
70 | private LLImageManager m_image; | 71 | #region Properties |
71 | public J2KImage(LLImageManager image) | ||
72 | { | ||
73 | m_image = image; | ||
74 | } | ||
75 | 72 | ||
76 | public uint m_pPacketNumber | 73 | public uint m_pPacketNumber |
77 | { | 74 | { |
@@ -84,10 +81,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
84 | 81 | ||
85 | public byte[] Data | 82 | public byte[] Data |
86 | { | 83 | { |
87 | get | 84 | get |
88 | { | 85 | { |
89 | if (m_asset != null) | 86 | if (m_asset != null) |
90 | return m_asset.Data; | 87 | return m_asset.Data; |
91 | else | 88 | else |
92 | return null; | 89 | return null; |
93 | } | 90 | } |
@@ -97,9 +94,10 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
97 | { | 94 | { |
98 | if (!m_decoded) | 95 | if (!m_decoded) |
99 | return 0; | 96 | return 0; |
97 | |||
100 | try | 98 | try |
101 | { | 99 | { |
102 | return (ushort)(((m_asset.Data.Length - cFirstPacketSize + cImagePacketSize - 1) / cImagePacketSize) + 1); | 100 | return (ushort)(((m_assetDataLength - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1); |
103 | } | 101 | } |
104 | catch (Exception) | 102 | catch (Exception) |
105 | { | 103 | { |
@@ -110,119 +108,154 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
110 | } | 108 | } |
111 | } | 109 | } |
112 | 110 | ||
113 | public void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) | 111 | #endregion Properties |
114 | { | ||
115 | m_image.m_outstandingtextures++; | ||
116 | Layers = layers; | ||
117 | m_decoded = true; | ||
118 | RunUpdate(); | ||
119 | } | ||
120 | 112 | ||
121 | public void AssetDataCallback(UUID AssetID, AssetBase asset) | 113 | public J2KImage(LLImageManager imageManager) |
122 | { | 114 | { |
123 | m_hasasset = true; | 115 | m_imageManager = imageManager; |
124 | if (asset == null || asset.Data == null) | ||
125 | { | ||
126 | m_asset = m_MissingSubstitute; | ||
127 | } | ||
128 | else | ||
129 | { | ||
130 | m_asset = asset; | ||
131 | } | ||
132 | RunUpdate(); | ||
133 | } | 116 | } |
134 | 117 | ||
135 | protected void AssetReceived(string id, Object sender, AssetBase asset) | 118 | public bool SendPackets(LLClientView client, int maxpack) |
136 | { | 119 | { |
137 | UUID assetID = UUID.Zero; | 120 | if (m_packetNumber <= m_stopPacket) |
138 | if (asset != null) | 121 | { |
139 | assetID = asset.FullID; | 122 | bool SendMore = true; |
140 | 123 | if (!m_sentinfo || (m_packetNumber == 0)) | |
141 | AssetDataCallback(assetID, asset); | 124 | { |
142 | 125 | if (SendFirstPacket(client)) | |
143 | } | 126 | { |
127 | SendMore = false; | ||
128 | } | ||
129 | m_sentinfo = true; | ||
130 | m_packetNumber++; | ||
131 | } | ||
132 | // bool ignoreStop = false; | ||
133 | if (m_packetNumber < 2) | ||
134 | { | ||
135 | m_packetNumber = 2; | ||
136 | } | ||
144 | 137 | ||
145 | private int GetPacketForBytePosition(int bytePosition) | 138 | int count = 0; |
146 | { | 139 | while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket) |
147 | return ((bytePosition - cFirstPacketSize + cImagePacketSize - 1) / cImagePacketSize) + 1; | 140 | { |
148 | } | 141 | count++; |
142 | SendMore = SendPacket(client); | ||
143 | m_packetNumber++; | ||
144 | } | ||
149 | 145 | ||
150 | public int LastPacketSize() | 146 | if (m_packetNumber > m_stopPacket) |
151 | { | 147 | return true; |
152 | if (m_packetNumber == 1) | ||
153 | return m_asset.Data.Length; | ||
154 | int lastsize = (m_asset.Data.Length - cFirstPacketSize) % cImagePacketSize; | ||
155 | //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary | ||
156 | if (lastsize == 0) | ||
157 | { | ||
158 | lastsize = cImagePacketSize; | ||
159 | } | 148 | } |
160 | return lastsize; | ||
161 | } | ||
162 | |||
163 | public int CurrentBytePosition() | ||
164 | { | ||
165 | if (m_packetNumber == 0) | ||
166 | return 0; | ||
167 | if (m_packetNumber == 1) | ||
168 | return cFirstPacketSize; | ||
169 | 149 | ||
170 | int result = cFirstPacketSize + ((int)m_packetNumber - 2) * cImagePacketSize; | 150 | return false; |
171 | if (result < 0) | ||
172 | { | ||
173 | result = cFirstPacketSize; | ||
174 | } | ||
175 | return result; | ||
176 | } | 151 | } |
177 | 152 | ||
178 | public bool SendFirstPacket(LLClientView client) | 153 | public void RunUpdate() |
179 | { | 154 | { |
180 | // this means we don't have | 155 | //This is where we decide what we need to update |
181 | if (Data == null) | 156 | //and assign the real discardLevel and packetNumber |
182 | { | 157 | //assuming of course that the connected client might be bonkers |
183 | client.SendImageNotFound(m_requestedUUID); | 158 | |
184 | m_log.WarnFormat("[TEXTURE]: Got null Data element on a asset {0}.. and the missing image Data property is al", m_requestedUUID); | 159 | if (!m_hasasset) |
185 | return true; | ||
186 | } | ||
187 | // Do we have less then 1 packet's worth of data? | ||
188 | else if (m_asset.Data.Length <= cFirstPacketSize) | ||
189 | { | 160 | { |
190 | // Send only 1 packet | 161 | if (!m_asset_requested) |
191 | client.SendImageFirstPart(1, m_requestedUUID, (uint)m_asset.Data.Length, m_asset.Data, 2); | 162 | { |
192 | m_stopPacket = 0; | 163 | m_asset_requested = true; |
193 | return true; | 164 | m_assetCache.Get(m_requestedUUID.ToString(), this, AssetReceived); |
165 | } | ||
194 | } | 166 | } |
195 | else | 167 | else |
196 | { | 168 | { |
197 | byte[] firstImageData = new byte[cFirstPacketSize]; | 169 | if (!m_decoded) |
198 | try | 170 | { |
199 | { | 171 | //We need to decode the requested image first |
200 | Buffer.BlockCopy(m_asset.Data, 0, firstImageData, 0, (int)cFirstPacketSize); | 172 | if (!m_decoderequested) |
201 | client.SendImageFirstPart(TexturePacketCount(), m_requestedUUID, (uint)m_asset.Data.Length, firstImageData, 2); | 173 | { |
174 | //Request decode | ||
175 | m_decoderequested = true; | ||
176 | // Do we have a jpeg decoder? | ||
177 | if (m_j2kDecodeModule != null) | ||
178 | { | ||
179 | if (Data == null) | ||
180 | { | ||
181 | J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]); | ||
182 | } | ||
183 | else | ||
184 | { | ||
185 | // Send it off to the jpeg decoder | ||
186 | m_j2kDecodeModule.BeginDecode(m_requestedUUID, Data, J2KDecodedCallback); | ||
187 | } | ||
188 | |||
189 | } | ||
190 | else | ||
191 | { | ||
192 | J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]); | ||
193 | } | ||
194 | } | ||
202 | } | 195 | } |
203 | catch (Exception) | 196 | else |
204 | { | 197 | { |
205 | m_log.Error("Texture block copy failed. Possibly out of memory?"); | 198 | // Check for missing image asset data |
206 | return true; | 199 | if (m_asset == null || m_asset.Data == null) |
200 | { | ||
201 | // FIXME: | ||
202 | m_packetNumber = m_stopPacket; | ||
203 | return; | ||
204 | } | ||
205 | |||
206 | if (m_requestedDiscardLevel >= 0 || m_stopPacket == 0) | ||
207 | { | ||
208 | int maxDiscardLevel = Math.Max(0, m_layers.Length - 1); | ||
209 | |||
210 | // Treat initial texture downloads with a DiscardLevel of -1 a request for the highest DiscardLevel | ||
211 | if (m_requestedDiscardLevel < 0 && m_stopPacket == 0) | ||
212 | m_requestedDiscardLevel = (sbyte)maxDiscardLevel; | ||
213 | |||
214 | // Clamp at the highest discard level | ||
215 | m_requestedDiscardLevel = (sbyte)Math.Min(m_requestedDiscardLevel, maxDiscardLevel); | ||
216 | |||
217 | //Calculate the m_stopPacket | ||
218 | if (m_layers.Length > 0) | ||
219 | { | ||
220 | m_stopPacket = (uint)GetPacketForBytePosition(m_layers[(m_layers.Length - 1) - m_requestedDiscardLevel].End); | ||
221 | //I don't know why, but the viewer seems to expect the final packet if the file | ||
222 | //is just one packet bigger. | ||
223 | if (TexturePacketCount() == m_stopPacket + 1) | ||
224 | { | ||
225 | m_stopPacket = TexturePacketCount(); | ||
226 | } | ||
227 | } | ||
228 | else | ||
229 | { | ||
230 | m_stopPacket = TexturePacketCount(); | ||
231 | } | ||
232 | |||
233 | m_packetNumber = m_requestedPacketNumber; | ||
234 | } | ||
235 | |||
236 | if (m_imageManager.Client.PacketHandler.GetQueueCount(ThrottleOutPacketType.Texture) == 0) | ||
237 | { | ||
238 | //m_log.Debug("No textures queued, sending one packet to kickstart it"); | ||
239 | SendPacket(m_imageManager.Client); | ||
240 | } | ||
207 | } | 241 | } |
208 | } | 242 | } |
209 | return false; | ||
210 | } | 243 | } |
211 | 244 | ||
212 | private bool SendPacket(LLClientView client) | 245 | private bool SendPacket(LLClientView client) |
213 | { | 246 | { |
214 | bool complete = false; | 247 | bool complete = false; |
215 | int imagePacketSize = ((int)m_packetNumber == (TexturePacketCount())) ? LastPacketSize() : cImagePacketSize; | 248 | int imagePacketSize = ((int)m_packetNumber == (TexturePacketCount())) ? LastPacketSize() : IMAGE_PACKET_SIZE; |
216 | 249 | ||
217 | try | 250 | try |
218 | { | 251 | { |
219 | if ((CurrentBytePosition() + cImagePacketSize) > m_asset.Data.Length) | 252 | if ((CurrentBytePosition() + IMAGE_PACKET_SIZE) > m_assetDataLength) |
220 | { | 253 | { |
221 | imagePacketSize = LastPacketSize(); | 254 | imagePacketSize = LastPacketSize(); |
222 | complete=true; | 255 | complete = true; |
223 | if ((CurrentBytePosition() + imagePacketSize) > m_asset.Data.Length) | 256 | if ((CurrentBytePosition() + imagePacketSize) > m_assetDataLength) |
224 | { | 257 | { |
225 | imagePacketSize = m_asset.Data.Length - CurrentBytePosition(); | 258 | imagePacketSize = m_assetDataLength - CurrentBytePosition(); |
226 | complete = true; | 259 | complete = true; |
227 | } | 260 | } |
228 | } | 261 | } |
@@ -244,7 +277,7 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
244 | } | 277 | } |
245 | 278 | ||
246 | //Send the packet | 279 | //Send the packet |
247 | client.SendImageNextPart((ushort)(m_packetNumber-1), m_requestedUUID, imageData); | 280 | client.SendImageNextPart((ushort)(m_packetNumber - 1), m_requestedUUID, imageData); |
248 | } | 281 | } |
249 | if (complete) | 282 | if (complete) |
250 | { | 283 | { |
@@ -260,143 +293,115 @@ namespace OpenSim.Region.ClientStack.LindenUDP | |||
260 | return false; | 293 | return false; |
261 | } | 294 | } |
262 | } | 295 | } |
263 | public bool SendPackets(LLClientView client, int maxpack) | 296 | |
297 | private int GetPacketForBytePosition(int bytePosition) | ||
264 | { | 298 | { |
299 | return ((bytePosition - FIRST_PACKET_SIZE + IMAGE_PACKET_SIZE - 1) / IMAGE_PACKET_SIZE) + 1; | ||
300 | } | ||
265 | 301 | ||
266 | if (!m_completedSendAtCurrentDiscardLevel) | 302 | private int LastPacketSize() |
303 | { | ||
304 | if (m_packetNumber == 1) | ||
305 | return m_assetDataLength; | ||
306 | int lastsize = (m_assetDataLength - FIRST_PACKET_SIZE) % IMAGE_PACKET_SIZE; | ||
307 | //If the last packet size is zero, it's really cImagePacketSize, it sits on the boundary | ||
308 | if (lastsize == 0) | ||
267 | { | 309 | { |
268 | if (m_packetNumber <= m_stopPacket) | 310 | lastsize = IMAGE_PACKET_SIZE; |
269 | { | 311 | } |
270 | bool SendMore = true; | 312 | return lastsize; |
271 | if (!m_sentinfo || (m_packetNumber == 0)) | 313 | } |
272 | { | ||
273 | if (SendFirstPacket(client)) | ||
274 | { | ||
275 | SendMore = false; | ||
276 | } | ||
277 | m_sentinfo = true; | ||
278 | m_packetNumber++; | ||
279 | } | ||
280 | // bool ignoreStop = false; | ||
281 | if (m_packetNumber < 2) | ||
282 | { | ||
283 | m_packetNumber = 2; | ||
284 | } | ||
285 | 314 | ||
286 | int count = 0; | 315 | private int CurrentBytePosition() |
287 | while (SendMore && count < maxpack && m_packetNumber <= m_stopPacket) | 316 | { |
288 | { | 317 | if (m_packetNumber == 0) |
289 | count++; | 318 | return 0; |
290 | SendMore = SendPacket(client); | 319 | if (m_packetNumber == 1) |
291 | m_packetNumber++; | 320 | return FIRST_PACKET_SIZE; |
292 | } | ||
293 | 321 | ||
294 | if (m_packetNumber > m_stopPacket) | 322 | int result = FIRST_PACKET_SIZE + ((int)m_packetNumber - 2) * IMAGE_PACKET_SIZE; |
295 | { | 323 | if (result < 0) |
296 | return true; | 324 | { |
297 | } | 325 | result = FIRST_PACKET_SIZE; |
326 | } | ||
327 | return result; | ||
328 | } | ||
329 | |||
330 | private bool SendFirstPacket(LLClientView client) | ||
331 | { | ||
332 | // this means we don't have | ||
333 | if (Data == null) | ||
334 | { | ||
335 | client.SendImageNotFound(m_requestedUUID); | ||
336 | m_log.WarnFormat("[TEXTURE]: Got null Data element on a asset {0}.. and the missing image Data property is also null", m_requestedUUID); | ||
337 | return true; | ||
338 | } | ||
339 | // Do we have less then 1 packet's worth of data? | ||
340 | else if (m_assetDataLength <= FIRST_PACKET_SIZE) | ||
341 | { | ||
342 | // Send only 1 packet | ||
343 | client.SendImageFirstPart(1, m_requestedUUID, (uint)m_assetDataLength, m_asset.Data, 2); | ||
344 | m_stopPacket = 0; | ||
345 | return true; | ||
346 | } | ||
347 | else | ||
348 | { | ||
349 | byte[] firstImageData = new byte[FIRST_PACKET_SIZE]; | ||
350 | try | ||
351 | { | ||
352 | Buffer.BlockCopy(m_asset.Data, 0, firstImageData, 0, (int)FIRST_PACKET_SIZE); | ||
353 | client.SendImageFirstPart(TexturePacketCount(), m_requestedUUID, (uint)m_assetDataLength, firstImageData, 2); | ||
354 | } | ||
355 | catch (Exception) | ||
356 | { | ||
357 | m_log.Error("Texture block copy failed. Possibly out of memory?"); | ||
358 | return true; | ||
298 | } | 359 | } |
299 | } | 360 | } |
300 | return false; | 361 | return false; |
301 | } | 362 | } |
302 | 363 | ||
303 | public void RunUpdate() | 364 | private void J2KDecodedCallback(UUID AssetId, OpenJPEG.J2KLayerInfo[] layers) |
304 | { | 365 | { |
305 | //This is where we decide what we need to update | 366 | m_layers = layers; |
306 | //and assign the real discardLevel and packetNumber | 367 | m_decoded = true; |
307 | //assuming of course that the connected client might be bonkers | 368 | RunUpdate(); |
369 | } | ||
308 | 370 | ||
309 | if (!m_hasasset) | 371 | private void AssetDataCallback(UUID AssetID, AssetBase asset) |
310 | { | 372 | { |
373 | m_hasasset = true; | ||
311 | 374 | ||
312 | if (!m_asset_requested) | 375 | if (asset == null || asset.Data == null) |
376 | { | ||
377 | if (m_imageManager.MissingImage != null) | ||
313 | { | 378 | { |
314 | m_asset_requested = true; | 379 | m_asset = m_imageManager.MissingImage; |
315 | m_assetCache.Get(m_requestedUUID.ToString(), this, AssetReceived); | 380 | m_assetDataLength = m_asset.Data.Length; |
316 | 381 | } | |
382 | else | ||
383 | { | ||
384 | m_asset = null; | ||
385 | m_decoded = true; | ||
317 | } | 386 | } |
318 | |||
319 | } | 387 | } |
320 | else | 388 | else |
321 | { | 389 | { |
390 | m_asset = asset; | ||
391 | m_assetDataLength = m_asset.Data.Length; | ||
392 | } | ||
322 | 393 | ||
394 | RunUpdate(); | ||
395 | } | ||
323 | 396 | ||
324 | if (!m_decoded) | 397 | private void AssetReceived(string id, Object sender, AssetBase asset) |
325 | { | 398 | { |
326 | //We need to decode the requested image first | 399 | UUID assetID = UUID.Zero; |
327 | if (!m_decoderequested) | 400 | if (asset != null) |
328 | { | 401 | assetID = asset.FullID; |
329 | //Request decode | ||
330 | m_decoderequested = true; | ||
331 | // Do we have a jpeg decoder? | ||
332 | if (m_j2kDecodeModule != null) | ||
333 | { | ||
334 | if (Data == null) | ||
335 | { | ||
336 | J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]); | ||
337 | } | ||
338 | // Send it off to the jpeg decoder | ||
339 | m_j2kDecodeModule.decode(m_requestedUUID, Data, J2KDecodedCallback); | ||
340 | |||
341 | } | ||
342 | else | ||
343 | { | ||
344 | J2KDecodedCallback(m_requestedUUID, new OpenJPEG.J2KLayerInfo[0]); | ||
345 | } | ||
346 | } | ||
347 | |||
348 | } | ||
349 | else | ||
350 | { | ||
351 | //discardLevel of -1 means just update the priority | ||
352 | if (m_requestedDiscardLevel != -1) | ||
353 | { | ||
354 | //Evaluate the discard level | ||
355 | //First, is it positive? | ||
356 | if (m_requestedDiscardLevel >= 0) | ||
357 | { | ||
358 | if (m_requestedDiscardLevel > Layers.Length - 1) | ||
359 | { | ||
360 | m_discardLevel = (sbyte)(Layers.Length - 1); | ||
361 | } | ||
362 | else | ||
363 | { | ||
364 | m_discardLevel = m_requestedDiscardLevel; | ||
365 | } | ||
366 | 402 | ||
367 | //Calculate the m_stopPacket | 403 | AssetDataCallback(assetID, asset); |
368 | if (Layers.Length > 0) | ||
369 | { | ||
370 | m_stopPacket = (uint)GetPacketForBytePosition(Layers[(Layers.Length - 1) - m_discardLevel].End); | ||
371 | //I don't know why, but the viewer seems to expect the final packet if the file | ||
372 | //is just one packet bigger. | ||
373 | if (TexturePacketCount() == m_stopPacket + 1) | ||
374 | { | ||
375 | m_stopPacket = TexturePacketCount(); | ||
376 | } | ||
377 | } | ||
378 | else | ||
379 | { | ||
380 | m_stopPacket = TexturePacketCount(); | ||
381 | } | ||
382 | //Don't reset packet number unless we're waiting or it's ahead of us | ||
383 | if (m_completedSendAtCurrentDiscardLevel || m_requestedPacketNumber>m_packetNumber) | ||
384 | { | ||
385 | m_packetNumber = m_requestedPacketNumber; | ||
386 | } | ||
387 | 404 | ||
388 | if (m_packetNumber <= m_stopPacket) | ||
389 | { | ||
390 | m_completedSendAtCurrentDiscardLevel = false; | ||
391 | } | ||
392 | } | ||
393 | } | ||
394 | else | ||
395 | { | ||
396 | m_packetNumber = m_stopPacket; | ||
397 | } | ||
398 | } | ||
399 | } | ||
400 | } | 405 | } |
401 | } | 406 | } |
402 | } | 407 | } |