diff --git a/OpenSim/Addons/os-webrtc-janus/Janus/JanusAudioBridge.cs b/OpenSim/Addons/os-webrtc-janus/Janus/JanusAudioBridge.cs
index b6186b55ab..3052681c45 100644
--- a/OpenSim/Addons/os-webrtc-janus/Janus/JanusAudioBridge.cs
+++ b/OpenSim/Addons/os-webrtc-janus/Janus/JanusAudioBridge.cs
@@ -84,12 +84,12 @@ namespace osWebRtcVoice
/// boolean on whether room will be spatial or non-spatial
/// added as "description" to the created room
///
- public async Task CreateRoom(int pRoomId, bool pSpatial, string pRoomDesc)
+ public async Task CreateRoom(int pRoomId, bool pSpatial, string pRoomDesc, string credentials)
{
JanusRoom ret = null;
try
{
- JanusMessageResp resp = await SendPluginMsg(new AudioBridgeCreateRoomReq(pRoomId, pSpatial, pRoomDesc)).ConfigureAwait(false);
+ JanusMessageResp resp = await SendPluginMsg(new AudioBridgeCreateRoomReq(pRoomId, pSpatial, pRoomDesc, credentials)).ConfigureAwait(false);
AudioBridgeResp abResp = new(resp);
m_log.Debug($"{LogHeader} CreateRoom. ReturnCode: '{abResp.AudioBridgeReturnCode}'");
@@ -156,7 +156,7 @@ namespace osWebRtcVoice
// The attempt is to deterministicly create a room number so all regions will generate the
// same room number across sessions and across the grid.
// getHashCode() is not deterministic across sessions.
- public static int CalcRoomNumber(string pRegionId, string pChannelType, int pParcelLocalID, string pChannelID)
+ public static int CalcRoomNumber(string regionID, string gridhash, string pChannelType, int pParcelLocalID, string pChannelID)
{
BHasherMdjb2 hasher = new();
// If there is a channel specified it must be group
@@ -164,13 +164,12 @@ namespace osWebRtcVoice
{
case "local":
// A "local" channel is unique to the region and parcel
- hasher.Add(pRegionId);
+ hasher.Add(regionID);
hasher.Add(pChannelType);
hasher.Add(pParcelLocalID);
break;
case "multiagent":
- // A "multiagent" channel is unique to the grid
- // should add a GridId here
+ hasher.Add(gridhash);
hasher.Add(pChannelID);
hasher.Add(pChannelType);
break;
@@ -184,61 +183,61 @@ namespace osWebRtcVoice
return roomNumber;
}
- public async Task SelectRoom(string pRegionId, string pChannelType, bool pSpatial, int pParcelLocalID, string pChannelID)
+ public async Task SelectRoom(string pRegionId, string pgridhash, string pChannelType, bool pSpatial, int pParcelLocalID, string pChannelID, string credentials)
{
- int roomNumber = CalcRoomNumber(pRegionId, pChannelType, pParcelLocalID, pChannelID);
+ int roomNumber = CalcRoomNumber(pRegionId, pgridhash, pChannelType, pParcelLocalID, pChannelID);
// Should be unique for the given use and channel type
- m_log.DebugFormat("{0} SelectRoom: roomNumber={1}", LogHeader, roomNumber);
+ m_log.Debug($"{LogHeader} SelectRoom: roomNumber={roomNumber}");
// Check to see if the room has already been created
+ JanusRoom existingRoom;
lock (_rooms)
{
- if (_rooms.ContainsKey(roomNumber))
+ if (_rooms.TryGetValue(roomNumber, out existingRoom))
{
- return _rooms[roomNumber];
+ return existingRoom;
}
}
// The room doesn't exist. Create it.
- string roomDesc = pRegionId + "/" + pChannelType + "/" + pParcelLocalID + "/" + pChannelID;
- JanusRoom ret = await CreateRoom(roomNumber, pSpatial, roomDesc).ConfigureAwait(false);
+ string roomDesc;
+ if(pChannelType == "local")
+ roomDesc = $"{pRegionId}/{pChannelType}/{pParcelLocalID}";
+ else
+ roomDesc = $"{pgridhash}/{pChannelType}/{pChannelID}";
+
+ JanusRoom ret = await CreateRoom(roomNumber, pSpatial, roomDesc, credentials).ConfigureAwait(false);
- JanusRoom existingRoom = null;
if (ret is not null)
{
lock (_rooms)
{
- if (_rooms.ContainsKey(roomNumber))
+ if(!_rooms.TryGetValue(roomNumber, out existingRoom))
{
// If the room was created while we were waiting,
- existingRoom = _rooms[roomNumber];
- }
- else
- {
- // Our room is the first one created. Save it.
_rooms[roomNumber] = ret;
}
}
}
+
if (existingRoom is not null)
{
// The room we created was already created by someone else. Delete ours and use the existing one
- await DestroyRoom(ret);
- ret = existingRoom;
+ await DestroyRoom(ret).ConfigureAwait(false);
+ return existingRoom;
}
+
return ret;
}
// Return the room with the given room ID or 'null' if no such room
- public JanusRoom GetRoom(int pRoomId)
+ public bool GetRoom(int pRoomId, out JanusRoom room)
{
- JanusRoom ret = null;
lock (_rooms)
{
- _rooms.TryGetValue(pRoomId, out ret);
+ return _rooms.TryGetValue(pRoomId, out room);
}
- return ret;
}
public override void Handle_Event(JanusMessageResp pResp)
@@ -250,8 +249,8 @@ namespace osWebRtcVoice
// An audio bridge event!
m_log.DebugFormat("{0} Handle_Event. {1}", LogHeader, abResp.ToString());
}
-
}
+
public override void Handle_Message(JanusMessageResp pResp)
{
base.Handle_Message(pResp);
@@ -261,7 +260,6 @@ namespace osWebRtcVoice
// An audio bridge event!
m_log.DebugFormat("{0} Handle_Event. {1}", LogHeader, abResp.ToString());
}
-
}
}
}
diff --git a/OpenSim/Addons/os-webrtc-janus/Janus/JanusMessages.cs b/OpenSim/Addons/os-webrtc-janus/Janus/JanusMessages.cs
index 44f4378d56..195f4d6080 100644
--- a/OpenSim/Addons/os-webrtc-janus/Janus/JanusMessages.cs
+++ b/OpenSim/Addons/os-webrtc-janus/Janus/JanusMessages.cs
@@ -514,11 +514,11 @@ namespace osWebRtcVoice
// ==============================================================
public class AudioBridgeCreateRoomReq : PluginMsgReq
{
- public AudioBridgeCreateRoomReq(int pRoomId) : this(pRoomId, false, null)
+ public AudioBridgeCreateRoomReq(int pRoomId) : this(pRoomId, false, null, null)
{
}
- public AudioBridgeCreateRoomReq(int pRoomId, bool pSpatial, string pDesc) : base(new OSDMap() {
+ public AudioBridgeCreateRoomReq(int pRoomId, bool pSpatial, string pDesc, string credentials) : base(new OSDMap() {
{ "room", pRoomId },
{ "request", "create" },
{ "is_private", false },
@@ -531,6 +531,8 @@ namespace osWebRtcVoice
{
if (!string.IsNullOrEmpty(pDesc))
AddStringToBody("description", pDesc);
+ if (!string.IsNullOrEmpty(credentials))
+ AddStringToBody("pin", credentials);
}
}
diff --git a/OpenSim/Addons/os-webrtc-janus/Janus/JanusRoom.cs b/OpenSim/Addons/os-webrtc-janus/Janus/JanusRoom.cs
index a49911fb4e..99ae57456e 100644
--- a/OpenSim/Addons/os-webrtc-janus/Janus/JanusRoom.cs
+++ b/OpenSim/Addons/os-webrtc-janus/Janus/JanusRoom.cs
@@ -59,7 +59,6 @@ namespace osWebRtcVoice
public async Task JoinRoom(JanusViewerSession pVSession)
{
- bool ret = false;
try
{
// m_log.DebugFormat("{0} JoinRoom. New joinReq for room {1}", LogHeader, RoomId);
@@ -79,10 +78,11 @@ namespace osWebRtcVoice
{
pVSession.ParticipantId = joinResp.ParticipantId;
pVSession.Answer = joinResp.Jsep;
- ret = true;
m_log.Debug($"{LogHeader} JoinRoom. Joined room {RoomId}. Participant={pVSession.ParticipantId}");
+ return true;
}
- else if (joinResp is not null && joinResp.AudioBridgeErrorCode == 491)
+
+ if (joinResp is not null && (joinResp.AudioBridgeErrorCode == 490 || joinResp.AudioBridgeErrorCode == 491))
{
m_log.Warn($"{LogHeader} JoinRoom. Already in a room for agent {pVSession.AgentId}. Attempting recovery.");
@@ -98,13 +98,11 @@ namespace osWebRtcVoice
{
pVSession.ParticipantId = retryJoinResp.ParticipantId;
pVSession.Answer = retryJoinResp.Jsep;
- ret = true;
m_log.Info($"{LogHeader} JoinRoom. Recovery succeeded for room {RoomId}. Participant={pVSession.ParticipantId}");
+ return true;
}
- else
- {
- m_log.Error($"{LogHeader} JoinRoom. Recovery retry failed for room {RoomId}. Resp={retryJoinResp?.ToString() ?? "null"}");
- }
+
+ m_log.Error($"{LogHeader} JoinRoom. Recovery retry failed for room {RoomId}. Resp={retryJoinResp?.ToString() ?? "null"}");
}
else
{
@@ -120,18 +118,19 @@ namespace osWebRtcVoice
if (m_log.IsDebugEnabled)
m_log.DebugFormat("{0} JoinRoom. Invalid participant detail: {1}", LogHeader, joinResp.ToString());
}
-
- m_log.ErrorFormat("{0} JoinRoom. Failed to join room {1}", LogHeader, RoomId);
- if (m_log.IsDebugEnabled)
- m_log.DebugFormat("{0} JoinRoom. Failure detail: {1}", LogHeader, joinResp?.ToString() ?? "null");
-
+ else
+ {
+ m_log.ErrorFormat("{0} JoinRoom. Failed to join room {1}", LogHeader, RoomId);
+ if (m_log.IsDebugEnabled)
+ m_log.DebugFormat("{0} JoinRoom. Failure detail: {1}", LogHeader, joinResp?.ToString() ?? "null");
+ }
}
}
catch (Exception e)
{
m_log.Error($"{LogHeader} JoinRoom. Exception ", e);
}
- return ret;
+ return false;
}
private async Task RecoverAlreadyInRoomAndLeave(string pDisplay)
@@ -222,7 +221,6 @@ namespace osWebRtcVoice
public async Task LeaveRoom(JanusViewerSession pAttendeeSession)
{
- bool ret = false;
try
{
JanusMessageResp resp = await _AudioBridge.SendPluginMsg(
@@ -238,33 +236,31 @@ namespace osWebRtcVoice
string returnCode = abResp.AudioBridgeReturnCode;
string janusReturnCode = resp.ReturnCode;
int errorCode = abResp.AudioBridgeErrorCode;
- bool isBenignAlreadyLeft = errorCode == 487 &&
- (returnCode == "event" || janusReturnCode == "event" || janusReturnCode == "ack");
if (errorCode == 0 &&
(abResp.isSuccess || returnCode == "left" || returnCode == "event" || returnCode == "success" || janusReturnCode == "ack"))
{
- ret = true;
if (janusReturnCode == "ack" && string.IsNullOrEmpty(returnCode))
{
- m_log.Debug($"{LogHeader} LeaveRoom. Ack accepted for room {RoomId}, participant={pAttendeeSession.ParticipantId}");
+ m_log.Debug($"{LogHeader} LeaveRoom. Ack for room {RoomId}, participant={pAttendeeSession.ParticipantId}");
}
+ return true;
}
- else if (isBenignAlreadyLeft)
+
+ if (errorCode == 487 &&
+ (returnCode == "event" || janusReturnCode == "event" || janusReturnCode == "ack"))
{
- ret = true;
m_log.Info($"{LogHeader} LeaveRoom. Participant already left room {RoomId}, participant={pAttendeeSession.ParticipantId} (errorCode=487)");
+ return true;
}
- else
- {
- m_log.Error($"{LogHeader} LeaveRoom. Failed room {RoomId}, participant={pAttendeeSession.ParticipantId}, janus={janusReturnCode}, audiobridge={returnCode}, errorCode={errorCode}");
- }
+
+ m_log.Error($"{LogHeader} LeaveRoom. Failed room {RoomId}, participant={pAttendeeSession.ParticipantId}, janus={janusReturnCode}, audiobridge={returnCode}, errorCode={errorCode}");
}
catch (Exception e)
{
m_log.Error($"{LogHeader} LeaveRoom. Exception ", e);
}
- return ret;
+ return false;
}
}
}
diff --git a/OpenSim/Addons/os-webrtc-janus/Janus/JanusViewerSession.cs b/OpenSim/Addons/os-webrtc-janus/Janus/JanusViewerSession.cs
index 7ab3e801c9..bb6e3185d5 100644
--- a/OpenSim/Addons/os-webrtc-janus/Janus/JanusViewerSession.cs
+++ b/OpenSim/Addons/os-webrtc-janus/Janus/JanusViewerSession.cs
@@ -119,8 +119,11 @@ namespace osWebRtcVoice
{
JanusSession s = Session;
Session = null;
- _ = await s.DestroySession().ConfigureAwait(false);
- s.Dispose();
+ if(s != null)
+ {
+ _ = await s.DestroySession().ConfigureAwait(false);
+ s.Dispose();
+ }
}
}
}
diff --git a/OpenSim/Addons/os-webrtc-janus/Janus/WebRtcJanusService.cs b/OpenSim/Addons/os-webrtc-janus/Janus/WebRtcJanusService.cs
index eb74403d37..932f003238 100644
--- a/OpenSim/Addons/os-webrtc-janus/Janus/WebRtcJanusService.cs
+++ b/OpenSim/Addons/os-webrtc-janus/Janus/WebRtcJanusService.cs
@@ -164,12 +164,12 @@ namespace osWebRtcVoice
// Requests through the capabilities will create rooms
janusSession.AddPlugin(audioBridge);
-
pViewerSession.VoiceServiceSessionId = janusSession.SessionId;
pViewerSession.Session = janusSession;
pViewerSession.AudioBridge = audioBridge;
janusSession.OnDisconnect += Handle_Hangup;
janusSession.OnHangup += Handle_Hangup;
+
return true;
}
_log.Error($"{LogHeader} JanusPluginHandle not created");
@@ -245,9 +245,9 @@ namespace osWebRtcVoice
_log.InfoFormat("{0} ProvisionVoiceAccountRequest: disconnected by {1}. agent={2}, scene={3}, room={4}, participant={5}, viewer_session={6}",
LogHeader, pReason, pViewerSession.AgentId, pViewerSession.RegionId, roomId, pViewerSession.ParticipantId, pViewerSession.ViewerSessionID);
+ VoiceViewerSession.RemoveViewerSession(pViewerSession.ViewerSessionID);
Task.Run(() =>
{
- VoiceViewerSession.RemoveViewerSession(pViewerSession.ViewerSessionID);
// No need to wait for the session to be shutdown
_ = pViewerSession.Shutdown();
});
@@ -265,23 +265,31 @@ namespace osWebRtcVoice
public async Task ProvisionVoiceAccountRequestBAD(IVoiceViewerSession pSession, OSDMap pRequest, UUID pUserID, UUID pSceneID)
{
+ long flowId = Interlocked.Increment(ref _VoiceFlowCounter);
+ if(pRequest.TryGetString("voice_server_type", out string voice_server_type))
+ {
+ if(!"webrtc".Equals(voice_server_type,StringComparison. CurrentCultureIgnoreCase))
+ {
+ _log.Error($"{LogHeader} ProvisionVoiceAccountRequest: invalid server type {voice_server_type ?? "null"}");
+ return new OSDMap
+ {
+ { "response", "failed" },
+ { "error", "Invalid server type" }
+ };
+ }
+ }
+
OSDMap ret = null;
string errorMsg = null;
JanusViewerSession viewerSession = pSession as JanusViewerSession;
- long flowId = Interlocked.Increment(ref _VoiceFlowCounter);
+
if (viewerSession is not null)
{
- if (viewerSession.Session is null)
- {
- // This is a new session so we must create a new session and handle to the audio bridge
- await ConnectToSessionAndAudioBridge(viewerSession).ConfigureAwait(false);
- }
-
// TODO: need to keep count of users in a room to know when to close a room
bool isLogout = pRequest.TryGetBool("logout", out bool lgout) && lgout;
if (isLogout)
{
- // The client is logging out. Exit the room.
+ // Exit the room.
if (viewerSession.Room is not null)
{
_ = await viewerSession.Room.LeaveRoom(viewerSession).ConfigureAwait(false);
@@ -296,14 +304,20 @@ namespace osWebRtcVoice
};
}
+ if (viewerSession.Session is null)
+ {
+ // This is a new session so we must create a new session and handle to the audio bridge
+ await ConnectToSessionAndAudioBridge(viewerSession).ConfigureAwait(false);
+ }
+
// Get the parameters that select the room
// To get here, voice_server_type has already been checked to be 'webrtc' and channel_type='local'
int parcel_local_id = pRequest.TryGetInt("parcel_local_id", out int pli) ? pli : JanusAudioBridge.REGION_ROOM_ID;
string channel_id = pRequest.TryGetString("channel_id", out string cli) ? cli : string.Empty;
string channel_credentials = pRequest.TryGetString("credentials", out string cred) ? cred : string.Empty;
string channel_type = pRequest["channel_type"].AsString();
+ string gridHash = pRequest.TryGetString("gridhash", out string ghash) ? ghash : string.Empty;
bool isSpatial = channel_type == "local";
- string voice_server_type = pRequest["voice_server_type"].AsString();
_log.DebugFormat("{0} ProvisionVoiceAccountRequest: parcel_id={1} channel_id={2} channel_type={3} voice_server_type={4}", LogHeader, parcel_local_id, channel_id, channel_type, voice_server_type);
@@ -320,14 +334,15 @@ namespace osWebRtcVoice
{
// The client is sending an offer. Find the right room and join it.
// _log.DebugFormat("{0} ProvisionVoiceAccountRequest: jsep type={1} sdp={2}", LogHeader, jsepType, jsepSdp);
- viewerSession.Room = await viewerSession.AudioBridge.SelectRoom(pSceneID.ToString(),
- channel_type, isSpatial, parcel_local_id, channel_id).ConfigureAwait(false);
+ viewerSession.Room = await viewerSession.AudioBridge.SelectRoom(pSceneID.ToString(), gridHash,
+ channel_type, isSpatial, parcel_local_id, channel_id, channel_credentials).ConfigureAwait(false);
if (viewerSession.Room is null)
{
errorMsg = "room selection failed";
_log.Error($"{LogHeader} ProvisionVoiceAccountRequest: room selection failed");
}
- else {
+ else
+ {
viewerSession.Offer = jsepSdp;
viewerSession.OfferOrig = jsepSdp;
viewerSession.AgentId = pUserID;
@@ -399,7 +414,7 @@ namespace osWebRtcVoice
JanusViewerSession viewerSession = pSession as JanusViewerSession;
JanusMessageResp resp = null;
long flowId = Interlocked.Increment(ref _VoiceFlowCounter);
- if (viewerSession is not null)
+ if (viewerSession is not null && viewerSession.Session is not null)
{
// The request should be an array of candidates
if (pRequest.TryGetOSDMap("candidate", out OSDMap candidate))
diff --git a/OpenSim/Addons/os-webrtc-janus/WebRtcVoiceRegionModule/WebRtcVoiceRegionModule.cs b/OpenSim/Addons/os-webrtc-janus/WebRtcVoiceRegionModule/WebRtcVoiceRegionModule.cs
index f1afd9c6d4..6329156a17 100644
--- a/OpenSim/Addons/os-webrtc-janus/WebRtcVoiceRegionModule/WebRtcVoiceRegionModule.cs
+++ b/OpenSim/Addons/os-webrtc-janus/WebRtcVoiceRegionModule/WebRtcVoiceRegionModule.cs
@@ -79,6 +79,8 @@ namespace osWebRtcVoice
private IWebRtcVoiceService m_spatialVoiceService;
private IWebRtcVoiceService m_nonSpatialVoiceService;
+ private UUID gridHash = UUID.Zero;
+
// ISharedRegionModule.Initialize
public void Initialise(IConfigSource config)
{
@@ -175,6 +177,14 @@ namespace osWebRtcVoice
scene.EventManager.OnNewClient += OnNewClient;
+ if(gridHash.IsZero())
+ {
+ if(!string.IsNullOrEmpty(scene.SceneGridInfo.GridUrl))
+ gridHash = Util.ComputeShake128UUID(scene.SceneGridInfo.GridUrl + scene.SceneGridInfo.GridName);
+ else if (!string.IsNullOrEmpty(scene.SceneGridInfo.HomeURL + scene.SceneGridInfo.GridName))
+ gridHash = Util.ComputeShake128UUID(scene.SceneGridInfo.HomeURLNoEndSlash);
+ }
+
ISimulatorFeaturesModule simFeatures = scene.RequestModuleInterface();
simFeatures?.AddFeature("VoiceServerType", OSD.FromString("webrtc"));
}
@@ -552,7 +562,7 @@ namespace osWebRtcVoice
}
else
{
- flags = IVoiceViewerSession.VFlags.IsEstate;
+ flags = IVoiceViewerSession.VFlags.IsEstate;
}
// TODO: check if this userId is making a new session (case that user is reconnecting)
@@ -583,6 +593,7 @@ namespace osWebRtcVoice
{
vSession.Flags = IVoiceViewerSession.VFlags.IsAdmin;
VoiceViewerSession.AddViewerSession(vSession);
+ map["gridhash"] = gridHash;
}
}
}