OSDN Git Service

39a5240a1a2178998d1a9411ce9dcd0cadf412cf
[radegast/radegast.git] / Radegast / Core / Media / Stream.cs
1 // \r
2 // Radegast Metaverse Client\r
3 // Copyright (c) 2009, Radegast Development Team\r
4 // All rights reserved.\r
5 // \r
6 // Redistribution and use in source and binary forms, with or without\r
7 // modification, are permitted provided that the following conditions are met:\r
8 // \r
9 //     * Redistributions of source code must retain the above copyright notice,\r
10 //       this list of conditions and the following disclaimer.\r
11 //     * Redistributions in binary form must reproduce the above copyright\r
12 //       notice, this list of conditions and the following disclaimer in the\r
13 //       documentation and/or other materials provided with the distribution.\r
14 //     * Neither the name of the application "Radegast", nor the names of its\r
15 //       contributors may be used to endorse or promote products derived from\r
16 //       this software without specific prior written permission.\r
17 // \r
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"\r
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\r
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE\r
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE\r
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL\r
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR\r
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER\r
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,\r
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\r
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\r
28 //\r
29 // $Id: Sound.cs 502 2010-03-14 23:13:46Z latifer $\r
30 //\r
31 using System;\r
32 using System.Runtime.InteropServices;\r
33 using FMOD;\r
34 using OpenMetaverse;\r
35 \r
36 namespace Radegast.Media\r
37 {\r
38     public class StreamInfoArgs : EventArgs\r
39     {\r
40         public string Key;\r
41         public string Value;\r
42 \r
43         public StreamInfoArgs(string key, string value)\r
44         {\r
45             Key = key;\r
46             Value = value;\r
47         }\r
48     }\r
49 \r
50     public class Stream : MediaObject\r
51     {\r
52         /// <summary>\r
53         /// Returns current position of the sound played in ms\r
54         /// Do not confuse with the spatial Position on other suonds.\r
55         /// </summary>\r
56         public uint Position { get { return position; } }\r
57         private uint position = 0;\r
58 \r
59         /// <summary>\r
60         /// Is sound currently playing\r
61         /// </summary>\r
62         public bool Playing { get { return playing; } }\r
63         private bool playing = false;\r
64 \r
65         /// <summary>\r
66         /// Is sound currently paused\r
67         /// </summary>\r
68         public bool Paused { get { return paused; } }\r
69         private bool paused = false;\r
70 \r
71         /// <summary>\r
72         /// Fired when a stream meta data is received\r
73         /// </summary>\r
74         /// <param name="sender">Sender</param>\r
75         /// <param name="e">Key, value are sent in e</param>\r
76         public delegate void StreamInfoCallback(object sender, StreamInfoArgs e);\r
77 \r
78         /// <summary>\r
79         /// Fired when a stream meta data is received\r
80         /// </summary>\r
81         public event StreamInfoCallback OnStreamInfo;\r
82 \r
83         private System.Timers.Timer timer;\r
84 \r
85         /// <summary>\r
86         /// Creates a new sound object\r
87         /// </summary>\r
88         /// <param name="system">Sound system</param>\r
89         public Stream()\r
90             :base()\r
91         {\r
92             timer = new System.Timers.Timer();\r
93             timer.Interval = 50d;\r
94             timer.Elapsed += new System.Timers.ElapsedEventHandler(timer_Elapsed);\r
95             timer.Enabled = false;\r
96         }\r
97 \r
98 \r
99         /// <summary>\r
100         /// Releases resources of this sound object\r
101         /// </summary>\r
102         public override void Dispose()\r
103         {\r
104             if (timer != null)\r
105             {\r
106                 timer.Enabled = false;\r
107                 timer.Dispose();\r
108                 timer = null;\r
109             }\r
110 \r
111             base.Dispose();\r
112         }\r
113 \r
114         /// <summary>\r
115         /// Plays audio stream\r
116         /// </summary>\r
117         /// <param name="url">URL of the stream</param>\r
118         public void PlayStream(string url)\r
119         {\r
120             if (!Active)\r
121             {\r
122                 invoke( new SoundDelegate(\r
123                     delegate {\r
124                         MediaManager.FMODExec(system.createSound(url,\r
125                             (MODE.HARDWARE | MODE._2D | MODE.CREATESTREAM | MODE.NONBLOCKING), ref sound));\r
126   \r
127                         timer.Enabled = true;\r
128                         timer_Elapsed(null, null);\r
129                     }));\r
130             }\r
131         }\r
132 \r
133         /// <summary>\r
134         /// Toggles sound pause\r
135         /// </summary>\r
136         public void TogglePaused()\r
137         {\r
138             invoke(new SoundDelegate(delegate\r
139               {\r
140                   if (channel != null)\r
141                   {\r
142                       channel.getPaused(ref paused);\r
143                       channel.setPaused(!paused);\r
144                   }\r
145               }));\r
146         }\r
147 \r
148          void timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)\r
149         {\r
150             OPENSTATE openstate = 0;\r
151             uint percentbuffered = 0;\r
152             bool starving = false;\r
153 \r
154             try\r
155             {\r
156                 if (Active)\r
157                 {\r
158                     // Query what the sound is doing.\r
159                     MediaManager.FMODExec(sound.getOpenState(ref openstate, ref percentbuffered, ref starving));\r
160 \r
161                     // If a channel is not allocated yet, ask for one.\r
162                     if (openstate == OPENSTATE.READY && channel == null)\r
163                     {\r
164                         // Allocate a channel and set initial volume.\r
165                         MediaManager.FMODExec(system.playSound( CHANNELINDEX.FREE, sound, false, ref channel));\r
166                         volume = 0.5f;\r
167                         MediaManager.FMODExec(channel.setVolume(volume));\r
168                     }\r
169                 }\r
170 \r
171                 if (channel != null)\r
172                 {\r
173                     // Do not try to get MP3 tags om Unix.  It breaks.\r
174                     if (Environment.OSVersion.Platform != PlatformID.Unix)\r
175                     {\r
176                         for (; ; )\r
177                         {\r
178                             TAG tag = new TAG();\r
179                             if (sound.getTag(null, -1, ref tag) != RESULT.OK)\r
180                             {\r
181                                 break;\r
182                             }\r
183                             if (tag.datatype != TAGDATATYPE.STRING)\r
184                             {\r
185                                 break;\r
186                             }\r
187                             else\r
188                             {\r
189                                 if (OnStreamInfo != null)\r
190                                     try { OnStreamInfo(this, new StreamInfoArgs(tag.name.ToLower(), Marshal.PtrToStringAnsi(tag.data))); }\r
191                                     catch (Exception) { }\r
192                             }\r
193                         }\r
194                     }\r
195 \r
196                     // Get pause/play status\r
197                     MediaManager.FMODExec(channel.getPaused(ref paused));\r
198                     MediaManager.FMODExec(channel.isPlaying(ref playing));\r
199                     MediaManager.FMODExec(channel.getPosition(ref position, TIMEUNIT.MS));\r
200                 }\r
201 \r
202                 if (system != null)\r
203                 {\r
204                     system.update();\r
205                 }\r
206             }\r
207             catch (Exception ex)\r
208             {\r
209                 playing = paused = false;\r
210                 timer.Enabled = false;\r
211                 Logger.Log("Error playing stream: ", Helpers.LogLevel.Debug, ex);\r
212             }\r
213         }\r
214     }\r
215 }\r