This commit is contained in:
2026-05-24 22:26:38 +08:00
parent 9b6ed2bcd6
commit 33128ea686
20 changed files with 380 additions and 392 deletions

View File

@@ -13,11 +13,6 @@ namespace Unity.RenderStreaming
{
public class StartPanel : BasePanel
{
/// <summary>
/// 每个Participant的UI信息
/// </summary>
private readonly Dictionary<string, ParticipantUI> participantUIs = new();
/// <summary>
/// 返回按钮
/// </summary>
@@ -60,30 +55,6 @@ namespace Unity.RenderStreaming
/// </summary>
private Dropdown _timeDropdown;
/// <summary>
/// Host连接
/// </summary>
private HostConnection hostConnection;
/// <summary>
/// 本地视频显示
/// </summary>
private RawImage localVideoImage;
/// <summary>
/// 麦克风流发送器
/// </summary>
private AudioStreamSender microphoneStreamer;
[Header("Participant视频容器")] private Transform participantVideoContainer;
/// <summary>
/// 渲染流管理
/// </summary>
private SignalingManager renderStreaming;
[Header("核心组件")] private RenderStreamingSettings settings;
[Header("Host本地视频")] private VideoStreamSender videoStreamSender;
public override UITweenType TweenType => UITweenType.Fade;
@@ -109,26 +80,6 @@ namespace Unity.RenderStreaming
_profileSpriteIndex = 0;
OnClickProfilePhoto();
renderStreaming = GameObject.FindObjectOfType<SignalingManager>();
hostConnection = GameObject.FindObjectOfType<HostConnection>();
videoStreamSender = hostConnection.GetComponent<VideoStreamSender>();
microphoneStreamer = hostConnection.GetComponent<AudioStreamSender>();
if (settings == null)
settings = new RenderStreamingSettings();
if (settings != null)
{
videoStreamSender.width = (uint)settings.StreamSize.x;
videoStreamSender.height = (uint)settings.StreamSize.y;
}
if (renderStreaming.runOnAwake)
return;
if (settings != null)
renderStreaming.useDefaultSettings = settings.UseDefaultSettings;
if (settings?.SignalingSettings != null)
renderStreaming.SetSignalingSettings(settings.SignalingSettings);
renderStreaming.Run();
}
public override void OnEnter(Action complete = null)
@@ -139,14 +90,6 @@ namespace Unity.RenderStreaming
_randomMeetingId.onClick.AddListener(OnClickRandomMeetingId);
_startButton.onClick.AddListener(OnClickStartButton);
if (hostConnection != null)
{
hostConnection.OnParticipantConnected += HandleParticipantConnected;
hostConnection.OnParticipantDisconnected += HandleParticipantDisconnected;
}
// 本地视频Sender启动后显示
videoStreamSender.OnStartedStream += OnStartedStream;
}
@@ -157,13 +100,6 @@ namespace Unity.RenderStreaming
_profilePhoto.onClick.RemoveListener(OnClickProfilePhoto);
_randomMeetingId.onClick.RemoveListener(OnClickRandomMeetingId);
_startButton.onClick.RemoveListener(OnClickStartButton);
if (hostConnection != null)
{
hostConnection.OnParticipantConnected -= HandleParticipantConnected;
hostConnection.OnParticipantDisconnected -= HandleParticipantDisconnected;
}
videoStreamSender.OnStartedStream -= OnStartedStream;
}
private void OnClickProfilePhoto()
@@ -196,7 +132,7 @@ namespace Unity.RenderStreaming
this.GetSystem<IGlobalConfigSystem>().SetUserId(OnClickRandomUserId());
this.GetSystem<IGlobalConfigSystem>().SetConnectionTimeType(_timeDropdown.value);
this.GetSystem<IGlobalConfigSystem>().SetConnectionId(_meetingId.text);
hostConnection.RoomConnectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
this.GetSystem<IGlobalConfigSystem>().SetConnectionName(_meetingNameInput.text);
if (!SignalingMessageHelper.IsReady())
{
@@ -216,146 +152,9 @@ namespace Unity.RenderStreaming
}
};
SignalingMessageHelper.SendMessage(JsonConvert.SerializeObject(userInfo));
SetUp();
this.GetSystem<IRenderStreamingSystem>().SetUp();
PanelSystem.PopQueue<StartPanel>();
PanelSystem.PushQueue<MainPanel>();
}
private void OnStartedStream(string id)
{
if (videoStreamSender.sourceWebCamTexture != null)
localVideoImage.texture = videoStreamSender.sourceWebCamTexture;
}
private class ParticipantUI
{
public Text nameLabel;
public GameObject root;
public RawImage videoImage;
}
#region
private void SetUp()
{
videoStreamSender.enabled = true;
if (settings != null)
videoStreamSender.SetCodec(settings.SenderVideoCodec);
hostConnection.CreateConnection(hostConnection.RoomConnectionId);
}
private void HangUp()
{
hostConnection.DeleteConnection(hostConnection.RoomConnectionId);
// 清理所有Participant UI
foreach (var ui in participantUIs.Values)
if (ui.root != null)
GameObject.Destroy(ui.root);
participantUIs.Clear();
localVideoImage.texture = null;
}
/// <summary>
/// 新Participant连接成功回调
/// 此时Participant的独立Receiver已创建可以绑定视频显示
/// </summary>
private void HandleParticipantConnected(ParticipantStreams ps)
{
// 创建Participant UI
var ui = CreateParticipantUI(ps.participantId);
participantUIs[ps.participantId] = ui;
// 绑定视频当Receiver收到纹理时更新RawImage
ps.videoReceiver.OnUpdateReceiveTexture += texture =>
{
ui.videoImage.color = Color.white;
// 防止纹理为null时导致RawImage闪黑重协商/track切换时可能短暂为null
if (ui.videoImage != null && texture != null)
ui.videoImage.texture = texture;
};
// 绑定音频AudioSource已在HostConnection中配置
ps.audioReceiver.OnUpdateReceiveAudioSource += source =>
{
if (source != null && !source.isPlaying)
{
source.loop = true;
source.Play();
}
};
Debug.Log($"[MultiParticipantHost] Participant UI created: {ps.participantId}");
}
/// <summary>
/// 动态创建单个Participant的视频显示UI
/// 结构: [NameLabel] + [RawImage(视频画面)]
/// </summary>
private ParticipantUI CreateParticipantUI(string participantId)
{
var ui = new ParticipantUI();
// 根节点
ui.root = new GameObject($"ParticipantUI_{participantId}");
ui.root.transform.SetParent(participantVideoContainer, false);
// 添加VerticalLayoutGroup使内容垂直排列
var vlg = ui.root.AddComponent<VerticalLayoutGroup>();
vlg.childControlWidth = true;
vlg.childControlHeight = false;
vlg.childForceExpandWidth = true;
vlg.childForceExpandHeight = false;
vlg.spacing = 2;
ui.root.transform.GetComponent<RectTransform>().anchorMin = Vector2.zero;
ui.root.transform.GetComponent<RectTransform>().anchorMax = Vector2.one;
// 名称标签
var labelObj = new GameObject("NameLabel");
labelObj.transform.SetParent(ui.root.transform, false);
ui.nameLabel = labelObj.AddComponent<Text>();
ui.nameLabel.text = $"Participant: {participantId}";
ui.nameLabel.fontSize = 14;
ui.nameLabel.color = Color.white;
ui.nameLabel.alignment = TextAnchor.MiddleCenter;
var labelLayout = labelObj.AddComponent<LayoutElement>();
labelLayout.preferredHeight = 20;
// 视频画面
var imageObj = new GameObject("VideoImage");
imageObj.transform.SetParent(ui.root.transform, false);
ui.videoImage = imageObj.AddComponent<RawImage>();
ui.videoImage.color = Color.black;
var imageLayout = imageObj.AddComponent<LayoutElement>();
imageLayout.preferredHeight = 200;
// AspectRatioFitter保持视频比例
var aspectRatio = imageObj.AddComponent<AspectRatioFitter>();
aspectRatio.aspectMode = AspectRatioFitter.AspectMode.FitInParent;
aspectRatio.aspectRatio = 16f / 9f;
return ui;
}
/// <summary>
/// Participant断开连接回调
/// 销毁其UI
/// </summary>
private void HandleParticipantDisconnected(string participantId)
{
if (participantUIs.TryGetValue(participantId, out var ui))
{
if (ui.root != null)
GameObject.Destroy(ui.root);
participantUIs.Remove(participantId);
}
Debug.Log($"[MultiParticipantHost] Participant UI removed: {participantId}");
}
#endregion
}
}