mirror of
https://github.com/opensim/opensim.git
synced 2026-05-13 01:46:07 +08:00
some changes adapted from Manni patch in mantis 9235 note participantID still type int
This commit is contained in:
@@ -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 }
|
||||
})
|
||||
})
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user