aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/Environment/Modules/TextureDownloadModule.cs')
-rw-r--r--OpenSim/Region/Environment/Modules/TextureDownloadModule.cs276
1 files changed, 176 insertions, 100 deletions
diff --git a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs
index 66cdec7..702af19 100644
--- a/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs
+++ b/OpenSim/Region/Environment/Modules/TextureDownloadModule.cs
@@ -46,11 +46,10 @@ namespace OpenSim.Region.Environment.Modules
46 private Scene m_scene; 46 private Scene m_scene;
47 private List<Scene> m_scenes = new List<Scene>(); 47 private List<Scene> m_scenes = new List<Scene>();
48 48
49 private Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>> ClientRequests =
50 new Dictionary<LLUUID, Dictionary<LLUUID, AssetRequest>>();
51
52 private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>(); 49 private BlockingQueue<TextureSender> QueueSenders = new BlockingQueue<TextureSender>();
53 private Dictionary<LLUUID, List<LLUUID>> InProcess = new Dictionary<LLUUID, List<LLUUID>>(); 50
51 private Dictionary<LLUUID, UserTextureDownloadService> m_userTextureServices = new Dictionary<LLUUID, UserTextureDownloadService>();
52
54 private Thread m_thread; 53 private Thread m_thread;
55 54
56 public TextureDownloadModule() 55 public TextureDownloadModule()
@@ -85,55 +84,36 @@ namespace OpenSim.Region.Environment.Modules
85 84
86 public bool IsSharedModule 85 public bool IsSharedModule
87 { 86 {
88 get { return true; } 87 get { return false; }
89 } 88 }
90 89
91 public void NewClient(IClientAPI client) 90 public void NewClient(IClientAPI client)
92 { 91 {
93 lock (ClientRequests)
94 {
95 if (!ClientRequests.ContainsKey(client.AgentId))
96 {
97 ClientRequests.Add(client.AgentId, new Dictionary<LLUUID, AssetRequest>());
98 InProcess.Add(client.AgentId, new List<LLUUID>());
99 }
100 }
101 client.OnRequestTexture += TextureRequest; 92 client.OnRequestTexture += TextureRequest;
102
103 } 93 }
104 94
105 public void TextureCallback(LLUUID textureID, AssetBase asset) 95 private bool TryGetUserTextureService(LLUUID userID, out UserTextureDownloadService textureService)
106 { 96 {
107 lock (ClientRequests) 97 lock (m_userTextureServices)
108 { 98 {
109 foreach (Dictionary<LLUUID, AssetRequest> reqList in ClientRequests.Values) 99 if (m_userTextureServices.TryGetValue(userID, out textureService))
110 { 100 {
111 if (reqList.ContainsKey(textureID)) 101 return true;
112 {
113 //check the texture isn't already in the process of being sent to the client.
114 if (!InProcess[reqList[textureID].RequestUser.AgentId].Contains(textureID))
115 {
116 TextureSender sender = new TextureSender(reqList[textureID], asset);
117 QueueSenders.Enqueue(sender);
118 InProcess[reqList[textureID].RequestUser.AgentId].Add(textureID);
119 reqList.Remove(textureID);
120 }
121 }
122 } 102 }
103
104 textureService = new UserTextureDownloadService(m_scene, QueueSenders);
105 m_userTextureServices.Add(userID, textureService);
106 return true;
123 } 107 }
124 } 108 }
125 109
126 public void TextureRequest(Object sender, TextureRequestArgs e) 110 public void TextureRequest(Object sender, TextureRequestArgs e)
127 { 111 {
128 IClientAPI client = (IClientAPI)sender; 112 IClientAPI client = (IClientAPI)sender;
129 if (!ClientRequests[client.AgentId].ContainsKey(e.RequestedAssetID)) 113 UserTextureDownloadService textureService;
114 if (TryGetUserTextureService(client.AgentId, out textureService))
130 { 115 {
131 lock (ClientRequests) 116 textureService.HandleTextureRequest(client, e);
132 {
133 AssetRequest request = new AssetRequest(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
134 ClientRequests[client.AgentId].Add(e.RequestedAssetID, request);
135 }
136 m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
137 } 117 }
138 } 118 }
139 119
@@ -142,57 +122,150 @@ namespace OpenSim.Region.Environment.Modules
142 while (true) 122 while (true)
143 { 123 {
144 TextureSender sender = QueueSenders.Dequeue(); 124 TextureSender sender = QueueSenders.Dequeue();
145 bool finished = sender.SendTexture(); 125 if (sender.Cancel)
146 if (finished)
147 { 126 {
148 TextureSent(sender); 127 TextureSent(sender);
149 } 128 }
150 else 129 else
151 { 130 {
152 QueueSenders.Enqueue(sender); 131 bool finished = sender.SendTexturePacket();
132 if (finished)
133 {
134 TextureSent(sender);
135 }
136 else
137 {
138 QueueSenders.Enqueue(sender);
139 }
153 } 140 }
154 } 141 }
155 } 142 }
156 143
157 private void TextureSent(TextureSender sender) 144 private void TextureSent(TextureSender sender)
158 { 145 {
159 if (InProcess[sender.request.RequestUser.AgentId].Contains(sender.request.RequestAssetID)) 146 sender.Sending = false;
147 }
148
149 public class UserTextureDownloadService
150 {
151 private Dictionary<LLUUID, TextureSender> m_textureSenders = new Dictionary<LLUUID, TextureSender>();
152
153 private BlockingQueue<TextureSender> m_sharedSendersQueue;
154
155 private Scene m_scene;
156
157 public UserTextureDownloadService(Scene scene, BlockingQueue<TextureSender> sharedQueue)
160 { 158 {
161 InProcess[sender.request.RequestUser.AgentId].Remove(sender.request.RequestAssetID); 159 m_scene = scene;
160 m_sharedSendersQueue = sharedQueue;
161 }
162
163 public void HandleTextureRequest(IClientAPI client, TextureRequestArgs e)
164 {
165 //TODO: should be working out the data size/ number of packets to be sent for each discard level
166 if ((e.DiscardLevel >= 0) || (e.Priority != 0))
167 {
168 lock (m_textureSenders)
169 {
170 if (!m_textureSenders.ContainsKey(e.RequestedAssetID))
171 {
172 TextureSender requestHandler = new TextureSender(client, e.RequestedAssetID, e.DiscardLevel, e.PacketNumber);
173 m_textureSenders.Add(e.RequestedAssetID, requestHandler);
174 m_scene.AssetCache.GetAsset(e.RequestedAssetID, TextureCallback);
175 }
176 else
177 {
178 m_textureSenders[e.RequestedAssetID].UpdateRequest(e.DiscardLevel, e.PacketNumber);
179 m_textureSenders[e.RequestedAssetID].counter = 0;
180 if ((m_textureSenders[e.RequestedAssetID].ImageLoaded) && (m_textureSenders[e.RequestedAssetID].Sending ==false))
181 {
182 m_textureSenders[e.RequestedAssetID].Sending = true;
183 m_sharedSendersQueue.Enqueue(m_textureSenders[e.RequestedAssetID]);
184 }
185 }
186 }
187 }
188 else
189 {
190 lock (m_textureSenders)
191 {
192 if (m_textureSenders.ContainsKey(e.RequestedAssetID))
193 {
194 m_textureSenders[e.RequestedAssetID].Cancel = true;
195 }
196 }
197 }
198 }
199
200 public void TextureCallback(LLUUID textureID, AssetBase asset)
201 {
202 lock (m_textureSenders)
203 {
204 if (m_textureSenders.ContainsKey(textureID))
205 {
206 if (!m_textureSenders[textureID].ImageLoaded)
207 {
208 m_textureSenders[textureID].TextureReceived(asset);
209 m_textureSenders[textureID].Sending = true;
210 m_textureSenders[textureID].counter = 0;
211 m_sharedSendersQueue.Enqueue(m_textureSenders[textureID]);
212 }
213 }
214 else
215 {
216 // Got a texture with no sender object to handle it, this shouldn't happen
217 }
218 }
162 } 219 }
163 } 220 }
164 221
165 public class TextureSender 222 public class TextureSender
166 { 223 {
167 public AssetRequest request; 224 public int counter = 0;
168 private int counter = 0;
169 private AssetBase m_asset; 225 private AssetBase m_asset;
170 public long DataPointer = 0; 226 public long DataPointer = 0;
171 public int NumPackets = 0; 227 public int NumPackets = 0;
172 public int PacketCounter = 0; 228 public int PacketCounter = 0;
229 public bool Cancel = false;
230 public bool ImageLoaded = false;
231
232 public bool Sending = false;
173 233
174 public TextureSender(AssetRequest req, AssetBase asset) 234 public IClientAPI RequestUser;
235 public LLUUID RequestedAssetID;
236 public int RequestedDiscardLevel = -1;
237 public uint StartPacketNumber = 0;
238
239 // private int m_sentDiscardLevel = -1;
240
241 public TextureSender(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
175 { 242 {
176 request = req; 243 RequestUser = client;
177 m_asset = asset; 244 RequestedAssetID = textureID;
245 RequestedDiscardLevel = discardLevel;
246 StartPacketNumber = packetNumber;
247 }
178 248
179 if (asset.Data.LongLength > 600) 249 public void TextureReceived(AssetBase asset)
180 { 250 {
181 NumPackets = 2 + (int)(asset.Data.Length - 601) / 1000; 251 m_asset = asset;
182 } 252 NumPackets = CalculateNumPackets(asset.Data.Length);
183 else 253 PacketCounter = (int)StartPacketNumber;
184 { 254 ImageLoaded = true;
185 NumPackets = 1; 255 }
186 }
187 256
188 PacketCounter = (int)req.PacketNumber; 257 public void UpdateRequest(int discardLevel, uint packetNumber)
258 {
259 RequestedDiscardLevel = discardLevel;
260 StartPacketNumber = packetNumber;
261 PacketCounter = (int)StartPacketNumber;
189 } 262 }
190 263
191 public bool SendTexture() 264 public bool SendTexturePacket()
192 { 265 {
193 SendPacket(); 266 SendPacket();
194 counter++; 267 counter++;
195 if ((PacketCounter >= NumPackets) || counter > 100 || (NumPackets == 1) || (request.DiscardLevel == -1)) 268 if ((NumPackets == 0) || (RequestedDiscardLevel == -1) || (PacketCounter > NumPackets) || ((RequestedDiscardLevel > 0) && (counter > 50 + (NumPackets / (RequestedDiscardLevel + 1)))) )
196 { 269 {
197 return true; 270 return true;
198 } 271 }
@@ -201,65 +274,68 @@ namespace OpenSim.Region.Environment.Modules
201 274
202 public void SendPacket() 275 public void SendPacket()
203 { 276 {
204 AssetRequest req = request; 277 if (PacketCounter <= NumPackets)
205 if (PacketCounter == 0)
206 { 278 {
207 if (NumPackets == 1) 279 if (PacketCounter == 0)
208 { 280 {
209 ImageDataPacket im = new ImageDataPacket(); 281 if (NumPackets == 0)
210 im.Header.Reliable = false; 282 {
211 im.ImageID.Packets = 1; 283 ImageDataPacket im = new ImageDataPacket();
212 im.ImageID.ID = m_asset.FullID; 284 im.Header.Reliable = false;
213 im.ImageID.Size = (uint)m_asset.Data.Length; 285 im.ImageID.Packets = 0;
214 im.ImageData.Data = m_asset.Data; 286 im.ImageID.ID = m_asset.FullID;
215 im.ImageID.Codec = 2; 287 im.ImageID.Size = (uint)m_asset.Data.Length;
216 req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); 288 im.ImageData.Data = m_asset.Data;
217 PacketCounter++; 289 im.ImageID.Codec = 2;
290 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
291 PacketCounter++;
292 }
293 else
294 {
295 ImageDataPacket im = new ImageDataPacket();
296 im.Header.Reliable = false;
297 im.ImageID.Packets = (ushort)(NumPackets);
298 im.ImageID.ID = m_asset.FullID;
299 im.ImageID.Size = (uint)m_asset.Data.Length;
300 im.ImageData.Data = new byte[600];
301 Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600);
302 im.ImageID.Codec = 2;
303 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
304 PacketCounter++;
305 }
218 } 306 }
219 else 307 else
220 { 308 {
221 ImageDataPacket im = new ImageDataPacket(); 309 ImagePacketPacket im = new ImagePacketPacket();
222 im.Header.Reliable = false; 310 im.Header.Reliable = false;
223 im.ImageID.Packets = (ushort)(NumPackets); 311 im.ImageID.Packet = (ushort)(PacketCounter);
224 im.ImageID.ID = m_asset.FullID; 312 im.ImageID.ID = m_asset.FullID;
225 im.ImageID.Size = (uint)m_asset.Data.Length; 313 int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1));
226 im.ImageData.Data = new byte[600]; 314 if (size > 1000) size = 1000;
227 Array.Copy(m_asset.Data, 0, im.ImageData.Data, 0, 600); 315 im.ImageData.Data = new byte[size];
228 im.ImageID.Codec = 2; 316 Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size);
229 req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture); 317 RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
230 PacketCounter++; 318 PacketCounter++;
231 } 319 }
232 } 320 }
233 else 321 }
322
323 private int CalculateNumPackets(int length)
324 {
325 int numPackets = 0;
326
327 if (length > 600)
234 { 328 {
235 ImagePacketPacket im = new ImagePacketPacket(); 329 //over 600 bytes so split up file
236 im.Header.Reliable = false; 330 int restData = (length - 600);
237 im.ImageID.Packet = (ushort)(PacketCounter); 331 int restPackets = ((restData + 999) / 1000);
238 im.ImageID.ID = m_asset.FullID; 332 numPackets = restPackets;
239 int size = m_asset.Data.Length - 600 - (1000 * (PacketCounter - 1));
240 if (size > 1000) size = 1000;
241 im.ImageData.Data = new byte[size];
242 Array.Copy(m_asset.Data, 600 + (1000 * (PacketCounter - 1)), im.ImageData.Data, 0, size);
243 req.RequestUser.OutPacket(im, ThrottleOutPacketType.Texture);
244 PacketCounter++;
245 } 333 }
334
335 return numPackets;
246 } 336 }
247 } 337 }
248 338
249 public class AssetRequest
250 {
251 public IClientAPI RequestUser;
252 public LLUUID RequestAssetID;
253 public int DiscardLevel = -1;
254 public uint PacketNumber = 0;
255 339
256 public AssetRequest(IClientAPI client, LLUUID textureID, int discardLevel, uint packetNumber)
257 {
258 RequestUser = client;
259 RequestAssetID = textureID;
260 DiscardLevel = discardLevel;
261 PacketNumber = packetNumber;
262 }
263 }
264 } 340 }
265} \ No newline at end of file 341} \ No newline at end of file