/// Callback for a client request for ParcelVoiceInfo public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, UUID agentID, Caps caps) { m_log.Info("[MurmurVoice]: Calling ParcelVoiceInfoRequest..."); try { ScenePresence avatar = scene.GetScenePresence(agentID); LLSDParcelVoiceInfoResponse parcelVoiceInfo; string channel_uri = String.Empty; if (null == scene.LandChannel) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatar.Name)); // get channel_uri: check first whether estate // settings allow voice, then whether parcel allows // voice, if all do retrieve or obtain the parcel // voice channel LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); m_log.DebugFormat("[MurmurVoice]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", scene.RegionInfo.RegionName, land.Name, land.LocalID, avatar.Name, request, path, param); if ( ((land.Flags & (uint)ParcelFlags.AllowVoiceChat) > 0) && scene.RegionInfo.EstateSettings.AllowVoice ) { Agent agent = m_manager.Agent.GetOrCreate(agentID); string RegionName = scene.RegionInfo.RegionName; if(m_RegionParents.ContainsKey(RegionName)) { int RParent = m_RegionParents[RegionName]; agent.channel = m_manager.Channel.GetOrCreate(ChannelName(scene, land),RParent); // Host/port pair for voice server channel_uri = String.Format("{0}:{1}", m_murmurd_exthost, m_murmurd_port); m_log.InfoFormat("[MurmurVoice]: {0}", channel_uri); m_callback.AddUserToChan(agent); } else m_log.DebugFormat("[MurmurVoice]: Region Parent channel not found: {0}",RegionName); } else { m_log.DebugFormat("[MurmurVoice]: Voice not enabled."); } Hashtable creds = new Hashtable(); creds["channel_uri"] = channel_uri; parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds); string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); m_log.InfoFormat("[MurmurVoice]: Parcel: {0}", r); return r; } catch (Exception e) { m_log.ErrorFormat("[MurmurVoice]: Exception: " + e.ToString()); return "<llsd><undef /></llsd>"; } }
/// <summary> /// Callback for a client request for ParcelVoiceInfo /// </summary> /// <param name="scene">current scene object of the client</param> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <param name="agentID"></param> /// <param name="caps"></param> /// <returns></returns> public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, UUID agentID, Caps caps) { m_log.DebugFormat( "[FreeSwitchVoice][PARCELVOICE]: ParcelVoiceInfoRequest() on {0} for {1}", scene.RegionInfo.RegionName, agentID); ScenePresence avatar = scene.GetScenePresence(agentID); string avatarName = avatar.Name; // - check whether we have a region channel in our cache // - if not: // create it and cache it // - send it to the client // - send channel_uri: as "sip:regionID@m_sipDomain" try { LLSDParcelVoiceInfoResponse parcelVoiceInfo; string channelUri; if (null == scene.LandChannel) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatarName)); // get channel_uri: check first whether estate // settings allow voice, then whether parcel allows // voice, if all do retrieve or obtain the parcel // voice channel LandData land = scene.GetLandData(avatar.AbsolutePosition); //m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param); // TODO: EstateSettings don't seem to get propagated... // if (!scene.RegionInfo.EstateSettings.AllowVoice) // { // m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": voice not enabled in estate settings", // scene.RegionInfo.RegionName); // channel_uri = String.Empty; // } // else if ((land.Flags & (uint)ParcelFlags.AllowVoiceChat) == 0) { // m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel", // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName); channelUri = String.Empty; } else { channelUri = ChannelUri(scene, land); } // fill in our response to the client Hashtable creds = new Hashtable(); creds["channel_uri"] = channelUri; parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds); string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); // m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}", // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r); return r; } catch (Exception e) { m_log.ErrorFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": avatar \"{1}\": {2}, retry later", scene.RegionInfo.RegionName, avatarName, e.Message); m_log.DebugFormat("[FreeSwitchVoice][PARCELVOICE]: region \"{0}\": avatar \"{1}\": {2} failed", scene.RegionInfo.RegionName, avatarName, e.ToString()); return "<llsd>undef</llsd>"; } }
/// Callback for a client request for ParcelVoiceInfo public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, UUID agentID) { m_log.Debug("[MurmurVoice] Calling ParcelVoiceInfoRequest..."); try { ScenePresence avatar = scene.GetScenePresence(agentID); string channel_uri = String.Empty; if (null == scene.LandChannel) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatar.Name)); // get channel_uri: check first whether estate // settings allow voice, then whether parcel allows // voice, if all do retrieve or obtain the parcel // voice channel LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); if (null == land) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatar.Name)); m_log.DebugFormat("[MurmurVoice] region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", scene.RegionInfo.RegionName, land.Name, land.LocalID, avatar.Name, request, path, param); if (((land.Flags & (uint)ParcelFlags.AllowVoiceChat) > 0) && scene.RegionInfo.EstateSettings.AllowVoice) { ServerManager manager = GetServerManager(scene); Agent agent = manager.Agent.GetOrCreate(agentID, scene); if (agent == null) { m_log.ErrorFormat("[MurmurVoice] Agent not connected {0}", agentID); return "<llsd><undef /></llsd>"; } agent.channel = manager.Channel.GetOrCreate(ChannelName(scene, land)); // Wait for session connect int retry = 0; while (agent.session < 0) { if (++retry > 50) { m_log.ErrorFormat("[MurmurVoice] Connecting failed {0} (uid {1}) identified by {2}", agent.uuid.ToString(), agent.userid, agent.pass); return "<llsd><undef /></llsd>"; } Thread.Sleep(200); } // Host/port pair for voice server channel_uri = String.Format("{0}:{1}", m_murmurd_host, m_murmurd_port); Murmur.User state = manager.Server.getState(agent.session); GetServerCallback(scene).AddUserToChan(state, agent.channel); m_log.DebugFormat("[MurmurVoice] {0}", channel_uri); } else { m_log.DebugFormat("[MurmurVoice] Voice not enabled."); } Hashtable creds = new Hashtable(); creds["channel_uri"] = channel_uri; LLSDParcelVoiceInfoResponse parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds); string r = LLSDHelpers.SerialiseLLSDReply(parcelVoiceInfo); m_log.DebugFormat("[MurmurVoice] Parcel: {0}", r); return r; } catch (Exception e) { m_log.ErrorFormat("[MurmurVoice] Exception: " + e.ToString()); return "<llsd><undef /></llsd>"; } }
/// <summary> /// Callback for a client request for ParcelVoiceInfo /// </summary> /// <param name="scene">current scene object of the client</param> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param"></param> /// <param name="agentID"></param> /// <param name="caps"></param> /// <returns></returns> public string ParcelVoiceInfoRequest(Scene scene, string request, string path, string param, UUID agentID, Caps caps) { ScenePresence avatar = scene.GetScenePresence(agentID); if (avatar == null) // seen on the main grid, perhaps on user disconnect or viewer crash return EMPTY_RESPONSE; string avatarName = avatar.Name; // - check whether we have a region channel in our cache // - if not: // create it and cache it // - send it to the client // - send channel_uri: as "sip:regionID@m_sipDomain" try { LLSDParcelVoiceInfoResponse parcelVoiceInfo; string channel_uri; if (null == scene.LandChannel) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatarName)); // If the avatar is in transit between regions, avatar.AbsolutePosition calls below can return undefined values. if (avatar.IsInTransit) { m_log.WarnFormat("[VivoxVoice][PARCELVOICE]: Cannot process voice info request - avatar {0} is still in transit between regions.", avatarName); return EMPTY_RESPONSE; } // get channel_uri: check first whether estate // settings allow voice, then whether parcel allows // voice, if all do retrieve or obtain the parcel // voice channel LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); if (land == null) { // m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": avatar\"{1}\" at ({2}): Land parcel not found.", // scene.RegionInfo.RegionName, avatarName, avatar.AbsolutePosition.ToString()); return EMPTY_RESPONSE; } // m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, request, path, param); // m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: avatar \"{0}\": location: {1} {2} {3}", // avatarName, avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y, avatar.AbsolutePosition.Z); // TODO: EstateSettings don't seem to get propagated... if (!scene.RegionInfo.EstateSettings.AllowVoice) { m_log.InfoFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": voice not enabled in estate settings", scene.RegionInfo.RegionName); channel_uri = String.Empty; } if ((land.Flags & (uint)ParcelFlags.AllowVoiceChat) == 0) { m_log.InfoFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": voice not enabled for parcel", scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName); channel_uri = String.Empty; } else { channel_uri = RegionGetOrCreateChannel(scene, land); } // fill in our response to the client Hashtable creds = new Hashtable(); creds["channel_uri"] = channel_uri; parcelVoiceInfo = new LLSDParcelVoiceInfoResponse(scene.RegionInfo.RegionName, land.LocalID, creds); string r = LLSDHelpers.SerializeLLSDReply(parcelVoiceInfo); // m_log.DebugFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": {4}", // scene.RegionInfo.RegionName, land.Name, land.LocalID, avatarName, r); return r; } catch (Exception e) { m_log.ErrorFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": avatar \"{1}\": {2} failed", scene.RegionInfo.RegionName, avatarName, e.Message); m_log.ErrorFormat("[VivoxVoice][PARCELVOICE]: region \"{0}\": avatar \"{1}\": {2} exception", scene.RegionInfo.RegionName, avatarName, e.ToString()); return EMPTY_RESPONSE; } }
/// <summary> /// Returns information about a mumble server via a REST Request /// </summary> /// <param name="request"></param> /// <param name="path"></param> /// <param name="param">A string representing the sim's UUID</param> /// <param name="httpRequest">HTTP request header object</param> /// <param name="httpResponse">HTTP response header object</param> /// <returns>Information about the mumble server in http response headers</returns> public string RestGetMumbleServerInfo(Scene scene, string request, string path, string param, OSHttpRequest httpRequest, OSHttpResponse httpResponse) { if (m_murmurd_host == null) { httpResponse.StatusCode = 404; httpResponse.StatusDescription = "Not Found"; string message = "[MurmurVoice]: Server info request from " + httpRequest.RemoteIPEndPoint.Address + ". Cannot send response, module is not configured properly."; m_log.Warn(message); return "Mumble server info is not available."; } if (httpRequest.Headers.GetValues("avatar_uuid") == null) { httpResponse.StatusCode = 400; httpResponse.StatusDescription = "Bad Request"; string message = "[MurmurVoice]: Invalid server info request from " + httpRequest.RemoteIPEndPoint.Address + ""; m_log.Warn(message); return "avatar_uuid header is missing"; } string avatar_uuid = httpRequest.Headers.GetValues("avatar_uuid")[0]; string responseBody = String.Empty; UUID avatarId; if (UUID.TryParse(avatar_uuid, out avatarId)) { if (scene == null) throw new Exception("[MurmurVoice] Invalid scene."); ServerManager manager = GetServerManager(scene); Agent agent = manager.Agent.GetOrCreate(avatarId, scene); string channel_uri; ScenePresence avatar = scene.GetScenePresence(avatarId); // get channel_uri: check first whether estate // settings allow voice, then whether parcel allows // voice, if all do retrieve or obtain the parcel // voice channel LandData land = scene.GetLandData(avatar.AbsolutePosition.X, avatar.AbsolutePosition.Y); if (null == land) throw new Exception(String.Format("region \"{0}\": avatar \"{1}\": land data not yet available", scene.RegionInfo.RegionName, avatar.Name)); m_log.DebugFormat("[MurmurVoice] region \"{0}\": Parcel \"{1}\" ({2}): avatar \"{3}\": request: {4}, path: {5}, param: {6}", scene.RegionInfo.RegionName, land.Name, land.LocalID, avatar.Name, request, path, param); if (((land.Flags & (uint)ParcelFlags.AllowVoiceChat) > 0) && scene.RegionInfo.EstateSettings.AllowVoice) { agent.channel = manager.Channel.GetOrCreate(ChannelName(scene, land)); // Host/port pair for voice server channel_uri = String.Format("{0}:{1}", m_murmurd_host, m_murmurd_port); if (agent.session > 0) { Murmur.User state = manager.Server.getState(agent.session); GetServerCallback(scene).AddUserToChan(state, agent.channel); } m_log.InfoFormat("[MurmurVoice] {0}", channel_uri); } else { m_log.DebugFormat("[MurmurVoice] Voice not enabled."); channel_uri = ""; } string m_context = "Mumble voice system"; httpResponse.AddHeader("Mumble-Server", m_murmurd_host); httpResponse.AddHeader("Mumble-Version", m_server_version); httpResponse.AddHeader("Mumble-Channel", channel_uri); httpResponse.AddHeader("Mumble-User", avatar_uuid); httpResponse.AddHeader("Mumble-Password", agent.pass); httpResponse.AddHeader("Mumble-Avatar-Id", avatar_uuid); httpResponse.AddHeader("Mumble-Context-Id", m_context); responseBody += "Mumble-Server: " + m_murmurd_host + "\n"; responseBody += "Mumble-Version: " + m_server_version + "\n"; responseBody += "Mumble-Channel: " + channel_uri + "\n"; responseBody += "Mumble-User: "******"\n"; responseBody += "Mumble-Password: "******"\n"; responseBody += "Mumble-Avatar-Id: " + avatar_uuid + "\n"; responseBody += "Mumble-Context-Id: " + m_context + "\n"; string log_message = "[MurmurVoice]: Server info request handled for " + httpRequest.RemoteIPEndPoint.Address + ""; m_log.Info(log_message); } else { httpResponse.StatusCode = 400; httpResponse.StatusDescription = "Bad Request"; m_log.Warn("[MurmurVoice]: Could not parse avatar uuid from request"); return "could not parse avatar_uuid header"; } return responseBody; }