diff options
Diffstat (limited to 'OpenSim/Region/Environment/Modules')
-rw-r--r-- | OpenSim/Region/Environment/Modules/TextureDownloadModule.cs | 276 |
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 |