OSDN Git Service

ESD seems to be causing the least amount of trouble on linux
[radegast/radegast.git] / Radegast / Core / Media / MediaManager.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$\r
30 //\r
31 using System;\r
32 using System.Collections.Generic;\r
33 using System.Text;\r
34 using FMOD;\r
35 using OpenMetaverse;\r
36 \r
37 namespace Radegast.Media\r
38 {\r
39     public class MediaManager : MediaObject\r
40     {\r
41         /// <summary>\r
42         /// Indicated wheather spund sytem is ready for use\r
43         /// </summary>\r
44         public bool SoundSystemAvailable { get { return soundSystemAvailable; } }\r
45         private bool soundSystemAvailable = false;\r
46 \r
47         private List<MediaObject> sounds = new List<MediaObject>();\r
48 \r
49         /// <summary>\r
50         /// Parcel music stream player\r
51         /// </summary>\r
52         public Sound ParcelMusic { get { return parcelMusic; } set { parcelMusic = value; } }\r
53         private Sound parcelMusic;\r
54 \r
55         public MediaManager(RadegastInstance instance)\r
56             : base(null)\r
57         {\r
58             try\r
59             {\r
60                 FMODExec(FMOD.Factory.System_Create(ref system));\r
61                 uint version = 0;\r
62                 FMODExec(system.getVersion(ref version));\r
63 \r
64                 if (version < FMOD.VERSION.number)\r
65                     throw new MediaException("You are using an old version of FMOD " + version.ToString("X") + ".  This program requires " + FMOD.VERSION.number.ToString("X") + ".");\r
66 \r
67                 // Assume no special hardware capabilities except 5.1 surround sound.\r
68                 FMOD.CAPS caps = FMOD.CAPS.NONE;\r
69                 FMOD.SPEAKERMODE speakermode = FMOD.SPEAKERMODE._5POINT1;\r
70 \r
71                 // Get the capabilities of the driver.\r
72                 int minfrequency = 0, maxfrequency = 0;\r
73                 StringBuilder name = new StringBuilder(128);\r
74                 FMODExec(system.getDriverCaps(0, ref caps,\r
75                     ref minfrequency, ref maxfrequency,\r
76                     ref speakermode)\r
77                 );\r
78 \r
79                 // Set FMOD speaker mode to what the driver supports.\r
80                 FMODExec(system.setSpeakerMode(speakermode));\r
81 \r
82                 // Forcing the ESD sound system on Linux seems to avoid a CPU loop\r
83                 if (System.Environment.OSVersion.Platform == PlatformID.Unix)\r
84                     FMODExec(system.setOutput(FMOD.OUTPUTTYPE.ESD));\r
85 \r
86                 // The user has the 'Acceleration' slider set to off, which\r
87                 // is really bad for latency.  At 48khz, the latency between\r
88                 // issuing an fmod command and hearing it will now be about 213ms.\r
89                 if ((caps & FMOD.CAPS.HARDWARE_EMULATED) == FMOD.CAPS.HARDWARE_EMULATED)\r
90                 {\r
91                     FMODExec(system.setDSPBufferSize(1024, 10));\r
92                 }\r
93 \r
94                 // Get driver information so we can check for a wierd one.\r
95                 FMOD.GUID guid = new FMOD.GUID();\r
96                 FMODExec(system.getDriverInfo(0, name, 128, ref guid));\r
97 \r
98                 // Sigmatel sound devices crackle for some reason if the format is pcm 16bit.\r
99                 // pcm floating point output seems to solve it.\r
100                 if (name.ToString().IndexOf("SigmaTel") != -1)\r
101                 {\r
102                     FMODExec(system.setSoftwareFormat(\r
103                         48000,\r
104                         FMOD.SOUND_FORMAT.PCMFLOAT,\r
105                         0, 0,\r
106                         FMOD.DSP_RESAMPLER.LINEAR)\r
107                     );\r
108                 }\r
109 \r
110                 // Try to initialize with all those settings, and Max 32 channels.\r
111                 FMOD.RESULT result = system.init(32, FMOD.INITFLAG.NORMAL, (IntPtr)null);\r
112                 if (result == FMOD.RESULT.ERR_OUTPUT_CREATEBUFFER)\r
113                 {\r
114                     // Can not handle surround sound - back to Stereo.\r
115                     FMODExec(system.setSpeakerMode(FMOD.SPEAKERMODE.STEREO));\r
116 \r
117                     // And init again.\r
118                     FMODExec(system.init(\r
119                         32,\r
120                         FMOD.INITFLAG.NORMAL,\r
121                         (IntPtr)null)\r
122                     );\r
123                 }\r
124 \r
125                 // Set real-world effect scales.\r
126                 FMODExec(system.set3DSettings(\r
127                     1.0f,   // Doppler scale\r
128                     1.0f,   // Distance scale is meters\r
129                     1.0f)   // Rolloff factor\r
130                 );\r
131 \r
132                 soundSystemAvailable = true;\r
133                 Logger.Log("Initialized FMOD Ex", Helpers.LogLevel.Debug);\r
134             }\r
135             catch (Exception ex)\r
136             {\r
137                 Logger.Log("Failed to initialize the sound system: ", Helpers.LogLevel.Warning, ex);\r
138             }\r
139         }\r
140 \r
141         public override void Dispose()\r
142         {\r
143             if (parcelMusic != null)\r
144             {\r
145                 if (!parcelMusic.Disposed)\r
146                     parcelMusic.Dispose();\r
147                 parcelMusic = null;\r
148             }\r
149 \r
150             lock(sounds)\r
151             {\r
152                 for (int i=0; i<sounds.Count; i++)\r
153                 {\r
154                     if (!sounds[i].Disposed)\r
155                         sounds[i].Dispose();\r
156                 }\r
157                 sounds.Clear();\r
158             }\r
159 \r
160             sounds = null;\r
161 \r
162             if (system != null)\r
163             {\r
164                 system.release();\r
165                 system = null;\r
166             }\r
167 \r
168             base.Dispose();\r
169         }\r
170 \r
171         public static void FMODExec(FMOD.RESULT result)\r
172         {\r
173             if (result != FMOD.RESULT.OK)\r
174             {\r
175                 throw new MediaException("FMOD error! " + result + " - " + FMOD.Error.String(result));\r
176             }\r
177         }\r
178     }\r
179 \r
180     public class MediaException : Exception\r
181     {\r
182         public MediaException(string msg)\r
183             : base(msg)\r
184         {\r
185         }\r
186     }\r
187 }\r