/* * Copyright (c) 2006-2014, openmetaverse.org * All rights reserved. * * - Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions are met: * * - Redistributions of source code must retain the above copyright notice, this * list of conditions and the following disclaimer. * - Neither the name of the openmetaverse.org nor the names * of its contributors may be used to endorse or promote products derived from * this software without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ using System; using System.Collections.Generic; using OpenMetaverse.Packets; namespace OpenMetaverse { /// /// /// public class SoundManager { #region Private Members private readonly GridClient Client; #endregion #region Event Handling /// The event subscribers, null of no subscribers private EventHandler m_AttachedSound; ///Raises the AttachedSound Event /// A AttachedSoundEventArgs object containing /// the data sent from the simulator protected virtual void OnAttachedSound(AttachedSoundEventArgs e) { EventHandler handler = m_AttachedSound; if (handler != null) handler(this, e); } /// Thread sync lock object private readonly object m_AttachedSoundLock = new object(); /// Raised when the simulator sends us data containing /// sound public event EventHandler AttachedSound { add { lock (m_AttachedSoundLock) { m_AttachedSound += value; } } remove { lock (m_AttachedSoundLock) { m_AttachedSound -= value; } } } /// The event subscribers, null of no subscribers private EventHandler m_AttachedSoundGainChange; ///Raises the AttachedSoundGainChange Event /// A AttachedSoundGainChangeEventArgs object containing /// the data sent from the simulator protected virtual void OnAttachedSoundGainChange(AttachedSoundGainChangeEventArgs e) { EventHandler handler = m_AttachedSoundGainChange; if (handler != null) handler(this, e); } /// Thread sync lock object private readonly object m_AttachedSoundGainChangeLock = new object(); /// Raised when the simulator sends us data containing /// ... public event EventHandler AttachedSoundGainChange { add { lock (m_AttachedSoundGainChangeLock) { m_AttachedSoundGainChange += value; } } remove { lock (m_AttachedSoundGainChangeLock) { m_AttachedSoundGainChange -= value; } } } /// The event subscribers, null of no subscribers private EventHandler m_SoundTrigger; ///Raises the SoundTrigger Event /// A SoundTriggerEventArgs object containing /// the data sent from the simulator protected virtual void OnSoundTrigger(SoundTriggerEventArgs e) { EventHandler handler = m_SoundTrigger; if (handler != null) handler(this, e); } /// Thread sync lock object private readonly object m_SoundTriggerLock = new object(); /// Raised when the simulator sends us data containing /// ... public event EventHandler SoundTrigger { add { lock (m_SoundTriggerLock) { m_SoundTrigger += value; } } remove { lock (m_SoundTriggerLock) { m_SoundTrigger -= value; } } } /// The event subscribers, null of no subscribers private EventHandler m_PreloadSound; ///Raises the PreloadSound Event /// A PreloadSoundEventArgs object containing /// the data sent from the simulator protected virtual void OnPreloadSound(PreloadSoundEventArgs e) { EventHandler handler = m_PreloadSound; if (handler != null) handler(this, e); } /// Thread sync lock object private readonly object m_PreloadSoundLock = new object(); /// Raised when the simulator sends us data containing /// ... public event EventHandler PreloadSound { add { lock (m_PreloadSoundLock) { m_PreloadSound += value; } } remove { lock (m_PreloadSoundLock) { m_PreloadSound -= value; } } } #endregion /// /// Construct a new instance of the SoundManager class, used for playing and receiving /// sound assets /// /// A reference to the current GridClient instance public SoundManager(GridClient client) { Client = client; Client.Network.RegisterCallback(PacketType.AttachedSound, AttachedSoundHandler); Client.Network.RegisterCallback(PacketType.AttachedSoundGainChange, AttachedSoundGainChangeHandler); Client.Network.RegisterCallback(PacketType.PreloadSound, PreloadSoundHandler); Client.Network.RegisterCallback(PacketType.SoundTrigger, SoundTriggerHandler); } #region public methods /// /// Plays a sound in the current region at full volume from avatar position /// /// UUID of the sound to be played public void PlaySound(UUID soundID) { SendSoundTrigger(soundID, Client.Self.SimPosition, 1.0f); } /// /// Plays a sound in the current region at full volume /// /// UUID of the sound to be played. /// position for the sound to be played at. Normally the avatar. public void SendSoundTrigger(UUID soundID, Vector3 position) { SendSoundTrigger(soundID, Client.Self.SimPosition, 1.0f); } /// /// Plays a sound in the current region /// /// UUID of the sound to be played. /// position for the sound to be played at. Normally the avatar. /// volume of the sound, from 0.0 to 1.0 public void SendSoundTrigger(UUID soundID, Vector3 position, float gain) { SendSoundTrigger(soundID, Client.Network.CurrentSim.Handle, position, gain); } /// /// Plays a sound in the specified sim /// /// UUID of the sound to be played. /// UUID of the sound to be played. /// position for the sound to be played at. Normally the avatar. /// volume of the sound, from 0.0 to 1.0 public void SendSoundTrigger(UUID soundID, Simulator sim, Vector3 position, float gain) { SendSoundTrigger(soundID, sim.Handle, position, gain); } /// /// Play a sound asset /// /// UUID of the sound to be played. /// handle id for the sim to be played in. /// position for the sound to be played at. Normally the avatar. /// volume of the sound, from 0.0 to 1.0 public void SendSoundTrigger(UUID soundID, ulong handle, Vector3 position, float gain) { SoundTriggerPacket soundtrigger = new SoundTriggerPacket(); soundtrigger.SoundData = new SoundTriggerPacket.SoundDataBlock(); soundtrigger.SoundData.SoundID = soundID; soundtrigger.SoundData.ObjectID = UUID.Zero; soundtrigger.SoundData.OwnerID = UUID.Zero; soundtrigger.SoundData.ParentID = UUID.Zero; soundtrigger.SoundData.Handle = handle; soundtrigger.SoundData.Position = position; soundtrigger.SoundData.Gain = gain; Client.Network.SendPacket(soundtrigger); } #endregion #region Packet Handlers /// Process an incoming packet and raise the appropriate events /// The sender /// The EventArgs object containing the packet data protected void AttachedSoundHandler(object sender, PacketReceivedEventArgs e) { if (m_AttachedSound != null) { AttachedSoundPacket sound = (AttachedSoundPacket)e.Packet; OnAttachedSound(new AttachedSoundEventArgs(e.Simulator, sound.DataBlock.SoundID, sound.DataBlock.OwnerID, sound.DataBlock.ObjectID, sound.DataBlock.Gain, (SoundFlags)sound.DataBlock.Flags)); } } /// Process an incoming packet and raise the appropriate events /// The sender /// The EventArgs object containing the packet data protected void AttachedSoundGainChangeHandler(object sender, PacketReceivedEventArgs e) { if (m_AttachedSoundGainChange != null) { AttachedSoundGainChangePacket change = (AttachedSoundGainChangePacket)e.Packet; OnAttachedSoundGainChange(new AttachedSoundGainChangeEventArgs(e.Simulator, change.DataBlock.ObjectID, change.DataBlock.Gain)); } } /// Process an incoming packet and raise the appropriate events /// The sender /// The EventArgs object containing the packet data protected void PreloadSoundHandler(object sender, PacketReceivedEventArgs e) { if (m_PreloadSound != null) { PreloadSoundPacket preload = (PreloadSoundPacket)e.Packet; foreach (PreloadSoundPacket.DataBlockBlock data in preload.DataBlock) { OnPreloadSound(new PreloadSoundEventArgs(e.Simulator, data.SoundID, data.OwnerID, data.ObjectID)); } } } /// Process an incoming packet and raise the appropriate events /// The sender /// The EventArgs object containing the packet data protected void SoundTriggerHandler(object sender, PacketReceivedEventArgs e) { if (m_SoundTrigger != null) { SoundTriggerPacket trigger = (SoundTriggerPacket)e.Packet; OnSoundTrigger(new SoundTriggerEventArgs(e.Simulator, trigger.SoundData.SoundID, trigger.SoundData.OwnerID, trigger.SoundData.ObjectID, trigger.SoundData.ParentID, trigger.SoundData.Gain, trigger.SoundData.Handle, trigger.SoundData.Position)); } } #endregion } #region EventArgs /// Provides data for the event /// The event occurs when the simulator sends /// the sound data which emits from an agents attachment /// /// The following code example shows the process to subscribe to the event /// and a stub to handle the data passed from the simulator /// /// // Subscribe to the AttachedSound event /// Client.Sound.AttachedSound += Sound_AttachedSound; /// /// // process the data raised in the event here /// private void Sound_AttachedSound(object sender, AttachedSoundEventArgs e) /// { /// // ... Process AttachedSoundEventArgs here ... /// } /// /// public class AttachedSoundEventArgs : EventArgs { private readonly Simulator m_Simulator; private readonly UUID m_SoundID; private readonly UUID m_OwnerID; private readonly UUID m_ObjectID; private readonly float m_Gain; private readonly SoundFlags m_Flags; /// Simulator where the event originated public Simulator Simulator { get { return m_Simulator; } } /// Get the sound asset id public UUID SoundID { get { return m_SoundID; } } /// Get the ID of the owner public UUID OwnerID { get { return m_OwnerID; } } /// Get the ID of the Object public UUID ObjectID { get { return m_ObjectID; } } /// Get the volume level public float Gain { get { return m_Gain; } } /// Get the public SoundFlags Flags { get { return m_Flags; } } /// /// Construct a new instance of the SoundTriggerEventArgs class /// /// Simulator where the event originated /// The sound asset id /// The ID of the owner /// The ID of the object /// The volume level /// The public AttachedSoundEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID, float gain, SoundFlags flags) { this.m_Simulator = sim; this.m_SoundID = soundID; this.m_OwnerID = ownerID; this.m_ObjectID = objectID; this.m_Gain = gain; this.m_Flags = flags; } } /// Provides data for the event /// The event occurs when an attached sound /// changes its volume level public class AttachedSoundGainChangeEventArgs : EventArgs { private readonly Simulator m_Simulator; private readonly UUID m_ObjectID; private readonly float m_Gain; /// Simulator where the event originated public Simulator Simulator { get { return m_Simulator; } } /// Get the ID of the Object public UUID ObjectID { get { return m_ObjectID; } } /// Get the volume level public float Gain { get { return m_Gain; } } /// /// Construct a new instance of the AttachedSoundGainChangedEventArgs class /// /// Simulator where the event originated /// The ID of the Object /// The new volume level public AttachedSoundGainChangeEventArgs(Simulator sim, UUID objectID, float gain) { this.m_Simulator = sim; this.m_ObjectID = objectID; this.m_Gain = gain; } } /// Provides data for the event /// The event occurs when the simulator forwards /// a request made by yourself or another agent to play either an asset sound or a built in sound /// /// Requests to play sounds where the is not one of the built-in /// will require sending a request to download the sound asset before it can be played /// /// /// The following code example uses the , /// and /// properties to display some information on a sound request on the window. /// /// // subscribe to the event /// Client.Sound.SoundTrigger += Sound_SoundTrigger; /// /// // play the pre-defined BELL_TING sound /// Client.Sound.SendSoundTrigger(Sounds.BELL_TING); /// /// // handle the response data /// private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e) /// { /// Console.WriteLine("{0} played the sound {1} at volume {2}", /// e.OwnerID, e.SoundID, e.Gain); /// } /// /// public class SoundTriggerEventArgs : EventArgs { private readonly Simulator m_Simulator; private readonly UUID m_SoundID; private readonly UUID m_OwnerID; private readonly UUID m_ObjectID; private readonly UUID m_ParentID; private readonly float m_Gain; private readonly ulong m_RegionHandle; private readonly Vector3 m_Position; /// Simulator where the event originated public Simulator Simulator { get { return m_Simulator; } } /// Get the sound asset id public UUID SoundID { get { return m_SoundID; } } /// Get the ID of the owner public UUID OwnerID { get { return m_OwnerID; } } /// Get the ID of the Object public UUID ObjectID { get { return m_ObjectID; } } /// Get the ID of the objects parent public UUID ParentID { get { return m_ParentID; } } /// Get the volume level public float Gain { get { return m_Gain; } } /// Get the regionhandle public ulong RegionHandle { get { return m_RegionHandle; } } /// Get the source position public Vector3 Position { get { return m_Position; } } /// /// Construct a new instance of the SoundTriggerEventArgs class /// /// Simulator where the event originated /// The sound asset id /// The ID of the owner /// The ID of the object /// The ID of the objects parent /// The volume level /// The regionhandle /// The source position public SoundTriggerEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID, UUID parentID, float gain, ulong regionHandle, Vector3 position) { this.m_Simulator = sim; this.m_SoundID = soundID; this.m_OwnerID = ownerID; this.m_ObjectID = objectID; this.m_ParentID = parentID; this.m_Gain = gain; this.m_RegionHandle = regionHandle; this.m_Position = position; } } /// Provides data for the event /// The event occurs when the simulator sends /// the appearance data for an avatar /// /// The following code example uses the and /// properties to display the selected shape of an avatar on the window. /// /// // subscribe to the event /// Client.Avatars.AvatarAppearance += Avatars_AvatarAppearance; /// /// // handle the data when the event is raised /// void Avatars_AvatarAppearance(object sender, AvatarAppearanceEventArgs e) /// { /// Console.WriteLine("The Agent {0} is using a {1} shape.", e.AvatarID, (e.VisualParams[31] > 0) : "male" ? "female") /// } /// /// public class PreloadSoundEventArgs : EventArgs { private readonly Simulator m_Simulator; private readonly UUID m_SoundID; private readonly UUID m_OwnerID; private readonly UUID m_ObjectID; /// Simulator where the event originated public Simulator Simulator { get { return m_Simulator; } } /// Get the sound asset id public UUID SoundID { get { return m_SoundID; } } /// Get the ID of the owner public UUID OwnerID { get { return m_OwnerID; } } /// Get the ID of the Object public UUID ObjectID { get { return m_ObjectID; } } /// /// Construct a new instance of the PreloadSoundEventArgs class /// /// Simulator where the event originated /// The sound asset id /// The ID of the owner /// The ID of the object public PreloadSoundEventArgs(Simulator sim, UUID soundID, UUID ownerID, UUID objectID) { this.m_Simulator = sim; this.m_SoundID = soundID; this.m_OwnerID = ownerID; this.m_ObjectID = objectID; } } #endregion }