本地优化

This commit is contained in:
2026-06-03 22:05:03 +08:00
parent a6509ea9ee
commit fea67869f2
18 changed files with 996 additions and 65 deletions

View File

@@ -31,6 +31,9 @@ public interface IGlobalConfigSystem : ISystem
public string GetUserId();
public void SetUserId(string userId);
public string GetParticipantId();
public void SetParticipantId(string participantId);
}
public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
@@ -65,6 +68,8 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
/// </summary>
private int _connectionTimeType;
private string _participantId;
private CancellationTokenSource _cts;
@@ -211,6 +216,16 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
_connectionAvatar = connectionTexture;
}
public string GetParticipantId()
{
return _participantId;
}
public void SetParticipantId(string participantId)
{
_participantId = participantId;
}
protected override void OnInit()
{
}

View File

@@ -128,6 +128,11 @@ namespace Script
await WebRTCUtil.DownloadAndSetAvatar(obj[i].avatar,
entry.transform.Find("image").GetComponent<Image>());
_userMap.TryAdd(obj[i], entry);
if (obj[i].role == "host")
{
this.GetSystem<IGlobalConfigSystem>().SetParticipantId(obj[i].participantId);
}
}
// 更新会议聊天面板人数

View File

@@ -1,6 +1,7 @@
using System.Collections.Generic;
using Newtonsoft.Json;
using RenderStreaming;
using Script.Recorder;
using Script.Util;
using Stary.Evo;
using Stary.Evo.UIFarme;
@@ -58,7 +59,7 @@ namespace Script
_audioStreamSender = GameObject.Find("RenderStreaming").GetComponent<AudioStreamSender>();
_videoStreamSender = GameObject.Find("RenderStreaming").GetComponent<VideoStreamSender>();
#if UNITY_EDITOR
_recorder = new EditorGameViewRecorder();
_recorder = new ServerMixedRecorder();
#elif UNITY_ANDROID
_recorder = new XrealMixedRecorder();
#else

View File

