aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
diff options
context:
space:
mode:
Diffstat (limited to 'OpenSim/Region/CoreModules/World/Sound/SoundModule.cs')
-rw-r--r--OpenSim/Region/CoreModules/World/Sound/SoundModule.cs315
1 files changed, 274 insertions, 41 deletions
diff --git a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
index a2f0950..089fcda 100644
--- a/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
+++ b/OpenSim/Region/CoreModules/World/Sound/SoundModule.cs
@@ -1,4 +1,4 @@
1/* 1/*
2 * Copyright (c) Contributors, http://opensimulator.org/ 2 * Copyright (c) Contributors, http://opensimulator.org/
3 * See CONTRIBUTORS.TXT for a full list of copyright holders. 3 * See CONTRIBUTORS.TXT for a full list of copyright holders.
4 * 4 *
@@ -24,56 +24,110 @@
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */ 26 */
27
28using System; 27using System;
28using System.IO;
29using System.Collections.Generic;
30using System.Reflection;
31
29using Nini.Config; 32using Nini.Config;
30using OpenMetaverse; 33using OpenMetaverse;
34using log4net;
35using Mono.Addins;
36
31using OpenSim.Framework; 37using OpenSim.Framework;
32using OpenSim.Region.Framework.Interfaces; 38using OpenSim.Region.Framework.Interfaces;
33using OpenSim.Region.Framework.Scenes; 39using OpenSim.Region.Framework.Scenes;
34using System.Reflection;
35using log4net;
36 40
37namespace OpenSim.Region.CoreModules.World.Sound 41namespace OpenSim.Region.CoreModules.World.Sound
38{ 42{
39 public class SoundModule : IRegionModule, ISoundModule 43 [Extension(Path = "/OpenSim/RegionModules", NodeName = "RegionModule", Id = "SoundModule")]
44 public class SoundModule : INonSharedRegionModule, ISoundModule
40 { 45 {
41// private static readonly ILog m_log = LogManager.GetLogger(MethodBase.GetCurrentMethod().DeclaringType); 46// private static readonly ILog m_log = LogManager.GetLogger(
42 47// MethodBase.GetCurrentMethod().DeclaringType);
43 protected Scene m_scene; 48
44 49 private Scene m_scene;
45 public void Initialise(Scene scene, IConfigSource source) 50
51 public bool Enabled { get; private set; }
52
53 public float MaxDistance { get; private set; }
54
55 #region INonSharedRegionModule
56
57 public void Initialise(IConfigSource configSource)
58 {
59 IConfig config = configSource.Configs["Sounds"];
60
61 if (config == null)
62 {
63 Enabled = true;
64 MaxDistance = 100.0f;
65 }
66 else
67 {
68 Enabled = config.GetString("Module", "OpenSim.Region.CoreModules.dll:SoundModule") ==
69 Path.GetFileName(Assembly.GetExecutingAssembly().Location)
70 + ":" + MethodBase.GetCurrentMethod().DeclaringType.Name;
71 MaxDistance = config.GetFloat("MaxDistance", 100.0f);
72 }
73 }
74
75 public void AddRegion(Scene scene) { }
76
77 public void RemoveRegion(Scene scene)
46 { 78 {
79 m_scene.EventManager.OnClientLogin -= OnNewClient;
80 }
81
82 public void RegionLoaded(Scene scene)
83 {
84 if (!Enabled)
85 return;
86
47 m_scene = scene; 87 m_scene = scene;
48 88 m_scene.EventManager.OnClientLogin += OnNewClient;
49 m_scene.EventManager.OnNewClient += OnNewClient; 89
50
51 m_scene.RegisterModuleInterface<ISoundModule>(this); 90 m_scene.RegisterModuleInterface<ISoundModule>(this);
52 } 91 }
53 92
54 public void PostInitialise() {} 93 public void Close() { }
55 public void Close() {} 94
95 public Type ReplaceableInterface
96 {
97 get { return typeof(ISoundModule); }
98 }
99
56 public string Name { get { return "Sound Module"; } } 100 public string Name { get { return "Sound Module"; } }
57 public bool IsSharedModule { get { return false; } } 101
58 102 #endregion
103
104 #region Event Handlers
105
59 private void OnNewClient(IClientAPI client) 106 private void OnNewClient(IClientAPI client)
60 { 107 {
61 client.OnSoundTrigger += TriggerSound; 108 client.OnSoundTrigger += TriggerSound;
62 } 109 }
63 110
111 #endregion
112
113 #region ISoundModule
114
64 public virtual void PlayAttachedSound( 115 public virtual void PlayAttachedSound(
65 UUID soundID, UUID ownerID, UUID objectID, double gain, Vector3 position, byte flags, float radius) 116 UUID soundID, UUID ownerID, UUID objectID, double gain, Vector3 position, byte flags, float radius)
66 { 117 {
67 SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); 118 SceneObjectPart part;
68 if (part == null) 119 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
69 return; 120 return;
70 121
71 SceneObjectGroup grp = part.ParentGroup; 122 SceneObjectGroup grp = part.ParentGroup;
72 123
124 if (radius == 0)
125 radius = MaxDistance;
126
73 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) 127 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
74 { 128 {
75 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position); 129 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position);
76 if (dis > 100.0) // Max audio distance 130 if (dis > MaxDistance) // Max audio distance
77 return; 131 return;
78 132
79 if (grp.IsAttachment) 133 if (grp.IsAttachment)
@@ -85,26 +139,22 @@ namespace OpenSim.Region.CoreModules.World.Sound
85 dis = 0; 139 dis = 0;
86 } 140 }
87 141
88 float thisSpGain;
89
90 // Scale by distance 142 // Scale by distance
91 if (radius == 0) 143 double thisSpGain = gain * ((radius - dis) / radius);
92 thisSpGain = (float)((double)gain * ((100.0 - dis) / 100.0));
93 else
94 thisSpGain = (float)((double)gain * ((radius - dis) / radius));
95 144
96 sp.ControllingClient.SendPlayAttachedSound(soundID, objectID, ownerID, thisSpGain, flags); 145 sp.ControllingClient.SendPlayAttachedSound(soundID, objectID,
146 ownerID, (float)thisSpGain, flags);
97 }); 147 });
98 } 148 }
99 149
100 public virtual void TriggerSound( 150 public virtual void TriggerSound(
101 UUID soundId, UUID ownerID, UUID objectID, UUID parentID, double gain, Vector3 position, UInt64 handle, float radius) 151 UUID soundId, UUID ownerID, UUID objectID, UUID parentID, double gain, Vector3 position, UInt64 handle, float radius)
102 { 152 {
103 SceneObjectPart part = m_scene.GetSceneObjectPart(objectID); 153 SceneObjectPart part;
104 if (part == null) 154 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
105 { 155 {
106 ScenePresence sp; 156 ScenePresence sp;
107 if (!m_scene.TryGetScenePresence(objectID, out sp)) 157 if (!m_scene.TryGetScenePresence(ownerID, out sp))
108 return; 158 return;
109 } 159 }
110 else 160 else
@@ -118,24 +168,207 @@ namespace OpenSim.Region.CoreModules.World.Sound
118 } 168 }
119 } 169 }
120 170
171 if (radius == 0)
172 radius = MaxDistance;
173
121 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp) 174 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
122 { 175 {
123 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position); 176 double dis = Util.GetDistanceTo(sp.AbsolutePosition, position);
124 177
125 if (dis > 100.0) // Max audio distance 178 if (dis > MaxDistance) // Max audio distance
126 return; 179 return;
127 180
128 float thisSpGain;
129
130 // Scale by distance 181 // Scale by distance
131 if (radius == 0) 182 double thisSpGain = gain * ((radius - dis) / radius);
132 thisSpGain = (float)((double)gain * ((100.0 - dis) / 100.0)); 183
184 sp.ControllingClient.SendTriggeredSound(soundId, ownerID,
185 objectID, parentID, handle, position,
186 (float)thisSpGain);
187 });
188 }
189
190 public virtual void StopSound(UUID objectID)
191 {
192 SceneObjectPart m_host;
193 if (!m_scene.TryGetSceneObjectPart(objectID, out m_host))
194 return;
195
196 StopSound(m_host);
197 }
198
199 private static void StopSound(SceneObjectPart m_host)
200 {
201 m_host.AdjustSoundGain(0);
202 // Xantor 20080528: Clear prim data of sound instead
203 if (m_host.ParentGroup.LoopSoundSlavePrims.Contains(m_host))
204 {
205 if (m_host.ParentGroup.LoopSoundMasterPrim == m_host)
206 {
207 foreach (SceneObjectPart part in m_host.ParentGroup.LoopSoundSlavePrims)
208 {
209 part.Sound = UUID.Zero;
210 part.SoundFlags = 1 << 5;
211 part.SoundRadius = 0;
212 part.ScheduleFullUpdate();
213 part.SendFullUpdateToAllClients();
214 }
215 m_host.ParentGroup.LoopSoundMasterPrim = null;
216 m_host.ParentGroup.LoopSoundSlavePrims.Clear();
217 }
133 else 218 else
134 thisSpGain = (float)((double)gain * ((radius - dis) / radius)); 219 {
220 m_host.Sound = UUID.Zero;
221 m_host.SoundFlags = 1 << 5;
222 m_host.SoundRadius = 0;
223 m_host.ScheduleFullUpdate();
224 m_host.SendFullUpdateToAllClients();
225 }
226 }
227 else
228 {
229 m_host.Sound = UUID.Zero;
230 m_host.SoundFlags = 1 << 5;
231 m_host.SoundRadius = 0;
232 m_host.ScheduleFullUpdate();
233 m_host.SendFullUpdateToAllClients();
234 }
235 }
135 236
136 sp.ControllingClient.SendTriggeredSound( 237 public virtual void PreloadSound(UUID objectID, UUID soundID, float radius)
137 soundId, ownerID, objectID, parentID, handle, position, thisSpGain); 238 {
239 SceneObjectPart part;
240 if (soundID == UUID.Zero
241 || !m_scene.TryGetSceneObjectPart(objectID, out part))
242 {
243 return;
244 }
245
246 if (radius == 0)
247 radius = MaxDistance;
248
249 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
250 {
251 if (!(Util.GetDistanceTo(sp.AbsolutePosition, part.AbsolutePosition) >= MaxDistance))
252 sp.ControllingClient.SendPreLoadSound(objectID, objectID, soundID);
138 }); 253 });
139 } 254 }
255
256 // Xantor 20080528 we should do this differently.
257 // 1) apply the sound to the object
258 // 2) schedule full update
259 // just sending the sound out once doesn't work so well when other avatars come in view later on
260 // or when the prim gets moved, changed, sat on, whatever
261 // see large number of mantises (mantes?)
262 // 20080530 Updated to remove code duplication
263 // 20080530 Stop sound if there is one, otherwise volume only changes don't work
264 public void LoopSound(UUID objectID, UUID soundID,
265 double volume, double radius, bool isMaster)
266 {
267 SceneObjectPart m_host;
268 if (!m_scene.TryGetSceneObjectPart(objectID, out m_host))
269 return;
270
271 if (isMaster)
272 m_host.ParentGroup.LoopSoundMasterPrim = m_host;
273
274 if (m_host.Sound != UUID.Zero)
275 StopSound(m_host);
276
277 m_host.Sound = soundID;
278 m_host.SoundGain = volume;
279 m_host.SoundFlags = 1; // looping
280 m_host.SoundRadius = radius;
281
282 m_host.ScheduleFullUpdate();
283 m_host.SendFullUpdateToAllClients();
284 }
285
286 public void SendSound(UUID objectID, UUID soundID, double volume,
287 bool triggered, byte flags, float radius, bool useMaster,
288 bool isMaster)
289 {
290 if (soundID == UUID.Zero)
291 return;
292
293 SceneObjectPart part;
294 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
295 return;
296
297 volume = Util.Clip((float)volume, 0, 1);
298
299 UUID parentID = part.ParentGroup.UUID;
300
301 Vector3 position = part.AbsolutePosition; // region local
302 ulong regionHandle = m_scene.RegionInfo.RegionHandle;
303
304 if (useMaster)
305 {
306 if (isMaster)
307 {
308 if (triggered)
309 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
310 else
311 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
312 part.ParentGroup.PlaySoundMasterPrim = part;
313 if (triggered)
314 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
315 else
316 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
317 foreach (SceneObjectPart prim in part.ParentGroup.PlaySoundSlavePrims)
318 {
319 position = prim.AbsolutePosition; // region local
320 if (triggered)
321 TriggerSound(soundID, part.OwnerID, prim.UUID, parentID, volume, position, regionHandle, radius);
322 else
323 PlayAttachedSound(soundID, part.OwnerID, prim.UUID, volume, position, flags, radius);
324 }
325 part.ParentGroup.PlaySoundSlavePrims.Clear();
326 part.ParentGroup.PlaySoundMasterPrim = null;
327 }
328 else
329 {
330 part.ParentGroup.PlaySoundSlavePrims.Add(part);
331 }
332 }
333 else
334 {
335 if (triggered)
336 TriggerSound(soundID, part.OwnerID, part.UUID, parentID, volume, position, regionHandle, radius);
337 else
338 PlayAttachedSound(soundID, part.OwnerID, part.UUID, volume, position, flags, radius);
339 }
340 }
341
342 public void TriggerSoundLimited(UUID objectID, UUID sound,
343 double volume, Vector3 min, Vector3 max)
344 {
345 if (sound == UUID.Zero)
346 return;
347
348 SceneObjectPart part;
349 if (!m_scene.TryGetSceneObjectPart(objectID, out part))
350 return;
351
352 m_scene.ForEachRootScenePresence(delegate(ScenePresence sp)
353 {
354 double dis = Util.GetDistanceTo(sp.AbsolutePosition,
355 part.AbsolutePosition);
356
357 if (dis > MaxDistance) // Max audio distance
358 return;
359 else if (!Util.IsInsideBox(sp.AbsolutePosition, min, max))
360 return;
361
362 // Scale by distance
363 double thisSpGain = volume * ((MaxDistance - dis) / MaxDistance);
364
365 sp.ControllingClient.SendTriggeredSound(sound, part.OwnerID,
366 part.UUID, part.ParentGroup.UUID,
367 m_scene.RegionInfo.RegionHandle,
368 part.AbsolutePosition, (float)thisSpGain);
369 });
370 }
371
372 #endregion
140 } 373 }
141} 374}