/*
* 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
}