@@ -0,0 +1,260 @@
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using RenderStreaming;
using Stary.Evo;
using Unity.RenderStreaming;
using Unity.WebRTC;
using UnityEngine;
namespace Script.Recorder
{
public class EditorServerRecorder : IVideoRecorder, IController
{
public bool IsRecording { get; }
public Action OnStartedRecordingVideo { get; set; }
public Action<string> OnStoppedRecordingVideoAction { get; set; }
private string recordingId;
private readonly Dictionary<string, RTCPeerConnection> recordingPeers = new();
public WebcamToRenderTexture sourceRenderTexture;
public string microphoneDeviceName = ""; // 留空使用默认麦克风
public int microphoneSampleRate = 48000;
private AudioSource microphoneAudioSource;
private bool microphoneStarted;
private VideoStreamTrack videoTrack;
private AudioStreamTrack audioTrack;
public async void StartRecording()
{
await CreateLocalTracks();
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
messageChannel.OnRecordingPeerRequestReceived += OnRecordingPeerRequestReceived;
messageChannel.OnRecordingAnswerReceived += OnRecordingAnswerReceived;
messageChannel.OnRecordingCandidateReceived += OnRecordingCandidateReceived;
messageChannel.OnRecordingStoppedReceived += OnRecordingStoppedReceived;
var data = new
{
connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId(),
layout = "grid",
format = "webm",
};
var result = await WebRequestSystem.Post(
this.GetSystem<IGlobalConfigSystem>().IP + "/api/recording-sessions",
JsonConvert.SerializeObject(data));
if (result != null)
{
RecordingSession session = JsonConvert.DeserializeObject<RecordingSession>(result);
if (string.IsNullOrEmpty(session.success))
{
Debug.LogError($"[ServerMixedRecorder] StartRecording 失败: {session}");
return;
}
recordingId = session.session.id;
}
}
public async UniTask CreateLocalTracks()
{
if (sourceRenderTexture == null)
{
sourceRenderTexture =new GameObject("WebcamToRenderTexture").AddComponent<WebcamToRenderTexture>();
videoTrack = new VideoStreamTrack(sourceRenderTexture.renderTexture);
}
microphoneAudioSource =
GameObject.Find("RenderStreaming/microphoneAudioSource").GetComponent<AudioSource>();
microphoneAudioSource.loop = true;
microphoneAudioSource.mute = true;
string device = string.IsNullOrEmpty(microphoneDeviceName)
? null
: microphoneDeviceName;
microphoneAudioSource.clip = Microphone.Start(
device,
true,
1,
microphoneSampleRate
);
microphoneStarted = true;
await CreateMicrophoneTrackWhenReady(device);
}
public async UniTask CreateMicrophoneTrackWhenReady(string device)
{
while (Microphone.GetPosition(device) <= 0)
await UniTask.NextFrame();
microphoneAudioSource.Play();
audioTrack = new AudioStreamTrack(microphoneAudioSource);
}
public async void OnRecordingPeerRequestReceived(RecordingRequest request)
{
if (string.IsNullOrEmpty(request.recordingId))
return;
OnRecordingStoppedReceived(request.recordingId);
var config = new RTCConfiguration
{
iceServers = new[]
{
new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } }
}
};
var pc = new RTCPeerConnection(ref config);
recordingPeers[request.recordingId] = pc;
pc.OnIceCandidate = candidate =>
{
if (candidate == null) return;
Send("recording-candidate", new RecordingCandidate
{
recordingId = request.recordingId,
connectionId = request.connectionId,
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
candidate = candidate.Candidate,
sdpMid = candidate.SdpMid,
sdpMLineIndex = candidate.SdpMLineIndex ?? 0
});
};
if (videoTrack != null)
pc.AddTransceiver(videoTrack,
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
if (audioTrack != null)
pc.AddTransceiver(audioTrack,
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
var offerOp = pc.CreateOffer();
await offerOp;
var offer = offerOp.Desc;
var localOp = pc.SetLocalDescription(ref offer);
await localOp;
Send("recording-offer", new RecordingOffer
{
recordingId = request.recordingId,
connectionId = request.connectionId,
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
sdp = offer.sdp
});
}
public async void OnRecordingAnswerReceived(RecordingAnswer answer)
{
if (!recordingPeers.TryGetValue(answer.recordingId, out var pc))
return;
var desc = new RTCSessionDescription
{
type = RTCSdpType.Answer,
sdp = answer.sdp
};
var op = pc.SetRemoteDescription(ref desc);
await op;
}
public void OnRecordingCandidateReceived(RecordingCandidate data)
{
if (!recordingPeers.TryGetValue(data.recordingId, out var pc))
return;
var candidate = new RTCIceCandidate(new RTCIceCandidateInit
{
candidate = data.candidate,
sdpMid = data.sdpMid,
sdpMLineIndex = data.sdpMLineIndex
});
pc.AddIceCandidate(candidate);
}
public void OnRecordingStoppedReceived(string recordingId)
{
if (!recordingPeers.TryGetValue(recordingId, out var pc))
return;
pc.Close();
recordingPeers.Remove(recordingId);
}
void Send(string type, object data)
{
var connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
var json = JsonConvert.SerializeObject(new Dictionary<string, object>
{
["type"] = "on-message",
["data"] = new Dictionary<string, object>
{
["connectionId"] = connectionId,
["message"] = new Dictionary<string, object>
{
["type"] = type,
["data"] = data
}
}
});
SignalingMessageHelper.SendMessage(json);
}
public async void StopRecording()
{
await WebRequestSystem.Delete(this.GetSystem<IGlobalConfigSystem>().IP,
$"/api/recording-sessions/{recordingId}");
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
messageChannel.OnRecordingPeerRequestReceived -= OnRecordingPeerRequestReceived;
messageChannel.OnRecordingAnswerReceived -= OnRecordingAnswerReceived;
messageChannel.OnRecordingCandidateReceived -= OnRecordingCandidateReceived;
messageChannel.OnRecordingStoppedReceived -= OnRecordingStoppedReceived;
}
void OnDestroy()
{
foreach (var pc in recordingPeers.Values)
pc.Close();
recordingPeers.Clear();
videoTrack?.Dispose();
audioTrack?.Dispose();
if (microphoneStarted)
{
string device = string.IsNullOrEmpty(microphoneDeviceName)
? null
: microphoneDeviceName;
Microphone.End(device);
}
}
public IArchitecture GetArchitecture()
{
return MainArchitecture.Interface;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 3583d180c5d94451bea6ead323d96021
timeCreated: 1780402391

View File

@@ -0,0 +1,381 @@
using System;
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using Newtonsoft.Json;
using RenderStreaming;
using Stary.Evo;
using Unity.RenderStreaming;
using Unity.WebRTC;
using UnityEngine;
namespace Script.Recorder
{
public class ServerMixedRecorder : IVideoRecorder, IController
{
public bool IsRecording { get; }
public Action OnStartedRecordingVideo { get; set; }
public Action<string> OnStoppedRecordingVideoAction { get; set; }
private string recordingId;
private readonly Dictionary<string, RTCPeerConnection> recordingPeers = new();
// [Header("Tracks")] public RenderTexture sourceRenderTexture;
// public string microphoneDeviceName = ""; // 留空使用默认麦克风
// public int microphoneSampleRate = 48000;
//
// private AudioSource microphoneAudioSource;
// private bool microphoneStarted;
private VideoStreamTrack videoTrack;
private AudioStreamTrack audioTrack;
public async void StartRecording()
{
await CreateLocalTracks();
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
messageChannel.OnRecordingPeerRequestReceived += OnRecordingPeerRequestReceived;
messageChannel.OnRecordingAnswerReceived += OnRecordingAnswerReceived;
messageChannel.OnRecordingCandidateReceived += OnRecordingCandidateReceived;
messageChannel.OnRecordingStoppedReceived += OnRecordingStoppedReceived;
var data = new
{
connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId(),
layout = "grid",
format = "webm",
};
var result = await WebRequestSystem.Post(
this.GetSystem<IGlobalConfigSystem>().IP + "/api/recording-sessions",
JsonConvert.SerializeObject(data));
if (result != null)
{
RecordingSession session = JsonConvert.DeserializeObject<RecordingSession>(result);
if (string.IsNullOrEmpty(session.success))
{
Debug.LogError($"[ServerMixedRecorder] StartRecording 失败: {session}");
return;
}
recordingId = session.session.id;
}
}
public async UniTask CreateLocalTracks()
{
var RenderStreaming =GameObject.Find("RenderStreaming");
VideoStreamSender videoStreamSender = RenderStreaming.GetComponent<VideoStreamSender>();
videoTrack = videoStreamSender.Track as VideoStreamTrack;
AudioStreamSender audioStreamSender = RenderStreaming.GetComponent<AudioStreamSender>();
audioTrack = audioStreamSender.Track as AudioStreamTrack;
// sourceRenderTexture = this.GetSystem<IRenderStreamingSystem>().GetRenderStreamingTexture();
// if (sourceRenderTexture != null)
// {
// videoTrack = new VideoStreamTrack(sourceRenderTexture);
// }
//
//
// microphoneAudioSource =
// GameObject.Find("RenderStreaming/microphoneAudioSource").GetComponent<AudioSource>();
// microphoneAudioSource.loop = true;
// microphoneAudioSource.mute = true;
//
// string device = string.IsNullOrEmpty(microphoneDeviceName)
// ? null
// : microphoneDeviceName;
//
// microphoneAudioSource.clip = Microphone.Start(
// device,
// true,
// 1,
// microphoneSampleRate
// );
//
// microphoneStarted = true;
//await CreateMicrophoneTrackWhenReady(device);
}
// public async UniTask CreateMicrophoneTrackWhenReady(string device)
// {
// while (Microphone.GetPosition(device) <= 0)
// await UniTask.NextFrame();
//
// microphoneAudioSource.Play();
// audioTrack = new AudioStreamTrack(microphoneAudioSource);
// }
public async void OnRecordingPeerRequestReceived(RecordingRequest request)
{
if (string.IsNullOrEmpty(request.recordingId))
return;
OnRecordingStoppedReceived(request.recordingId);
var config = new RTCConfiguration
{
iceServers = new[]
{
new RTCIceServer { urls = new[] { "stun:stun.l.google.com:19302" } }
}
};
var pc = new RTCPeerConnection(ref config);
recordingPeers[request.recordingId] = pc;
pc.OnIceCandidate = candidate =>
{
if (candidate == null) return;
Send("recording-candidate", new RecordingCandidate
{
recordingId = request.recordingId,
connectionId = request.connectionId,
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
candidate = candidate.Candidate,
sdpMid = candidate.SdpMid,
sdpMLineIndex = candidate.SdpMLineIndex ?? 0
});
};
if (videoTrack != null)
pc.AddTransceiver(videoTrack,
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
if (audioTrack != null)
pc.AddTransceiver(audioTrack,
new RTCRtpTransceiverInit { direction = RTCRtpTransceiverDirection.SendOnly });
var offerOp = pc.CreateOffer();
await offerOp;
var offer = offerOp.Desc;
var localOp = pc.SetLocalDescription(ref offer);
await localOp;
Send("recording-offer", new RecordingOffer
{
recordingId = request.recordingId,
connectionId = request.connectionId,
participantId = this.GetSystem<IGlobalConfigSystem>().GetParticipantId(),
sdp = offer.sdp
});
}
public async void OnRecordingAnswerReceived(RecordingAnswer answer)
{
if (!recordingPeers.TryGetValue(answer.recordingId, out var pc))
return;
var desc = new RTCSessionDescription
{
type = RTCSdpType.Answer,
sdp = answer.sdp
};
var op = pc.SetRemoteDescription(ref desc);
await op;
}
public void OnRecordingCandidateReceived(RecordingCandidate data)
{
if (!recordingPeers.TryGetValue(data.recordingId, out var pc))
return;
var candidate = new RTCIceCandidate(new RTCIceCandidateInit
{
candidate = data.candidate,
sdpMid = data.sdpMid,
sdpMLineIndex = data.sdpMLineIndex
});
pc.AddIceCandidate(candidate);
}
public void OnRecordingStoppedReceived(string recordingId)
{
if (!recordingPeers.TryGetValue(recordingId, out var pc))
return;
pc.Close();
recordingPeers.Remove(recordingId);
}
void Send(string type, object data)
{
var connectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
var json = JsonConvert.SerializeObject(new Dictionary<string, object>
{
["type"] = "on-message",
["data"] = new Dictionary<string, object>
{
["connectionId"] = connectionId,
["message"] = new Dictionary<string, object>
{
["type"] = type,
["data"] = data
}
}
});
SignalingMessageHelper.SendMessage(json);
}
public async void StopRecording()
{
await WebRequestSystem.Delete(this.GetSystem<IGlobalConfigSystem>().IP,
$"/api/recording-sessions/{recordingId}");
var messageChannel = GameObject.FindObjectOfType<MessageChannel>();
messageChannel.OnRecordingPeerRequestReceived -= OnRecordingPeerRequestReceived;
messageChannel.OnRecordingAnswerReceived -= OnRecordingAnswerReceived;
messageChannel.OnRecordingCandidateReceived -= OnRecordingCandidateReceived;
messageChannel.OnRecordingStoppedReceived -= OnRecordingStoppedReceived;
}
void OnDestroy()
{
foreach (var pc in recordingPeers.Values)
pc.Close();
recordingPeers.Clear();
videoTrack?.Dispose();
audioTrack?.Dispose();
// if (microphoneStarted)
// {
// string device = string.IsNullOrEmpty(microphoneDeviceName)
// ? null
// : microphoneDeviceName;
//
// Microphone.End(device);
// }
}
public IArchitecture GetArchitecture()
{
return MainArchitecture.Interface;
}
}
[Serializable]
public class Session
{
/// <summary>
///
/// </summary>
public string id { get; set; }
/// <summary>
///
/// </summary>
public string connectionId { get; set; }
/// <summary>
///
/// </summary>
public string status { get; set; }
/// <summary>
///
/// </summary>
public string layout { get; set; }
/// <summary>
///
/// </summary>
public string format { get; set; }
/// <summary>
///
/// </summary>
public string createdAt { get; set; }
/// <summary>
///
/// </summary>
public string startedAt { get; set; }
/// <summary>
///
/// </summary>
public string updatedAt { get; set; }
}
[Serializable]
public class Agent
{
/// <summary>
///
/// </summary>
public string id { get; set; }
/// <summary>
///
/// </summary>
public string recordingId { get; set; }
/// <summary>
///
/// </summary>
public string connectionId { get; set; }
/// <summary>
///
/// </summary>
public string status { get; set; }
/// <summary>
///
/// </summary>
public string mediaMode { get; set; }
/// <summary>
///
/// </summary>
public string createdAt { get; set; }
/// <summary>
///
/// </summary>
public string updatedAt { get; set; }
}
[Serializable]
public class RecordingSession
{
/// <summary>
///
/// </summary>
public string success { get; set; }
/// <summary>
///
/// </summary>
public Session session { get; set; }
/// <summary>
///
/// </summary>
public Agent agent { get; set; }
/// <summary>
///
/// </summary>
public string notified { get; set; }
/// <summary>
///
/// </summary>
public string peerRequestNotified { get; set; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d9d49eabfbbd4b4d8b4b88f082441596
timeCreated: 1780371636

View File

@@ -0,0 +1,47 @@
using Unity.WebRTC;
using UnityEngine;
public class WebcamToRenderTexture : MonoBehaviour
{
public RenderTexture renderTexture;
private WebCamTexture webcamTexture;
void Awake()
{
if (renderTexture == null)
{
RenderTextureFormat supportedFormat = WebRTC.GetSupportedRenderTextureFormat(SystemInfo.graphicsDeviceType);
// 创建新的RenderTexture
renderTexture = new RenderTexture(1920, 1200, 0, supportedFormat);
renderTexture.enableRandomWrite = true;
renderTexture.Create();
//_textureImage.texture = localRenderTexture;
}
webcamTexture = new WebCamTexture();
webcamTexture.Play();
}
void Update()
{
if (webcamTexture != null && webcamTexture.didUpdateThisFrame)
{
Graphics.Blit(webcamTexture, renderTexture);
}
}
void OnDestroy()
{
if (webcamTexture != null)
{
webcamTexture.Stop();
}
if (renderTexture != null)
{
renderTexture.Release();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 63353e4a29ff45c9803dae86c9590d72
timeCreated: 1780403919

View File

@@ -14,7 +14,7 @@ using CameraType = Unity.XR.XREAL.CameraType;
using GalleryDataProvider = Unity.XR.XREAL.MockGalleryDataProvider;
#endif
public class XrealMixedRecorder : IVideoRecorder, IController
public class XrealMixedRecorder : IVideoRecorder, IController , IDisposable
{
public enum ResolutionLevel
{
@@ -25,7 +25,7 @@ public class XrealMixedRecorder : IVideoRecorder, IController
public ResolutionLevel resolutionLevel = ResolutionLevel.High;
public BlendMode blendMode = BlendMode.Blend;
public AudioState audioState = AudioState.MicAudio;
public AudioState audioState = AudioState.ApplicationAndMicAudio;
public CaptureSide captureside = CaptureSide.Single;
public bool useGreenBackGround = false;
@@ -82,7 +82,7 @@ public class XrealMixedRecorder : IVideoRecorder, IController
}
Debug.Log("Stop Video Capture!");
_videoCapture.StopRecordingAsync(OnStoppedRecordingVideo);
_videoCapture.StopRecordingAsync(OnStoppedVideoCaptureMode);
}
/// <summary> Executes the 'stopped recording video' action. </summary>
@@ -103,6 +103,11 @@ public class XrealMixedRecorder : IVideoRecorder, IController
/// <param name="result"> The result.</param>
private async void OnStoppedVideoCaptureMode(XREALVideoCapture.VideoCaptureResult result)
{
if (!result.success)
{
Debug.Log("Stopped Recording Video Faild!");
return;
}
Debug.Log("Stopped Video Capture Mode!");
var encoder = _videoCapture.GetContext().GetEncoder() as VideoEncoder;
@@ -114,8 +119,6 @@ public class XrealMixedRecorder : IVideoRecorder, IController
await DelayInsertVideoToGallery(path, filename, "Record");
OnStoppedRecordingVideoAction?.Invoke(path);
// Release video capture resource.
_videoCapture.Dispose();
_videoCapture = null;
}
/// <summary> 延迟将视频插入相册,确保视频文件已完全写入 </summary>
@@ -235,4 +238,19 @@ public class XrealMixedRecorder : IVideoRecorder, IController
{
return MainArchitecture.Interface;
}
public void Dispose()
{
_videoCapture.StopVideoModeAsync((result) =>
{
if (!result.success)
{
Debug.Log("Stopped Video Capture Mode faild!");
return;
}
_videoCapture?.Dispose();
_videoCapture = null;
});
}
}

View File

@@ -11,6 +11,8 @@ namespace Script
{
void SetUp();
void HangUp();
RenderTexture GetRenderStreamingTexture();
}
public class RenderStreamingSystem : AbstractSystem, IRenderStreamingSystem
@@ -232,6 +234,15 @@ namespace Script
Debug.Log($"[MultiParticipantHost] Participant UI removed: {participantId}");
}
public RenderTexture GetRenderStreamingTexture()
{
if (_yuvToRenderTexture.localRenderTexture == null)
{
Debug.LogError("RenderTexture 未初始化");
return null;
}
return _yuvToRenderTexture.localRenderTexture;
}
#endregion

View File

@@ -348,16 +348,13 @@ namespace Stary.Evo
/// <param name="url">获取Token值的服务URL地址很重要</param>
/// <param name="postData">传入请求的参数此处参数为JOSN格式</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> Post(string url, string postData)
public static async Task<string> Post(string url, string postData)
{
try
{
await GetCertificateData();
using var webRequest = new UnityWebRequest(url, UnityWebRequest.kHttpVerbPOST);
// #if UNITY_2021_3_OR_NEWER
// using (UnityWebRequest webRequest = UnityWebRequest.PostWwwForm(url, postData)) //第二种写法此行注释
// #else
// using (UnityWebRequest webRequest = UnityWebRequest.PostWwwForm(url, postData)) //第二种写法此行注释
// #endif
webRequest.downloadHandler = new DownloadHandlerBuffer();
var postBytes = Encoding.UTF8.GetBytes(postData);
webRequest.uploadHandler = new UploadHandlerRaw(postBytes);
@@ -367,6 +364,7 @@ namespace Stary.Evo
webRequest.disposeDownloadHandlerOnDispose = true;
webRequest.disposeCertificateHandlerOnDispose = true;
webRequest.timeout = 30;
webRequest.certificateHandler = new SelfSignedCertHandler(certificateData);
await webRequest.SendWebRequest();
webRequest.uploadHandler?.Dispose();
// 更新错误检查方式
@@ -374,28 +372,16 @@ namespace Stary.Evo
webRequest.result == UnityWebRequest.Result.ProtocolError)
{
Debug.LogError(webRequest.error);
return new ResultMessageEntity
{
code = 5001,
message = webRequest.error
};
return webRequest.error;
}
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError(resultMessageEntity.message);
return resultMessageEntity;
return webRequest.downloadHandler.text;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Post" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
return e.Message;
}
}
@@ -408,10 +394,11 @@ namespace Stary.Evo
/// <param name="url">请求数据的URL地址</param>
/// <param name="path">请求数据的路径</param>
/// <returns></returns>
public static async Task<ResultMessageEntity> Delete(string url, string path)
public static async Task<string> Delete(string url, string path)
{
try
{
await GetCertificateData();
// 修复URL拼接
var fullUrl = url.TrimEnd('/') + "/" + path.TrimStart('/');
using var webRequest = new UnityWebRequest(fullUrl, UnityWebRequest.kHttpVerbDELETE);
@@ -420,6 +407,7 @@ namespace Stary.Evo
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
webRequest.timeout = 20;
webRequest.certificateHandler = new SelfSignedCertHandler(certificateData);
await webRequest.SendWebRequest();
// 增强错误处理
@@ -431,36 +419,20 @@ namespace Stary.Evo
$"Response: {webRequest.downloadHandler.text}";
Debug.LogError(errorMsg);
return new ResultMessageEntity
{
code = 5001,
message = errorMsg
};
return errorMsg;
}
// 修复空响应处理
var responseText = webRequest.downloadHandler.text;
if (string.IsNullOrEmpty(responseText))
return new ResultMessageEntity
{
code = 200,
message = "删除成功"
};
var resultMessageEntity =
JsonConvert.DeserializeObject<ResultMessageEntity>(webRequest.downloadHandler.text);
if (resultMessageEntity.code != 200) Debug.LogError(resultMessageEntity.message);
return resultMessageEntity;
return responseText;
}
catch (Exception e)
{
Debug.LogError("UnityEvo:WebRequestSystem.Get" + e.Message);
return new ResultMessageEntity
{
code = 5001,
message = e.Message
};
return e.Message;
}
}
@@ -568,6 +540,5 @@ namespace Stary.Evo
else
Debug.Log($"上传成功: {request.downloadHandler.text}");
}
}
}

View File

@@ -32,6 +32,12 @@ namespace Unity.RenderStreaming
public event Action<string, ChatData> OnChatMessageReceived;
public event Action<RecordingRequest> OnRecordingPeerRequestReceived;
public event Action<RecordingAnswer> OnRecordingAnswerReceived;
public event Action<RecordingCandidate> OnRecordingCandidateReceived;
public event Action<string> OnRecordingStoppedReceived;
public override void OnMessage(string message)
{
try
@@ -59,6 +65,27 @@ namespace Unity.RenderStreaming
var mediaState = json.ToObject<MediaStateChange>();
OnMediaStateChangeReceived?.Invoke(ConnectionId, mediaState);
break;
case MessageTypes.RecordingPeerRequest:
json = record.data as JObject;
var recordingPeerRequest = json.ToObject<RecordingRequest>();
OnRecordingPeerRequestReceived?.Invoke(recordingPeerRequest);
break;
case MessageTypes.RecordingAnswer:
json = record.data as JObject;
var recordingAnswer = json.ToObject<RecordingAnswer>();
OnRecordingAnswerReceived?.Invoke(recordingAnswer);
break;
case MessageTypes.RecordingCandidate:
json = record.data as JObject;
var recordingCandidate = json.ToObject<RecordingCandidate>();
OnRecordingCandidateReceived?.Invoke(recordingCandidate);
break;
case MessageTypes.RecordingStopped:
json = record.data as JObject;
var recordingStopped = json.ToObject<RecordingStopped>();
OnRecordingStoppedReceived?.Invoke(recordingStopped.recordingId);
break;
}
messageHistory.Add(record);

View File

@@ -13,6 +13,11 @@ namespace Unity.RenderStreaming
public const string UserInfo = "user-info";
public const string MediaStateChange = "media-state-changed";
public const string ParticipantsSync = "participants-sync";
public const string RecordingPeerRequest = "recording-peer-request";
public const string RecordingAnswer = "recording-answer";
public const string RecordingCandidate = "recording-candidate";
public const string RecordingStopped = "recording-stopped";
}
[Serializable]
@@ -54,4 +59,43 @@ namespace Unity.RenderStreaming
public int width;
public int height;
}
[Serializable]public class RecordingRequest
{
public string recordingId;
public string connectionId;
public string mediaMode;
}
[Serializable]public class RecordingOffer
{
public string recordingId;
public string connectionId;
public string participantId;
public string sdp;
}
[Serializable]public class RecordingAnswer
{
public string recordingId;
public string connectionId;
public string participantId;
public string sdp;
}
[Serializable]public class RecordingCandidate
{
public string recordingId;
public string connectionId;
public string participantId;
public string candidate;
public string sdpMid;
public int sdpMLineIndex;
}
[Serializable]public class RecordingStopped
{
public string recordingId;
}
}

