using System;
using System.Net.Sockets;
using System.Text;
using libsecondlife;
namespace libsecondlife.Utilities
{
public enum VoiceStatus
{
StatusLoginRetry,
StatusLoggedIn,
StatusJoining,
StatusJoined,
StatusLeftChannel,
BeginErrorStatus,
ErrorChannelFull,
ErrorChannelLocked,
ErrorNotAvailable,
ErrorUnknown
}
public enum VoiceServiceType
{
/// Unknown voice service level
Unknown,
/// Spatialized local chat
TypeA,
/// Remote multi-party chat
TypeB,
/// One-to-one and small group chat
TypeC
}
public class VoiceManager
{
public const string DAEMON_ARGS = " -p tcp -h -c -ll ";
public const int DAEMON_LOG_LEVEL = 1;
public const int DAEMON_PORT = 44124;
public const string VOICE_RELEASE_SERVER = "bhr.vivox.com";
public const string VOICE_DEBUG_SERVER = "bhd.vivox.com";
public const string REQUEST_TERMINATOR = "\n\n\n";
public SecondLife Client;
protected TCPPipe _DaemonPipe;
protected VoiceStatus _Status;
protected int _CommandCookie = 0;
protected string _TuningSoundFile = String.Empty;
protected string _VoiceServer = VOICE_RELEASE_SERVER;
public VoiceManager(SecondLife client)
{
Client = client;
}
public bool IsDaemonRunning()
{
return false;
}
public bool StartDaemon()
{
return false;
}
public void StopDaemon()
{
}
public bool ConnectToDaemon()
{
return ConnectToDaemon("127.0.0.1", DAEMON_PORT);
}
public bool ConnectToDaemon(string address, int port)
{
_DaemonPipe = new TCPPipe();
_DaemonPipe.OnDisconnected += new TCPPipe.OnDisconnectedCallback(_DaemonPipe_OnDisconnected);
_DaemonPipe.OnReceiveLine += new TCPPipe.OnReceiveLineCallback(_DaemonPipe_OnReceiveLine);
SocketException se = _DaemonPipe.Connect(address, port);
if (se == null)
{
return true;
}
else
{
Console.WriteLine("Connection failed: " + se.Message);
return false;
}
}
public string VoiceAccountFromUUID(LLUUID id)
{
string result = "x" + Convert.ToBase64String(id.GetBytes());
return result.Replace('+', '-').Replace('/', '_');
}
public LLUUID UUIDFromVoiceAccount(string accountName)
{
if (accountName.Length == 25 && accountName[0] == 'x' && accountName[23] == '=' && accountName[24] == '=')
{
accountName = accountName.Replace('/', '_').Replace('+', '-');
byte[] idBytes = Convert.FromBase64String(accountName);
if (idBytes.Length == 16)
return new LLUUID(idBytes, 0);
else
return LLUUID.Zero;
}
else
{
return LLUUID.Zero;
}
}
public string SIPURIFromVoiceAccount(string account)
{
return String.Format("sip:{0}@{1}", account, _VoiceServer);
}
public void RequestCaptureDevices()
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}",
_CommandCookie++,
REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestCaptureDevices() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestRenderDevices()
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}",
_CommandCookie++,
REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestRenderDevices() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestCreateConnector()
{
RequestCreateConnector(VOICE_RELEASE_SERVER);
}
public void RequestCreateConnector(string voiceServer)
{
if (_DaemonPipe.Connected)
{
_VoiceServer = voiceServer;
string accountServer = String.Format("https://www.{0}/api2/", _VoiceServer);
string logPath = ".";
StringBuilder request = new StringBuilder();
request.Append(String.Format("", _CommandCookie++));
request.Append("V2 SDK");
request.Append(String.Format("{0}", accountServer));
request.Append("");
request.Append("false");
request.Append(String.Format("{0}", logPath));
request.Append("vivox-gateway");
request.Append(".log");
request.Append("0");
request.Append("");
request.Append("");
request.Append(REQUEST_TERMINATOR);
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(request.ToString()));
}
else
{
Client.Log("VoiceManager.CreateConnector() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestLogin(string accountName, string password, string connectorHandle)
{
if (_DaemonPipe.Connected)
{
StringBuilder request = new StringBuilder();
request.Append(String.Format("", _CommandCookie++));
request.Append(String.Format("{0}", connectorHandle));
request.Append(String.Format("{0}", accountName));
request.Append(String.Format("{0}", password));
request.Append("VerifyAnswer");
request.Append("");
request.Append(REQUEST_TERMINATOR);
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(request.ToString()));
}
else
{
Client.Log("VoiceManager.Login() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestSetRenderDevice(string deviceName)
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}",
_CommandCookie, deviceName, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestSetRenderDevice() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestStartTuningMode(int duration)
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}",
_CommandCookie, duration, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestStartTuningMode() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestStopTuningMode()
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}",
_CommandCookie, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestStopTuningMode() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestSetSpeakerVolume(int volume)
{
if (volume < 0 || volume > 100)
throw new ArgumentException("volume must be between 0 and 100", "volume");
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}",
_CommandCookie, volume, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestSetSpeakerVolume() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestSetCaptureVolume(int volume)
{
if (volume < 0 || volume > 100)
throw new ArgumentException("volume must be between 0 and 100", "volume");
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}",
_CommandCookie, volume, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestSetCaptureVolume() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
///
/// Does not appear to be working
///
///
///
public void RequestRenderAudioStart(string fileName, bool loop)
{
if (_DaemonPipe.Connected)
{
_TuningSoundFile = fileName;
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}{3}",
_CommandCookie++, _TuningSoundFile, (loop ? "1" : "0"), REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestRenderAudioStart() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
public void RequestRenderAudioStop()
{
if (_DaemonPipe.Connected)
{
_DaemonPipe.SendData(Encoding.ASCII.GetBytes(String.Format(
"{1}{2}",
_CommandCookie++, _TuningSoundFile, REQUEST_TERMINATOR)));
}
else
{
Client.Log("VoiceManager.RequestRenderAudioStop() called when the daemon pipe is disconnected", Helpers.LogLevel.Error);
}
}
private void _DaemonPipe_OnDisconnected(SocketException se)
{
if (se != null) Console.WriteLine("Disconnected! " + se.Message);
else Console.WriteLine("Disconnected!");
}
private void _DaemonPipe_OnReceiveLine(string line)
{
Client.DebugLog("VOICE: " + line);
}
}
}