some changes adapted from Manni patch in mantis 9235 note participantID still type int

This commit is contained in:
UbitUmarov
2026-03-14 20:55:05 +00:00
parent 8d7d2afd78
commit e661b5d6b5
2 changed files with 164 additions and 25 deletions

View File

@@ -72,13 +72,13 @@ namespace osWebRtcVoice
public string TransactionId
{
get { return m_message.TryGetString("transaction", out string tid) ? tid : null; }
get { return m_message.TryGetString("transaction", out string tid) ? tid : null; }
set { m_message["transaction"] = value; }
}
public string Sender
{
get { return m_message.TryGetString("sender", out string tid) ? tid : null; }
get { return m_message.TryGetString("sender", out string tid) ? tid : null; }
set { m_message["sender"] = value; }
}
@@ -199,7 +199,7 @@ namespace osWebRtcVoice
}
// Return the "data" portion of the response as an OSDMap or null if there is none
public OSDMap dataSection { get { return m_message.TryGetOSDMap("data", out OSDMap osdm) ? osdm : null; } }
public OSDMap dataSection { get { return m_message.TryGetOSDMap("data", out OSDMap data) ? data : null; } }
// Check if a successful response code is in the response
public virtual bool isSuccess { get { return CheckReturnCode("success"); } }
@@ -216,8 +216,8 @@ namespace osWebRtcVoice
{
get
{
return m_message is not null && m_message.ContainsKey("janus") ?
m_message["janus"].AsString() : string.Empty;
return m_message is not null && m_message.TryGetString("janus", out string sjanus) ?
sjanus : string.Empty;
}
}
}
@@ -464,6 +464,14 @@ namespace osWebRtcVoice
return m_data.TryGetValue(pKey, out OSD okey) ? (int)okey.AsLong(): 0;
}
// Get an long value for a key in the response data or zero if not there
public long PluginRespDataLong(string pKey)
{
if (m_data is null)
return 0L;
return m_data.TryGetValue(pKey, out OSD okey) ? okey.AsLong(): 0L;
}
// Get a string value for a key in the response data or empty string if not there
public string PluginRespDataString(string pKey)
{
@@ -519,7 +527,7 @@ namespace osWebRtcVoice
{ "spatial_audio", pSpatial },
{ "denoise", false },
{ "record", false }
})
})
{
if (!String.IsNullOrEmpty(pDesc))
AddStringToBody("description", pDesc);
@@ -533,7 +541,7 @@ namespace osWebRtcVoice
{ "request", "destroy" },
{ "room", pRoomId },
{ "permanent", true }
})
})
{
}
}
@@ -558,6 +566,7 @@ namespace osWebRtcVoice
}
public int ParticipantId { get { return PluginRespDataInt("id"); } }
//public long ParticipantId { get { return PluginRespDataLong("id"); } }
}
// ==============================================================
@@ -565,7 +574,7 @@ namespace osWebRtcVoice
{
// TODO:
public AudioBridgeConfigRoomReq(int pRoomId, string pSdp) : base(new OSDMap() {
{ "request", "configure" },
{ "request", "configure" }
})
{
}
@@ -586,7 +595,7 @@ namespace osWebRtcVoice
{ "request", "leave" },
{ "room", pRoomId },
{ "id", pAttendeeId }
})
})
{
}
}
@@ -607,7 +616,7 @@ namespace osWebRtcVoice
public AudioBridgeListParticipantsReq(int pRoom) : base(new OSDMap() {
{ "request", "listparticipants" },
{ "room", pRoom }
})
})
{
}
}

View File

