OSDN Git Service

Update copyright year
[radegast/radegast.git] / plugins / Radegast.Plugin.Speech / RadSpeech / PluginControl.cs
1 // 
2 // Radegast Metaverse Client Speech Interface
3 // Copyright (c) 2009-2014, 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: PluginControl.cs 203 2009-09-07 19:26:02Z mojitotech@gmail.com $
30 //
31 using System;
32 using System.Collections.Generic;
33 using System.Linq;
34 using System.Text;
35 using System.IO;
36 using System.Reflection;
37 using Radegast;
38 using System.Windows.Forms;
39 using OpenMetaverse;
40 using OpenMetaverse.StructuredData;
41
42 namespace RadegastSpeech
43 {
44     [Radegast.Plugin(Name = "Speech", Description = "Adds TTS and STT accesibility capabilities to Radegast", Version = "0.3")]
45     public class PluginControl : IRadegastPlugin
46     {
47         private const string VERSION = "0.3";
48         public RadegastInstance instance;
49         internal Talk.Control talker;
50         internal Listen.Control listener;
51         internal Conversation.Control converse;
52         internal Environment.Control env;
53         internal Sound.Control sound;
54         internal ToolStripDropDownButton ToolsMenu;
55         private ToolStripMenuItem SpeechButton;
56         internal IRadSpeech osLayer;
57         public OSDMap config;
58         private bool started;
59
60         /// <summary>
61         /// Plugin start-up entry.
62         /// </summary>
63         /// <param name="inst"></param>
64         /// <remarks>Called by Radegast at start-up</remarks>
65         public void StartPlugin(RadegastInstance inst)
66         {
67             instance = inst;
68
69             // Get configuration settings, and initialize if not found.
70             config = instance.GlobalSettings["plugin.speech"] as OSDMap;
71             
72             if (config == null)
73             {
74                 config = new OSDMap();
75                 config["enabled"] = new OSDBoolean(false);
76                 config["voices"] = new OSDMap();
77                 config["properties"] = new OSDMap();
78                 config["substitutions"] = new OSDMap();
79                 instance.GlobalSettings["plugin.speech"] = config;
80                 instance.GlobalSettings.Save();
81             }
82
83             // Add our enable/disable item to the Plugin Menu.
84             ToolsMenu = instance.MainForm.PluginsMenu;
85
86             SpeechButton = new ToolStripMenuItem("Speech", null, OnSpeechMenuButtonClicked);
87             ToolsMenu.DropDownItems.Add(SpeechButton);
88
89             SpeechButton.Checked = config["enabled"].AsBoolean();
90
91             ToolsMenu.Visible = true;
92
93             if (SpeechButton.Checked)
94             {
95                 Initialize();
96             }
97         }
98
99         /// <summary>
100         /// Startup code (executed only when needed)
101         /// </summary>
102         private void Initialize()
103         {
104             // Never initialize twice
105             if (started) return;
106
107             // Do the one-time only initializations.
108             try
109             {
110                 LoadOSLayer();
111                 env = new Environment.Control(this);
112                 talker = new Talk.Control(this);
113                 listener = new Listen.Control(this);
114                 converse = new Conversation.Control(this);
115                 sound = new Sound.FmodSound(this);
116                 StartControls();
117                 if (!instance.Netcom.IsLoggedIn)
118                 {
119                     talker.SayMore("Press enter to connect.");
120                 }
121                 else
122                 {
123                     // Create conversations and pick active one if we are activating
124                     // the speech plugin mid-session
125                     foreach (RadegastTab tab in instance.TabConsole.Tabs.Values)
126                     {
127                         converse.CreateConversationFromTab(tab, false);
128                     }
129                     converse.ActivateConversationFromTab(instance.TabConsole.SelectedTab);
130
131                 }
132                 started = true;
133             }
134             catch (Exception e)
135             {
136                 SpeechButton.Checked = false;
137                 config["enabled"] = OSD.FromBoolean(false);
138                 SaveSpeechSettings();
139                 System.Windows.Forms.MessageBox.Show("Speech failed initialization: " + e.Message);
140                 return;
141             }
142         }
143
144         /// <summary>
145         /// Shutdown speech module
146         /// </summary>
147         private void Shutdown()
148         {
149             if (!started) return;
150             try
151             {
152                 converse.Shutdown();
153                 listener.Shutdown();
154                 talker.Shutdown();
155                 env.Shutdown();
156                 sound.Shutdown();
157             }
158             catch (Exception e)
159             {
160                 Logger.Log("Failed to shutdown speech modules: ", Helpers.LogLevel.Warning, e);
161             }
162             finally
163             {
164                 started = false;
165             }
166         }
167
168         /// <summary>
169         /// Start all speech subsystems 
170         /// </summary>
171         private void StartControls()
172         {
173             // Start up each of the area controllers.  The order
174             // here is important.
175             try
176             {
177                 sound.Start();      // Sound output
178                 talker.Start();     // Synthesis
179                 listener.Start();   // Recognition
180                 converse.Start();   // Topic-specific conversations
181                 env.Start();        // Environmental awareness
182             }
183             catch (Exception e)
184             {
185                 System.Windows.Forms.MessageBox.Show("Speech can not start.  See log.");
186                 Logger.Log("Speech can not start.", Helpers.LogLevel.Error, e);
187
188                 System.Console.WriteLine(e.StackTrace);
189                 MarkDisabled();
190                 return;
191             }
192
193             // Register the speech-related actions for context menus.
194             // Editing voice assignments to avatars.
195             instance.ContextActionManager.RegisterContextAction(
196                 new GUI.AvatarSpeechAction(instance, this));
197             // Reading the contents of notecards.
198             instance.ContextActionManager.RegisterContextAction(
199                 new GUI.NotecardReadAction(instance, this));
200
201             talker.Say("Rahdegast is ready.");
202         }
203
204         void MarkDisabled()
205         {
206             SpeechButton.Checked = false;
207             osLayer = null;
208         }
209
210         /// <summary>
211         /// Plugin shut-down entry
212         /// </summary>
213         /// <param name="inst"></param>
214         /// <remarks>Called by Radegast at shut-down, or when Speech is switched off.
215         /// We use this to release system resources.</remarks>
216         public void StopPlugin(RadegastInstance inst)
217         {
218             SpeechButton.Dispose();
219             Shutdown();
220         }
221
222         /// <summary>
223         /// Handle toggling of our enable flag
224         /// </summary>
225         /// <param name="sender"></param>
226         /// <param name="e"></param>
227         void OnSpeechMenuButtonClicked(object sender, EventArgs e)
228         {
229             SpeechButton.Checked = !SpeechButton.Checked;
230
231             if (SpeechButton.Checked)
232             {
233                 Initialize();
234             }
235             else
236             {
237                 Shutdown();
238             }
239
240             // Save this into the INI file.
241             config["enabled"] = OSD.FromBoolean(SpeechButton.Checked);
242             SaveSpeechSettings();
243         }
244
245         public void SaveSpeechSettings()
246         {
247             instance.GlobalSettings.Save();
248         }
249
250         /// <summary>
251         /// Find the system-specific DLL for this platform
252         /// </summary>
253         private void LoadOSLayer()
254         {
255             string dirName = Application.StartupPath;
256
257             if (!Directory.Exists(dirName))
258                 throw new Exception("No startup directory found " + dirName);
259
260             // The filename depends on the platform.
261             System.Version version = System.Environment.OSVersion.Version;
262             string loadfilename = null;
263             switch (System.Environment.OSVersion.Platform)
264             {
265                 case PlatformID.Win32NT:
266                 case PlatformID.Win32Windows:
267                     // XP and later have Speech Synthesis.
268                     // XP=5, Vista=6, W7=7
269                     if (version.Major >= 5)
270                         loadfilename = "RadSpeechWin";
271                     break;
272                 case PlatformID.Unix:
273                     loadfilename = "RadSpeechLin";
274                     break;
275                 case PlatformID.MacOSX:
276                     loadfilename = "RadSpeechMac";
277                     break;
278             }
279
280             // If the name was not set, we do not support this platform
281             if (loadfilename == null)
282                 throw new Exception("Platform not supported for Speech");
283
284             loadfilename = Path.Combine(dirName, loadfilename + ".dll");
285             try
286             {
287                 Assembly assembly = Assembly.LoadFile(loadfilename);
288
289                 // Examine the types exposed by this DLL, looking for ours.
290                 foreach (Type type in assembly.GetTypes())
291                 {
292                     if (typeof(IRadSpeech).IsAssignableFrom(type))
293                     {
294                         foreach (var ci in type.GetConstructors())
295                         {
296                             if (ci.GetParameters().Length > 0) continue;
297                             try
298                             {
299                                 // This is the one.  Instantiate it.
300                                 osLayer = (IRadSpeech)ci.Invoke(new object[0]);
301                                 return;
302                             }
303                             catch (Exception ex)
304                             {
305                                 throw new Exception("ERROR in Speech OS Layer: " + ex.Message);
306                             }
307                         }
308                     }
309                 }
310             }
311             catch (BadImageFormatException)
312             {
313                 // non .NET .dlls
314                 throw new Exception("Speech OS Layer bad format " + loadfilename);
315             }
316             catch (ReflectionTypeLoadException ex)
317             {
318                 // Out of date or dlls missing sub dependencies
319                 throw new Exception("ERROR loading Speech OS Layer " + loadfilename + ", " + ex.Message);
320             }
321             catch (Exception ex)
322             {
323                 throw new Exception("Exception loading Speech OS Layer " + loadfilename + ", " + ex.Message);
324             }
325         }
326
327     }
328 }