using System; using System.Collections.Generic; using System.IO; using System.Net.Sockets; using System.Diagnostics; using System.Threading; using System.Text; namespace OpenMetaverse.Voice { public partial class VoiceGateway { public delegate void DaemonRunningCallback(); public delegate void DaemonExitedCallback(); public delegate void DaemonCouldntRunCallback(); public delegate void DaemonConnectedCallback(); public delegate void DaemonDisconnectedCallback(); public delegate void DaemonCouldntConnectCallback(); public event DaemonRunningCallback OnDaemonRunning; public event DaemonExitedCallback OnDaemonExited; public event DaemonCouldntRunCallback OnDaemonCouldntRun; public event DaemonConnectedCallback OnDaemonConnected; public event DaemonDisconnectedCallback OnDaemonDisconnected; public event DaemonCouldntConnectCallback OnDaemonCouldntConnect; public bool DaemonIsRunning { get { return daemonIsRunning; } } public bool DaemonIsConnected { get { return daemonIsConnected; } } public int RequestId { get { return requestId; } } protected Process daemonProcess; protected ManualResetEvent daemonLoopSignal = new ManualResetEvent(false); protected TCPPipe daemonPipe; protected bool daemonIsRunning = false; protected bool daemonIsConnected = false; protected int requestId = 0; #region Daemon Management /// /// Starts a thread that keeps the daemon running /// /// /// public void StartDaemon(string path, string args) { StopDaemon(); daemonLoopSignal.Set(); Thread thread = new Thread(new ThreadStart(delegate() { while (daemonLoopSignal.WaitOne(500, false)) { daemonProcess = new Process(); daemonProcess.StartInfo.FileName = path; daemonProcess.StartInfo.Arguments = args; daemonProcess.StartInfo.UseShellExecute = false; bool ok = true; if (!File.Exists(path)) ok = false; if (ok) { // Attempt to start the process if (!daemonProcess.Start()) ok = false; } if (!ok) { daemonIsRunning = false; daemonLoopSignal.Reset(); if (OnDaemonCouldntRun != null) { try { OnDaemonCouldntRun(); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } } return; } else { daemonIsRunning = true; if (OnDaemonRunning != null) { try { OnDaemonRunning(); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } } Logger.DebugLog("Started voice daemon, waiting for exit..."); daemonProcess.WaitForExit(); Logger.DebugLog("Voice daemon exited"); daemonIsRunning = false; if (OnDaemonExited != null) { try { OnDaemonExited(); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } } } } })); thread.Start(); } /// /// Stops the daemon and the thread keeping it running /// public void StopDaemon() { daemonLoopSignal.Reset(); if (daemonProcess != null) { try { daemonProcess.Kill(); } catch (InvalidOperationException ex) { Logger.Log("Failed to stop the voice daemon", Helpers.LogLevel.Error, ex); } } } /// /// /// /// /// /// public bool ConnectToDaemon(string address, int port) { daemonIsConnected = false; daemonPipe = new TCPPipe(); daemonPipe.OnDisconnected += delegate(SocketException e) { if (OnDaemonDisconnected != null) { try { OnDaemonDisconnected(); } catch (Exception ex) { Logger.Log(ex.Message, Helpers.LogLevel.Error, null, ex); } } }; daemonPipe.OnReceiveLine += new TCPPipe.OnReceiveLineCallback(daemonPipe_OnReceiveLine); SocketException se = daemonPipe.Connect(address, port); if (se == null) { daemonIsConnected = true; if (OnDaemonConnected != null) { try { OnDaemonConnected(); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } } return true; } else { daemonIsConnected = false; if (OnDaemonCouldntConnect != null) { try { OnDaemonCouldntConnect(); } catch (Exception e) { Logger.Log(e.Message, Helpers.LogLevel.Error, null, e); } } Logger.Log("Voice daemon connection failed: " + se.Message, Helpers.LogLevel.Error); return false; } } #endregion Daemon Management public int Request(string action) { return Request(action, null); } public int Request(string action, string requestXML) { int returnId = requestId; if (daemonIsConnected) { StringBuilder sb = new StringBuilder(); sb.Append(String.Format(""); } else { sb.Append(">"); sb.Append(requestXML); sb.Append(""); } sb.Append("\n\n\n"); daemonPipe.SendData(Encoding.ASCII.GetBytes(sb.ToString())); return returnId; } else { return -1; } } public static string MakeXML(string name, string text) { if (string.IsNullOrEmpty(text)) return string.Format("<{0} />", name); else return string.Format("<{0}>{1}", name, text); } private void daemonPipe_OnReceiveLine(string line) { if (line.Substring(0, 10) == " CaptureDevices = new List(); foreach (CaptureDevice device in rsp.Results.CaptureDevices) CaptureDevices.Add(device.Device); OnAuxGetCaptureDevicesResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, CaptureDevices, rsp.Results.CurrentCaptureDevice.Device, rsp.InputXml.Request); } break; case "Aux.GetRenderDevices.1": if (OnAuxGetRenderDevicesResponse != null) { List RenderDevices = new List(); foreach (RenderDevice device in rsp.Results.RenderDevices) RenderDevices.Add(device.Device); OnAuxGetRenderDevicesResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, RenderDevices, rsp.Results.CurrentRenderDevice.Device, rsp.InputXml.Request); } break; case "Aux.SetRenderDevice.1": if (OnAuxSetRenderDeviceResponse != null) { OnAuxSetRenderDeviceResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Aux.SetCaptureDevice.1": if (OnAuxSetCaptureDeviceResponse != null) { OnAuxSetCaptureDeviceResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Session.RenderAudioStart.1": if (OnSessionRenderAudioStartResponse != null) { OnSessionRenderAudioStartResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Session.RenderAudioStop.1": if (OnSessionRenderAudioStopResponse != null) { OnSessionRenderAudioStopResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Aux.CaptureAudioStart.1": if (OnAuxCaptureAudioStartResponse != null) { OnAuxCaptureAudioStartResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Aux.CaptureAudioStop.1": if (OnAuxCaptureAudioStopResponse != null) { OnAuxCaptureAudioStopResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Aux.SetMicLevel.1": if (OnAuxSetMicLevelResponse != null) { OnAuxSetMicLevelResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Aux.SetSpeakerLevel.1": if (OnAuxSetSpeakerLevelResponse != null) { OnAuxSetSpeakerLevelResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Account.Login.1": if (OnAccountLoginResponse != null) { OnAccountLoginResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.Results.AccountHandle, rsp.InputXml.Request); } break; case "Account.Logout.1": if (OnAccountLogoutResponse != null) { OnAccountLogoutResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Session.Create.1": if (OnSessionCreateResponse != null) { OnSessionCreateResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.Results.SessionHandle, rsp.InputXml.Request); } break; case "Session.Connect.1": if (OnSessionConnectResponse != null) { OnSessionConnectResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Session.Terminate.1": if (OnSessionTerminateResponse != null) { OnSessionTerminateResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; case "Session.SetParticipantVolumeForMe.1": if (OnSessionSetParticipantVolumeForMeResponse != null) { OnSessionSetParticipantVolumeForMeResponse(int.Parse(rsp.ReturnCode), int.Parse(rsp.Results.StatusCode), rsp.Results.StatusString, rsp.InputXml.Request); } break; default: Logger.Log("Unimplemented response from the voice daemon: " + line, Helpers.LogLevel.Error); break; } } else if (line.Substring(0, 7) == "