View File

@@ -1,6 +1,7 @@
using System;
using RenderStreaming;
using Stary.Evo;
using Unity.RenderStreaming;
using Unity.XR.XREAL;
using UnityEngine;
using UnityEngine.UI;
@@ -19,12 +20,14 @@ namespace Script
//private RawImage _localVideoImage;
//private RawImage _textureImage;
private VideoStreamSender videoStreamSender;
private void Start()
{
//_localVideoImage= GameObject.Find("CanvasMain/RawImage").GetComponent<RawImage>();
//_textureImage= GameObject.Find("CanvasMain/RawImage1").GetComponent<RawImage>();
localVideoMaterial = Resources.Load<Material>("LocalRenderMaterial");
m_RGBCameraTexture = XREALRGBCameraTexture.CreateSingleton();
videoStreamSender=this.GetComponent<VideoStreamSender>();
Play();
}
@@ -52,8 +55,8 @@ namespace Script
return;
// 获取Y纹理的尺寸作为目标RenderTexture的尺寸
int width = yuvTextures[0].width;
int height = yuvTextures[0].height;
var width = videoStreamSender.width;
var height = videoStreamSender.height;
// if (_localVideoImage==null || _localVideoImage.rectTransform.sizeDelta.x != width ||
// _localVideoImage.rectTransform.sizeDelta.y != height)
// {
@@ -68,7 +71,7 @@ namespace Script
localRenderTexture.Release();
// 创建新的RenderTexture
localRenderTexture = new RenderTexture(width, height, 0, RenderTextureFormat.ARGB32);
localRenderTexture = new RenderTexture((int)width, (int)height, 0, RenderTextureFormat.ARGB32);
localRenderTexture.enableRandomWrite = true;
localRenderTexture.Create();
//_textureImage.texture = localRenderTexture;