OSDN Git Service

Initial reorganizations of Media classes to support parcel, object, and speech Sounds.
authorMojito Sorbet <mojitotech@gmail.com>
Mon, 3 May 2010 17:12:15 +0000 (17:12 +0000)
committerMojito Sorbet <mojitotech@gmail.com>
Mon, 3 May 2010 17:12:15 +0000 (17:12 +0000)
git-svn-id: https://radegast.googlecode.com/svn/branches/sounds@607 f7a694da-4d33-11de-9ad6-1127a62b9fcd

Radegast/Core/Media/BufferSound.cs [new file with mode: 0644]
Radegast/Core/Media/MediaManager.cs
Radegast/Core/Media/MediaObject.cs
Radegast/Core/Media/Speech.cs [new file with mode: 0644]
Radegast/Core/Media/Stream.cs [new file with mode: 0644]
Radegast/GUI/Consoles/MediaConsole.cs

diff --git a/Radegast/Core/Media/BufferSound.cs b/Radegast/Core/Media/BufferSound.cs
new file mode 100644 (file)
index 0000000..3dfb74e
--- /dev/null
@@ -0,0 +1,153 @@
+// \r
+// Radegast Metaverse Client\r
+// Copyright (c) 2009, Radegast Development Team\r
+// All rights reserved.\r
+// \r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are met:\r
+// \r
+//     * Redistributions of source code must retain the above copyright notice,\r
+//       this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above copyright\r
+//       notice, this list of conditions and the following disclaimer in the\r
+//       documentation and/or other materials provided with the distribution.\r
+//     * Neither the name of the application "Radegast", nor the names of its\r
+//       contributors may be used to endorse or promote products derived from\r
+//       this software without specific prior written permission.\r
+// \r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+//\r
+// $Id: Sound.cs 502 2010-03-14 23:13:46Z latifer $\r
+//\r
+using System;\r
+using System.Runtime.InteropServices;\r
+using FMOD;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast.Media\r
+{\r
+\r
+    public class BufferSound : MediaObject\r
+    {\r
+       /// <summary>\r
+        /// Is sound currently playing\r
+        /// </summary>\r
+        public bool Playing { get { return playing; } }\r
+        private bool playing = false;\r
+\r
+        /// <summary>\r
+        /// Is sound currently paused\r
+        /// </summary>\r
+        public bool Paused { get { return paused; } }\r
+        private bool paused = false;\r
+\r
+        private bool soundcreated = false;\r
+        private System.Timers.Timer timer;\r
+\r
+        private FMOD.CREATESOUNDEXINFO extendedInfo;\r
+\r
+        /// <summary>\r
+        /// Creates a new sound object\r
+        /// </summary>\r
+        /// <param name="system">Sound system</param>\r
+        public BufferSound()\r
+            :base()\r
+        {\r
+            timer = new System.Timers.Timer();\r
+            timer.Interval = 50d;\r
+            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);\r
+            timer.Enabled = false;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Releases resources of this sound object\r
+        /// </summary>\r
+        public override void Dispose()\r
+        {\r
+            if (timer != null)\r
+            {\r
+                timer.Enabled = false;\r
+                timer.Dispose();\r
+                timer = null;\r
+            }\r
+\r
+            if (sound != null)\r
+            {\r
+                sound.release();\r
+                sound = null;\r
+            }\r
+            base.Dispose();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Plays audio buffer\r
+        /// </summary>\r
+        /// <param name="url">URL of the stream</param>\r
+        public void Play( byte[] buffer, bool loop)\r
+        {\r
+            extendedInfo.format = SOUND_FORMAT.PCM16;\r
+\r
+            invoke(new SoundDelegate(delegate\r
+            {\r
+                MediaManager.FMODExec(system.createSound(buffer,\r
+                    (MODE.HARDWARE | MODE._3D | MODE.NONBLOCKING),\r
+                    ref extendedInfo,\r
+                    ref sound));\r
+            }));\r
+        }\r
+\r
+        /// <summary>\r
+        /// Toggles sound pause\r
+        /// </summary>\r
+        public void TogglePaused()\r
+        {\r
+            if (channel != null)\r
+            {\r
+                channel.getPaused(ref paused);\r
+                channel.setPaused(!paused);\r
+            }\r
+        }\r
+\r
+        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)\r
+        {\r
+            OPENSTATE openstate = 0;\r
+            uint percentbuffered = 0;\r
+            bool starving = false;\r
+\r
+            try\r
+            {\r
+                if (soundcreated)\r
+                {\r
+                    MediaManager.FMODExec(sound.getOpenState(ref openstate, ref percentbuffered, ref starving));\r
+\r
+                    if (openstate == OPENSTATE.READY && channel == null)\r
+                    {\r
+                        MediaManager.FMODExec(system.playSound(CHANNELINDEX.FREE, sound, false, ref channel));\r
+                        MediaManager.FMODExec(channel.setVolume(volume));\r
+                    }\r
+                }\r
+\r
+                if (system != null)\r
+                {\r
+                    system.update();\r
+                }\r
+            }\r
+            catch (Exception ex)\r
+            {\r
+                playing = paused = false;\r
+                timer.Enabled = false;\r
+                Logger.Log("Error playing sound: ", Helpers.LogLevel.Debug, ex);\r
+            }\r
+        }\r
+    }\r
+}\r
index 8ae3df3..3979a2c 100644 (file)
@@ -32,6 +32,7 @@ using System;
 using System.Collections.Generic;
 using System.Text;
 using FMOD;
