//\r
using System;\r
using System.Runtime.InteropServices;\r
+using System.Collections.Generic;\r
using FMOD;\r
using OpenMetaverse;\r
+using OpenMetaverse.Assets;\r
\r
namespace Radegast.Media\r
{\r
public class BufferSound : MediaObject\r
{\r
private FMOD.CREATESOUNDEXINFO extendedInfo;\r
-\r
+ private UUID Id;\r
+ private Boolean prefetchOnly = false;\r
+ private FMOD.MODE mode;\r
public Sound Sound { get { return sound; } }\r
\r
/// <summary>\r
/// Creates a new sound object\r
/// </summary>\r
/// <param name="system">Sound system</param>\r
- public BufferSound(byte[] buffer, bool loop, bool global, Vector3 worldpos )\r
+ public BufferSound( UUID soundId, bool loop, bool global, Vector3 worldpos, float vol )\r
:base()\r
{\r
+ allBuffers.AddLast(this);\r
position = FromOMVSpace(worldpos);\r
-\r
- extendedInfo.format = SOUND_FORMAT.PCM16;\r
- extendedInfo.nonblockcallback += DispatchNonBlockCallback;\r
+ volume = vol;\r
\r
// Set flags to determine how it will be played.\r
- FMOD.MODE mode = FMOD.MODE.SOFTWARE | FMOD.MODE._3D;\r
- position = FromOMVSpace(worldpos);\r
+ FMOD.MODE mode = FMOD.MODE.SOFTWARE | FMOD.MODE._3D | FMOD.MODE.NONBLOCKING;\r
\r
// Set coordinate space interpretation.\r
if (global)\r
else\r
mode |= FMOD.MODE._3D_HEADRELATIVE;\r
\r
- invoke(new SoundDelegate(delegate\r
- {\r
- FMODExec(system.createSound(buffer,\r
- mode,\r
- ref extendedInfo,\r
- ref sound));\r
-\r
- // Register for callbacks.\r
- RegisterSound(sound);\r
-\r
- if (loop)\r
- FMODExec(sound.setLoopCount(-1));\r
- }));\r
+ manager.Instance.Client.Assets.RequestAsset(\r
+ Id,\r
+ AssetType.Sound,\r
+ false,\r
+ new AssetManager.AssetReceivedCallback(Assets_OnSoundReceived));\r
}\r
\r
- public BufferSound( BufferSound shared, bool loop, Vector3 worldpos)\r
+ public BufferSound( UUID soundId )\r
: base()\r
{\r
- position = FromOMVSpace(worldpos);\r
-\r
- // Share a previously loaded sound.\r
- Cloned = true;\r
- sound = shared.Sound;\r
-\r
- NonBlockCallbackHandler(RESULT.OK );\r
+ allBuffers.AddLast(this);\r
+ prefetchOnly = true;\r
+ Id = soundId;\r
+\r
+ manager.Instance.Client.Assets.RequestAsset(\r
+ Id,\r
+ AssetType.Sound,\r
+ false,\r
+ new AssetManager.AssetReceivedCallback(Assets_OnSoundReceived));\r
}\r
\r
/// <summary>\r
base.Dispose();\r
}\r
\r
+ /**\r
+ * Handle arrival of a sound resource.\r
+ */\r
+ void Assets_OnSoundReceived(AssetDownload transfer, Asset asset)\r
+ {\r
+ if (transfer.Success)\r
+ {\r
+ // If this was a Prefetch, just stop here.\r
+ if (prefetchOnly)\r
+ {\r
+ allBuffers.Remove(this);\r
+ return;\r
+ }\r
+\r
+ AssetSound s = asset as AssetSound;\r
+ s.Decode();\r
+\r
+ invoke(new SoundDelegate(delegate\r
+ {\r
+ FMODExec(system.createSound(\r
+ s.AssetData,\r
+ mode,\r
+ ref extendedInfo,\r
+ ref sound));\r
+\r
+ // Register for callbacks.\r
+ RegisterSound(sound);\r
+\r
+// if (loop)\r
+// FMODExec(sound.setLoopCount(-1));\r
+ }));\r
+ }\r
+ else\r
+ {\r
+ Logger.Log("Failed to download sound: " + transfer.Status.ToString(),\r
+ Helpers.LogLevel.Error);\r
+ }\r
+ }\r
protected override RESULT NonBlockCallbackHandler(RESULT instatus)\r
{\r
if (instatus != RESULT.OK)\r
{\r
- Logger.Log("Error opening stream: ", Helpers.LogLevel.Debug);\r
+ Logger.Log("Error opening sound: ", Helpers.LogLevel.Error);\r
return RESULT.OK;\r
}\r
\r
{\r
// Allocate a channel and set initial volume. Initially paused.\r
FMODExec(system.playSound(CHANNELINDEX.FREE, sound, true, ref channel));\r
- volume = 0.5f;\r
FMODExec(channel.setVolume(volume));\r
\r
// Take note of when the sound is finished playing.\r
FMODExec(channel.setCallback(EndCallback));\r
\r
- // Set speech attenuation limits.\r
+ // Set attenuation limits.\r
FMODExec(sound.set3DMinMaxDistance(\r
1.2f, // Any closer than this gets no louder\r
- 8.0f)); // Further than this gets no softer.\r
+ 20.0f)); // Further than this gets no softer.\r
\r
// Set the sound point of origin.\r
FMODExec(channel.set3DAttributes(ref position, ref ZeroVector));\r
}\r
catch (Exception ex)\r
{\r
- Logger.Log("Error starting stream: ", Helpers.LogLevel.Debug, ex);\r
+ Logger.Log("Error starting sound: ", Helpers.LogLevel.Debug, ex);\r
}\r
\r
return RESULT.OK;\r
if (type != CHANNEL_CALLBACKTYPE.END) return RESULT.OK;\r
\r
// Release the buffer to avoid a big memory leak.\r
- //TODO Should be a reference count on cloned sound buffers.\r
- if (!Cloned && sound != null)\r
+\r
+ if (sound != null)\r
{\r
sound.release();\r
sound = null;\r
}\r
channel = null;\r
\r
+ allBuffers.Remove(this);\r
+\r
return RESULT.OK;\r
}\r
\r
using FMOD;
using System.Threading;
using OpenMetaverse;
+using OpenMetaverse.Assets;
namespace Radegast.Media
{
private bool soundSystemAvailable = false;
private Thread soundThread;
private Thread listenerThread;
- RadegastInstance instance;
+ public RadegastInstance Instance;
private List<MediaObject> sounds = new List<MediaObject>();
public MediaManager(RadegastInstance instance)
: base()
{
- this.instance = instance;
+ this.Instance = instance;
manager = this;
loadCallback = new FMOD.SOUND_NONBLOCKCALLBACK(DispatchNonBlockCallback);
endCallback = new FMOD.CHANNEL_CALLBACK(DispatchEndCallback);
+ allBuffers = new LinkedList<BufferSound>();
// Start the background thread that does all the FMOD calls.
soundThread = new Thread(new ThreadStart(CommandLoop));
listenerThread.IsBackground = true;
listenerThread.Name = "ListenerThread";
listenerThread.Start();
+
+ // Subscribe to events about inworld sounds
+ instance.Client.Sound.SoundTrigger += new EventHandler<SoundTriggerEventArgs>(Sound_SoundTrigger);
+ instance.Client.Sound.AttachedSound += new EventHandler<AttachedSoundEventArgs>(Sound_AttachedSound);
+ instance.Client.Sound.PreloadSound += new EventHandler<PreloadSoundEventArgs>(Sound_PreloadSound);
}
private void CommandLoop()
if (system == null) continue;
- AgentManager my = instance.Client.Self;
+ AgentManager my = Instance.Client.Self;
// If we are standing still, nothing to update now, but
// FMOD needs a 'tick' anyway for callbacks, etc. In looping
}
}
+ /**
+ * Handle triggering a sound to play
+ */
+ private void Sound_SoundTrigger(object sender, SoundTriggerEventArgs e)
+ {
+ new BufferSound(
+ e.SoundID,
+ false,
+ true,
+ e.Position,
+ e.Gain);
+ }
+
+ private void Sound_AttachedSound(object sender, AttachedSoundEventArgs e)
+ {
+
+ }
+
+ /**
+ * Handle request to preload a sound resource.
+ */
+ private void Sound_PreloadSound(object sender, PreloadSoundEventArgs e)
+ {
+ new BufferSound( e.SoundID );
+ }
+
+
+ }
+
+ public class PlayingSound
+ {
+ private UUID Id;
+ private Vector3 position;
+ private float volume;
+
+ public PlayingSound( UUID soundId )
+ {
+ Id = soundId;
+ }
}
public class MediaException : Exception