@@ -28,18 +28,11 @@
using System;
using System.Reflection;
using OpenSim.Framework;
using OpenSim.Services.Interfaces;
using OpenSim.Services.Base;
using OpenMetaverse.StructuredData;
using OpenMetaverse;
using Nini.Config;
using log4net;
using System.Threading.Tasks;
using System.Text.RegularExpressions;
using System.Collections.Generic;
namespace osWebRtcVoice
{
@@ -76,30 +69,136 @@ namespace osWebRtcVoice
// and, if removed, the viewer complains that the "m=" sections are
// out of order. Not "cleaning" (removing the data section) seems to work.
// string cleanSdp = CleanupSdp(pSdp);
var joinReq = new AudioBridgeJoinRoomReq(RoomId, pVSession.AgentId.ToString());
AudioBridgeJoinRoomReq joinReq = new(RoomId, pVSession.AgentId.ToString());
// joinReq.SetJsep("offer", cleanSdp);
joinReq.SetJsep("offer", pVSession.Offer);
JanusMessageResp resp = await _AudioBridge.SendPluginMsg(joinReq);
AudioBridgeJoinRoomResp joinResp = new AudioBridgeJoinRoomResp(resp);
AudioBridgeJoinRoomResp joinResp = new(resp);
// if (joinResp is not null && joinResp.AudioBridgeReturnCode == "joined" && joinResp.ParticipantId > 0)
if (joinResp is not null && joinResp.AudioBridgeReturnCode == "joined")
{
pVSession.ParticipantId = joinResp.ParticipantId;
pVSession.Answer = joinResp.Jsep;
ret = true;
m_log.DebugFormat("{0} JoinRoom. Joined room {1}. Participant={2}", LogHeader, RoomId, pVSession.ParticipantId);
m_log.Debug($"{LogHeader} JoinRoom. Joined room {RoomId}. Participant={pVSession.ParticipantId}");
}
else if (joinResp is not null && joinResp.AudioBridgeErrorCode == 491)
{
m_log.Warn($"{LogHeader} JoinRoom. Already in a room for agent {pVSession.AgentId}. Attempting recovery.");
bool recovered = await RecoverAlreadyInRoomAndLeave(pVSession.AgentId.ToString());
if (recovered)
{
AudioBridgeJoinRoomReq retryJoinReq = new(RoomId, pVSession.AgentId.ToString());
retryJoinReq.SetJsep("offer", pVSession.Offer);
JanusMessageResp retryResp = await _AudioBridge.SendPluginMsg(retryJoinReq);
AudioBridgeJoinRoomResp retryJoinResp = new(retryResp);
// if (retryJoinResp is not null && retryJoinResp.AudioBridgeReturnCode == "joined" && retryJoinResp.ParticipantId > 0)
if (retryJoinResp is not null && retryJoinResp.AudioBridgeReturnCode == "joined")
{
pVSession.ParticipantId = retryJoinResp.ParticipantId;
pVSession.Answer = retryJoinResp.Jsep;
ret = true;
m_log.Info($"{LogHeader} JoinRoom. Recovery succeeded for room {RoomId}. Participant={pVSession.ParticipantId}");
}
else
{
m_log.Error($"{LogHeader} JoinRoom. Recovery retry failed for room {RoomId}. Resp={retryJoinResp?.ToString() ?? "null"}");
}
}
else
{
m_log.Error($"{LogHeader} JoinRoom. Recovery failed: could not clear previous room membership. Resp={joinResp}");
}
}
/*
else
{
m_log.ErrorFormat("{0} JoinRoom. Failed to join room {1}. Resp={2}", LogHeader, RoomId, joinResp.ToString());
if (joinResp is not null && joinResp.AudioBridgeReturnCode == "joined" && joinResp.ParticipantId <= 0)
{
m_log.Error($"{LogHeader} JoinRoom. Joined response contains invalid participant id {joinResp.ParticipantId} for room {RoomId}. Resp={joinResp}");
}
m_log.Error($"{LogHeader} JoinRoom. Failed to join room {RoomId}. Resp={joinResp}");
}
*/
}
catch (Exception e)
{
m_log.Error($"{LogHeader} JoinRoom. Exception ", e);
}
return ret;
}
private async Task<bool> RecoverAlreadyInRoomAndLeave(string pDisplay)
{
try
{
JanusMessageResp listRoomsRespRaw = await _AudioBridge.SendPluginMsg(new AudioBridgeListRoomsReq());
AudioBridgeResp listRoomsResp = new AudioBridgeResp(listRoomsRespRaw);
if (listRoomsResp?.PluginRespData is null ||
!listRoomsResp.PluginRespData.TryGetValue("list", out OSD roomListNode) ||
roomListNode is not OSDArray roomList)
{
return false;
}
foreach (OSD roomNode in roomList)
{
if (roomNode is not OSDMap roomMap ||
!roomMap.TryGetValue("room", out OSD roomIdNode))
continue;
int roomId = roomIdNode.AsInteger();
// if (roomId <= 0)
// continue;
JanusMessageResp listParticipantsRespRaw = await _AudioBridge.SendPluginMsg(new AudioBridgeListParticipantsReq(roomId));
AudioBridgeResp listParticipantsResp = new AudioBridgeResp(listParticipantsRespRaw);
if (listParticipantsResp?.PluginRespData is null ||
!listParticipantsResp.PluginRespData.TryGetValue("participants", out OSD participantsNode) ||
participantsNode is not OSDArray participants)
continue;
foreach (OSD participantNode in participants)
{
if (participantNode is not OSDMap participant)
continue;
string display = participant.TryGetValue("display", out OSD displayNode) ? displayNode.AsString() : string.Empty;
if (!string.Equals(display, pDisplay, StringComparison.Ordinal))
continue;
int participantId = participant.TryGetValue("id", out OSD idNode) ? (int)idNode.AsLong() : 0;
if (participantId <= 0)
continue;
JanusMessageResp leaveRespRaw = await _AudioBridge.SendPluginMsg(new AudioBridgeLeaveRoomReq(roomId, participantId));
AudioBridgeResp leaveResp = new(leaveRespRaw);
if (leaveResp is not null)
{
int errorCode = leaveResp.AudioBridgeErrorCode;
string abCode = leaveResp.AudioBridgeReturnCode;
string janusCode = leaveRespRaw.ReturnCode;
if (errorCode == 0 || abCode == "left" || abCode == "event" || janusCode == "ack")
{
m_log.Info($"{LogHeader} RecoverAlreadyInRoomAndLeave. Cleared stale participant {participantId} from room {roomId}");
return true;
}
}
}
}
}
catch (Exception e)
{
m_log.ErrorFormat("{0} JoinRoom. Exception {1}", LogHeader, e);
m_log.Error($"{LogHeader} RecoverAlreadyInRoomAndLeave. Exception ", e);
}
return ret;
return false;
}
// TODO: this doesn't work.
@@ -126,13 +225,44 @@ namespace osWebRtcVoice
{
JanusMessageResp resp = await _AudioBridge.SendPluginMsg(
new AudioBridgeLeaveRoomReq(RoomId, pAttendeeSession.ParticipantId));
if (resp is null)
{
m_log.Error($"{LogHeader} LeaveRoom. Null response for room {RoomId}, participant={pAttendeeSession.ParticipantId}");
return false;
}
AudioBridgeResp abResp = new(resp);
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}");
}
}
else if (isBenignAlreadyLeft)
{
ret = true;
m_log.Info($"{LogHeader} LeaveRoom. Participant already left room {RoomId}, participant={pAttendeeSession.ParticipantId} (errorCode=487)");
}
else
{
m_log.Error($"{LogHeader} LeaveRoom. Failed room {RoomId}, participant={pAttendeeSession.ParticipantId}, janus={janusReturnCode}, audiobridge={returnCode}, errorCode={errorCode}");
}
}
catch (Exception e)
{
m_log.ErrorFormat("{0} LeaveRoom. Exception {1}", LogHeader, e);
m_log.Error($"{LogHeader} LeaveRoom. Exception ", e);
}
return ret;
}
}
}