OSDN Git Service

Remove timer loop from stream class.
[radegast/radegast.git] / Radegast / Core / Media / MediaObject.cs
1 // 
2 // Radegast Metaverse Client
3 // Copyright (c) 2009, Radegast Development Team
4 // All rights reserved.
5 // 
6 // Redistribution and use in source and binary forms, with or without
7 // modification, are permitted provided that the following conditions are met:
8 // 
9 //     * Redistributions of source code must retain the above copyright notice,
10 //       this list of conditions and the following disclaimer.
11 //     * Redistributions in binary form must reproduce the above copyright
12 //       notice, this list of conditions and the following disclaimer in the
13 //       documentation and/or other materials provided with the distribution.
14 //     * Neither the name of the application "Radegast", nor the names of its
15 //       contributors may be used to endorse or promote products derived from
16 //       this software without specific prior written permission.
17 // 
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
19 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
21 // DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
22 // FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23 // DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
24 // SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
25 // CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
26 // OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 //
29 // $Id$
30 //
31 using System;
32 using System.Collections.Generic;
33 using System.Text;
34 using System.Threading;
35 using FMOD;
36
37 namespace Radegast.Media
38 {
39     public abstract class MediaObject : Object, IDisposable
40     {
41         /// <summary>
42         /// Indicates if this object's resources have already been disposed
43         /// </summary>
44         public bool Disposed { get { return disposed; } }
45         private bool disposed = false;
46  
47         /// All commands are made through queued delegate calls, so they
48         /// are guaranteed to take place in the same thread.  FMOD requires this.
49         public delegate void SoundDelegate();
50
51         /// Queue of sound commands
52         /// 
53         /// </summary>
54         protected static Queue<SoundDelegate> queue;
55
56         /// <summary>
57         /// FMOD channel controller, should not be used directly, add methods to Radegast.Media.Sound
58         /// </summary>
59         public Channel FMODChannel { get { return channel; } }
60         protected Channel channel = null;
61
62         protected FMOD.CREATESOUNDEXINFO extraInfo;
63
64         /// <summary>
65         /// FMOD sound object, should not be used directly, add methods to Radegast.Media.Sound
66         /// </summary>
67         public FMOD.Sound FMODSound { get { return sound; } }
68         protected FMOD.Sound sound = null;
69
70         protected static FMOD.VECTOR UpVector;
71         protected static FMOD.VECTOR ZeroVector;
72
73         public FMOD.System FMODSystem { get { return system; } }
74         /// <summary>
75         /// Base FMOD system object, of which there is only one.
76         /// </summary>
77         protected static FMOD.System system = null;
78
79         public MediaObject()
80         {
81             extraInfo = new FMOD.CREATESOUNDEXINFO();
82             extraInfo.cbsize = 10;
83
84         }
85
86         protected bool Cloned = false;
87         public virtual void Dispose()
88         {
89             if (!Cloned && sound != null)
90             {
91                 sound.release();
92                 sound = null;
93             }
94
95             disposed = true;
96         }
97
98         public bool Active { get { return (sound != null); } }
99
100         /// <summary>
101         /// Put a delegate call on the command queue.
102         /// </summary>
103         /// <param name="action"></param>
104         protected void invoke(SoundDelegate action)
105         {
106             // Do nothing if queue not ready yet.
107             if (queue == null) return;
108
109             // Put that on the queue and wake up the background thread.
110             lock (queue)
111             {
112                 queue.Enqueue( action );
113                 Monitor.Pulse(queue);
114             }
115
116         }
117
118         /// <summary>
119         ///  Common actgions for all sound types.
120         /// </summary>
121         protected float volume = 0.5f;
122         public float Volume
123         {
124             get
125             {
126                 return volume;
127             }
128             set
129             {
130                 invoke(new SoundDelegate(delegate
131                 {
132                     MediaManager.FMODExec(channel.setVolume(value));
133                     volume = value;
134                 }));
135             }
136         }
137
138         public void Stop()
139         {
140             if (channel != null)
141             {
142                 invoke(new SoundDelegate(delegate
143                 {
144                     MediaManager.FMODExec(channel.stop());
145                 }));
146             }
147         }
148
149         /// <summary>
150         /// Convert OpenMetaVerse to FMOD coordinate space.
151         /// </summary>
152         /// <param name="omvV"></param>
153         /// <returns></returns>
154         protected FMOD.VECTOR FromOMVSpace(OpenMetaverse.Vector3 omvV)
155         {
156             // OMV  X is forward, Y is left, Z is up.
157             // FMOD Z is forward, X is right, Y is up.
158             FMOD.VECTOR v = new FMOD.VECTOR();
159             v.x = -omvV.Y;
160             v.y = omvV.Z;
161             v.z = omvV.X;
162             return v;
163         }
164
165         protected static Dictionary<IntPtr,MediaObject> allSounds;
166         protected static Dictionary<IntPtr, MediaObject> allChannels;
167         protected void RegisterSound(FMOD.Sound sound)
168         {
169             allSounds.Add(sound.getRaw(), this);
170         }
171         protected void RegisterChannel(FMOD.Channel channel)
172         {
173             allSounds.Add(channel.getRaw(), this);
174         }
175         protected void UnRegisterSound()
176         {
177             if (sound == null) return;
178             IntPtr raw = sound.getRaw();
179             if (allSounds.ContainsKey( raw ))
180             {
181                 allSounds.Remove( raw );
182             }
183         }
184         protected void UnRegisterChannel()
185         {
186             if (channel == null) return;
187             IntPtr raw = channel.getRaw();
188             if (allChannels.ContainsKey(raw))
189             {
190                 allChannels.Remove(raw);
191             }
192         }
193
194         /// <summary>
195         /// A callback for asynchronous FMOD calls.
196         /// </summary>
197         /// <returns></returns>
198         protected virtual FMOD.RESULT NonBlockCallbackHandler( RESULT result ) { return RESULT.OK; }
199         protected virtual FMOD.RESULT EndCallbackHandler() { return RESULT.OK; }
200
201         protected RESULT DispatchNonBlockCallback(IntPtr soundraw, RESULT result)
202         {
203             if (allSounds.ContainsKey(soundraw))
204             {
205                 MediaObject sndobj = allSounds[soundraw];
206                 return sndobj.NonBlockCallbackHandler( result );
207             }
208
209             return FMOD.RESULT.OK;
210         }
211
212         protected RESULT DispatchEndCallback(
213             IntPtr channelraw,
214             CHANNEL_CALLBACKTYPE type,
215             IntPtr commanddata1,
216             IntPtr commanddata2)
217         {
218             // Ignore other callback types.
219             if (type != CHANNEL_CALLBACKTYPE.END) return RESULT.OK;
220
221             if (allChannels.ContainsKey(channelraw))
222             {
223                 MediaObject sndobj = allSounds[channelraw];
224                 return sndobj.EndCallbackHandler();
225             }
226
227             return RESULT.OK;
228         }
229
230         public delegate RESULT SOUND_NONBLOCKCALLBACK(IntPtr soundraw, RESULT result);
231
232         protected static void FMODExec(FMOD.RESULT result)
233         {
234             if (result != FMOD.RESULT.OK)
235             {
236                 throw new MediaException("FMOD error! " + result + " - " + FMOD.Error.String(result));
237             }
238         }
239
240
241  
242     }
243 }