+using System.Threading;
 using OpenMetaverse;
 
 namespace Radegast.Media
@@ -43,17 +44,56 @@ namespace Radegast.Media
         /// </summary>
         public bool SoundSystemAvailable { get { return soundSystemAvailable; } }
         private bool soundSystemAvailable = false;
+        private Thread soundThread;
 
         private List<MediaObject> sounds = new List<MediaObject>();
 
-        /// <summary>
-        /// Parcel music stream player
-        /// </summary>
-        public Sound ParcelMusic { get { return parcelMusic; } set { parcelMusic = value; } }
-        private Sound parcelMusic;
-
         public MediaManager(RadegastInstance instance)
-            : base(null)
+            : base()
+        {
+            // Start the background thread that does all the FMOD calls.
+            soundThread = new Thread(new ThreadStart(CommandLoop));
+            soundThread.IsBackground = true;
+            soundThread.Name = "SoundThread";
+            soundThread.Start();
+        }
+
+        private void CommandLoop()
+        {
+            SoundDelegate action;
+
+            InitFMOD();
+            if (!this.soundSystemAvailable) return;
+
+            // Initialize the command queue.
+            queue = new Queue<SoundDelegate>();
+
+            try
+            {
+                while (true)
+                {
+                    // Wait for something to show up in the queue.
+                    lock (queue)
+                    {
+                        while (queue.Count == 0)
+                        {
+                            Monitor.Wait(queue);
+                        }
+
+                        action = queue.Dequeue();
+                    }
+
+                    // We have an action, so call it.
+                    action();
+                }
+            }
+            catch (Exception e)
+            {
+                System.Console.WriteLine("Sound shutdown " + e.Message);
+            }
+        }
+
+        private void InitFMOD()
         {
             try
             {
@@ -62,7 +102,10 @@ namespace Radegast.Media
                 FMODExec(system.getVersion(ref version));
 
                 if (version < FMOD.VERSION.number)
-                    throw new MediaException("You are using an old version of FMOD " + version.ToString("X") + ".  This program requires " + FMOD.VERSION.number.ToString("X") + ".");
+                    throw new MediaException("You are using an old version of FMOD " +
+                        version.ToString("X") +
+                        ".  This program requires " +
+                        FMOD.VERSION.number.ToString("X") + ".");
 
                 // Assume no special hardware capabilities except 5.1 surround sound.
                 FMOD.CAPS caps = FMOD.CAPS.NONE;
@@ -140,16 +183,9 @@ namespace Radegast.Media
 
         public override void Dispose()
         {
-            if (parcelMusic != null)
-            {
-                if (!parcelMusic.Disposed)
-                    parcelMusic.Dispose();
-                parcelMusic = null;
-            }
-
-            lock(sounds)
+            lock (sounds)
             {
-                for (int i=0; i<sounds.Count; i++)
+                for (int i = 0; i < sounds.Count; i++)
                 {
                     if (!sounds[i].Disposed)
                         sounds[i].Dispose();
index 27cde65..7d2e4e0 100644 (file)
@@ -31,6 +31,8 @@
 using System;
 using System.Collections.Generic;
 using System.Text;
+using System.Threading;
+using FMOD;
 
 namespace Radegast.Media
 {
@@ -41,21 +43,86 @@ namespace Radegast.Media
         /// </summary>
         public bool Disposed { get { return disposed; } }
         private bool disposed = false;
+        /// All commands are made through queued delegate calls, so they
+        /// are guaranteed to take place in the same thread.  FMOD requires this.
+        public delegate void SoundDelegate();
+
+        /// Queue of sound commands
+        /// 
+        /// </summary>
+        protected static Queue<SoundDelegate> queue;
+
+        /// <summary>
+        /// FMOD channel controller, should not be used directly, add methods to Radegast.Media.Sound
+        /// </summary>
+        public Channel FMODChannel { get { return channel; } }
+        protected Channel channel = null;
+
+        /// <summary>
+        /// FMOD sound object, should not be used directly, add methods to Radegast.Media.Sound
+        /// </summary>
+        public FMOD.Sound FMODSound { get { return sound; } }
+        protected FMOD.Sound sound = null;
 
         public FMOD.System FMODSystem { get { return system; } }
         /// <summary>
-        /// Base FMOD system object
+        /// Base FMOD system object, of which there is only one.
         /// </summary>
-        protected FMOD.System system = null;
+        protected static FMOD.System system = null;
 
-        public MediaObject(FMOD.System system)
+        public MediaObject()
         {
-            this.system = system;
         }
 
         public virtual void Dispose()
         {
+            if (sound != null)
+            {
+                sound.release();
+                sound = null;
+            }
+
             disposed = true;
         }
+
+        public bool Active { get { return (sound != null); } }
+
+        /// <summary>
+        /// Put a delegate call on the command queue.
+        /// </summary>
+        /// <param name="action"></param>
+        protected void invoke(SoundDelegate action)
+        {
+            // Do nothing if queue not ready yet.
+            if (queue == null) return;
+
+            // Put that on the queue and wake up the background thread.
+            lock (queue)
+            {
+                queue.Enqueue( action );
+                Monitor.Pulse(queue);
+            }
+
+        }
+
+        /// <summary>
+        ///  Common actgions for all sound types.
+        /// </summary>
+        protected float volume = 0.5f;
+        public float Volume {
+            get
+            {
+                return volume;
+            }
+            set
+            {
+                invoke(new SoundDelegate(delegate
+                {
+                    MediaManager.FMODExec(channel.setVolume(value));
+                    volume = value;
+                }));
+            }
+        }
     }
 }
diff --git a/Radegast/Core/Media/Speech.cs b/Radegast/Core/Media/Speech.cs
new file mode 100644 (file)
index 0000000..8189ae0
--- /dev/null
@@ -0,0 +1,157 @@
+// \r
+// Radegast Metaverse Client\r
+// Copyright (c) 2009, Radegast Development Team\r
+// All rights reserved.\r
+// \r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are met:\r
+// \r
+//     * Redistributions of source code must retain the above copyright notice,\r
+//       this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above copyright\r
+//       notice, this list of conditions and the following disclaimer in the\r
+//       documentation and/or other materials provided with the distribution.\r
+//     * Neither the name of the application "Radegast", nor the names of its\r
+//       contributors may be used to endorse or promote products derived from\r
+//       this software without specific prior written permission.\r
+// \r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+//\r
+// $Id: Sound.cs 502 2010-03-14 23:13:46Z latifer $\r
+//\r
+using System;\r
+using System.Runtime.InteropServices;\r
+using FMOD;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast.Media\r
+{\r
+    public class Speech : MediaObject\r
+    {\r
+        /// <summary>\r
+        /// Is sound currently playing\r
+        /// </summary>\r
+        public bool Playing { get { return playing; } }\r
+        private bool playing = false;\r
+\r
+        /// <summary>\r
+        /// Is sound currently paused\r
+        /// </summary>\r
+        public bool Paused { get { return paused; } }\r
+        private bool paused = false;\r
+\r
+        /// <summary>\r
+        /// Fired when a stream meta data is received\r
+        /// </summary>\r
+        /// <param name="sender">Sender</param>\r
+        /// <param name="e">Key, value are sent in e</param>\r
+        public delegate void StreamInfoCallback(object sender, StreamInfoArgs e);\r
+\r
+        private bool soundcreated = false;\r
+        private System.Timers.Timer timer;\r
+\r
+        /// <summary>\r
+        /// Creates a new sound object\r
+        /// </summary>\r
+        /// <param name="system">Sound system</param>\r
+        public Speech()\r
+            :base()\r
+        {\r
+            timer = new System.Timers.Timer();\r
+            timer.Interval = 50d;\r
+            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);\r
+            timer.Enabled = false;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Releases resources of this sound object\r
+        /// </summary>\r
+        public override void Dispose()\r
+        {\r
+            if (timer != null)\r
+            {\r
+                timer.Enabled = false;\r
+                timer.Dispose();\r
+                timer = null;\r
+            }\r
+\r
+            if (sound != null)\r
+            {\r
+                sound.release();\r
+                sound = null;\r
+            }\r
+            base.Dispose();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Plays audio stream\r
+        /// </summary>\r
+        /// <param name="filename">Name of a WAV file created by the synthesizer</param>\r
+        public void Play(string filename)\r
+        {\r
+            if (!soundcreated)\r
+            {\r
+                MediaManager.FMODExec(system.createSound(filename,\r
+                    (MODE.HARDWARE | MODE._2D | MODE.CREATESTREAM | MODE.NONBLOCKING),\r
+                    ref sound));\r
+                soundcreated = true;\r
+                timer.Enabled = true;\r
+                timer_Elapsed(null, null);\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Toggles sound pause\r
+        /// </summary>\r
+        public void TogglePaused()\r
+        {\r
+            if (channel != null)\r
+            {\r
+                channel.getPaused(ref paused);\r
+                channel.setPaused(!paused);\r
+            }\r
+        }\r
+\r
+        void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)\r
+        {\r
+            OPENSTATE openstate = 0;\r
+            uint percentbuffered = 0;\r
+            bool starving = false;\r
+\r
+            try\r
+            {\r
+                if (soundcreated)\r
+                {\r
+                    MediaManager.FMODExec(sound.getOpenState(ref openstate, ref percentbuffered, ref starving));\r
+\r
+                    if (openstate == OPENSTATE.READY && channel == null)\r
+                    {\r
+                        MediaManager.FMODExec(system.playSound(CHANNELINDEX.FREE, sound, false, ref channel));\r
+                        MediaManager.FMODExec(channel.setVolume(volume));\r
+                    }\r
+                }\r
+\r
+                if (system != null)\r
+                {\r
+                    system.update();\r
+                }\r
+            }\r
+            catch (Exception ex)\r
+            {\r
+                playing = paused = false;\r
+                timer.Enabled = false;\r
+                Logger.Log("Error playing speech: ", Helpers.LogLevel.Debug, ex);\r
+            }\r
+        }\r
+    }\r
+}\r
diff --git a/Radegast/Core/Media/Stream.cs b/Radegast/Core/Media/Stream.cs
new file mode 100644 (file)
index 0000000..39a5240
--- /dev/null
@@ -0,0 +1,215 @@
+// \r
+// Radegast Metaverse Client\r
+// Copyright (c) 2009, Radegast Development Team\r
+// All rights reserved.\r
+// \r
+// Redistribution and use in source and binary forms, with or without\r
+// modification, are permitted provided that the following conditions are met:\r
+// \r
+//     * Redistributions of source code must retain the above copyright notice,\r
+//       this list of conditions and the following disclaimer.\r
+//     * Redistributions in binary form must reproduce the above copyright\r
+//       notice, this list of conditions and the following disclaimer in the\r
+//       documentation and/or other materials provided with the distribution.\r
+//     * Neither the name of the application "Radegast", nor the names of its\r
+//       contributors may be used to endorse or promote products derived from\r
+//       this software without specific prior written permission.\r
+// \r
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
+// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
+// DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
+// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
+// DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
+// SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
+// OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
+// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
+//\r
+// $Id: Sound.cs 502 2010-03-14 23:13:46Z latifer $\r
+//\r
+using System;\r
+using System.Runtime.InteropServices;\r
+using FMOD;\r
+using OpenMetaverse;\r
+\r
+namespace Radegast.Media\r
+{\r
+    public class StreamInfoArgs : EventArgs\r
+    {\r
+        public string Key;\r
+        public string Value;\r
+\r
+        public StreamInfoArgs(string key, string value)\r
+        {\r
+            Key = key;\r
+            Value = value;\r
+        }\r
+    }\r
+\r
+    public class Stream : MediaObject\r
+    {\r
+        /// <summary>\r
+        /// Returns current position of the sound played in ms\r
+        /// Do not confuse with the spatial Position on other suonds.\r
+        /// </summary>\r
+        public uint Position { get { return position; } }\r
+        private uint position = 0;\r
+\r
+        /// <summary>\r
+        /// Is sound currently playing\r
+        /// </summary>\r
+        public bool Playing { get { return playing; } }\r
+        private bool playing = false;\r
+\r
+        /// <summary>\r
+        /// Is sound currently paused\r
+        /// </summary>\r
+        public bool Paused { get { return paused; } }\r
+        private bool paused = false;\r
+\r
+        /// <summary>\r
+        /// Fired when a stream meta data is received\r
+        /// </summary>\r
+        /// <param name="sender">Sender</param>\r
+        /// <param name="e">Key, value are sent in e</param>\r
+        public delegate void StreamInfoCallback(object sender, StreamInfoArgs e);\r
+\r
+        /// <summary>\r
+        /// Fired when a stream meta data is received\r
+        /// </summary>\r
+        public event StreamInfoCallback OnStreamInfo;\r
+\r
+        private System.Timers.Timer timer;\r
+\r
+        /// <summary>\r
+        /// Creates a new sound object\r
+        /// </summary>\r
+        /// <param name="system">Sound system</param>\r
+        public Stream()\r
+            :base()\r
+        {\r
+            timer = new System.Timers.Timer();\r
+            timer.Interval = 50d;\r
+            timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);\r
+            timer.Enabled = false;\r
+        }\r
+\r
+\r
+        /// <summary>\r
+        /// Releases resources of this sound object\r
+        /// </summary>\r
+        public override void Dispose()\r
+        {\r
+            if (timer != null)\r
+            {\r
+                timer.Enabled = false;\r
+                timer.Dispose();\r
+                timer = null;\r
+            }\r
+\r
+            base.Dispose();\r
+        }\r
+\r
+        /// <summary>\r
+        /// Plays audio stream\r
+        /// </summary>\r
+        /// <param name="url">URL of the stream</param>\r
+        public void PlayStream(string url)\r
+        {\r
+            if (!Active)\r
+            {\r
+                invoke( new SoundDelegate(\r
+                    delegate {\r
+                        MediaManager.FMODExec(system.createSound(url,\r
+                            (MODE.HARDWARE | MODE._2D | MODE.CREATESTREAM | MODE.NONBLOCKING), ref sound));\r
+  \r
+                        timer.Enabled = true;\r
+                        timer_Elapsed(null, null);\r
+                    }));\r
+            }\r
+        }\r
+\r
+        /// <summary>\r
+        /// Toggles sound pause\r
+        /// </summary>\r
+        public void TogglePaused()\r
+        {\r
+            invoke(new SoundDelegate(delegate\r
+              {\r
+                  if (channel != null)\r
+                  {\r
+                      channel.getPaused(ref paused);\r
+                      channel.setPaused(!paused);\r
+                  }\r
+              }));\r
+        }\r
+\r
+         void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)\r
+        {\r
+            OPENSTATE openstate = 0;\r
+            uint percentbuffered = 0;\r
+            bool starving = false;\r
+\r
+            try\r
+            {\r
+                if (Active)\r
+                {\r
+                    // Query what the sound is doing.\r
+                    MediaManager.FMODExec(sound.getOpenState(ref openstate, ref percentbuffered, ref starving));\r
+\r
+                    // If a channel is not allocated yet, ask for one.\r
+                    if (openstate == OPENSTATE.READY && channel == null)\r
+                    {\r
+                        // Allocate a channel and set initial volume.\r
+                        MediaManager.FMODExec(system.playSound( CHANNELINDEX.FREE, sound, false, ref channel));\r
+                        volume = 0.5f;\r
+                        MediaManager.FMODExec(channel.setVolume(volume));\r
+                    }\r
+                }\r
+\r
+                if (channel != null)\r
+                {\r
+                    // Do not try to get MP3 tags om Unix.  It breaks.\r
+                    if (Environment.OSVersion.Platform != PlatformID.Unix)\r
+                    {\r
+                        for (; ; )\r
+                        {\r
+                            TAG tag = new TAG();\r
+                            if (sound.getTag(null, -1, ref tag) != RESULT.OK)\r
+                            {\r
+                                break;\r
+                            }\r
+                            if (tag.datatype != TAGDATATYPE.STRING)\r
+                            {\r
+                                break;\r
+                            }\r
+                            else\r
+                            {\r
+                                if (OnStreamInfo != null)\r
+                                    try { OnStreamInfo(this, new StreamInfoArgs(tag.name.ToLower(), Marshal.PtrToStringAnsi(tag.data))); }\r
+                                    catch (Exception) { }\r
+                            }\r
+                        }\r
+                    }\r
+\r
+                    // Get pause/play status\r
+                    MediaManager.FMODExec(channel.getPaused(ref paused));\r
+                    MediaManager.FMODExec(channel.isPlaying(ref playing));\r
+                    MediaManager.FMODExec(channel.getPosition(ref position, TIMEUNIT.MS));\r
+                }\r
+\r
+                if (system != null)\r
+                {\r
+                    system.update();\r
+                }\r
+            }\r
+            catch (Exception ex)\r
+            {\r
+                playing = paused = false;\r
+                timer.Enabled = false;\r
+                Logger.Log("Error playing stream: ", Helpers.LogLevel.Debug, ex);\r
+            }\r
+        }\r
+    }\r
+}\r
index f9cb130..3dca62d 100644 (file)
@@ -34,7 +34,8 @@ namespace Radegast
         private const int saveConfigTimeout = 3000;
         private bool playing;
         private string currentURL;
-        private MediaManager mngr;
+        //private MediaManager mngr;
+        private Media.Stream parcelStream;
         private readonly object parcelMusicLock = new object();
 
 
@@ -47,7 +48,7 @@ namespace Radegast
             Disposed += new EventHandler(MediaConsole_Disposed);
 
             this.instance = instance;
-            this.mngr = instance.MediaManager;
+            this.parcelStream = new Media.Stream();
 
             s = instance.GlobalSettings;
 
@@ -128,9 +129,9 @@ namespace Radegast
             lock (parcelMusicLock)
             {
                 playing = false;
-                if (mngr.ParcelMusic != null)
-                    mngr.ParcelMusic.Dispose();
-                mngr.ParcelMusic = null;
+                if (parcelStream != null)
+                    parcelStream.Dispose();
+                parcelStream = null;
                 lblStation.Tag = lblStation.Text = string.Empty;
                 txtSongTitle.Text = string.Empty;
             }
@@ -142,10 +143,10 @@ namespace Radegast
             {
                 Stop();
                 playing = true;
-                mngr.ParcelMusic = new Sound(mngr.FMODSystem);
-                mngr.ParcelMusic.Volume = audioVolume;
-                mngr.ParcelMusic.PlayStream(currentURL);
-                mngr.ParcelMusic.OnStreamInfo += new Sound.StreamInfoCallback(ParcelMusic_OnStreamInfo);
+                parcelStream = new Media.Stream();
+                parcelStream.Volume = audioVolume;
+                parcelStream.PlayStream(currentURL);
+                parcelStream.OnStreamInfo += new Media.Stream.StreamInfoCallback(ParcelMusic_OnStreamInfo);
             }
         }
 
@@ -204,8 +205,8 @@ namespace Radegast
         {
             configTimer.Change(saveConfigTimeout, System.Threading.Timeout.Infinite);
             lock (parcelMusicLock)
-                if (mngr.ParcelMusic != null)
-                    mngr.ParcelMusic.Volume = volAudioStream.Value/50f;
+                if (parcelStream != null)
+                    parcelStream.Volume = volAudioStream.Value/50f;
         }
 
         private void txtAudioURL_TextChanged(object sender, EventArgs e)