两个页面接入完成
This commit is contained in:
@@ -2,6 +2,7 @@ using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using Stary.Evo;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
public interface IGlobalConfigSystem : ISystem
|
||||
{
|
||||
@@ -12,7 +13,7 @@ public interface IGlobalConfigSystem : ISystem
|
||||
public string GetConnectionName();
|
||||
public void SetConnectionName(string connectionName);
|
||||
|
||||
public UniTaskVoid StartConnectionTime();
|
||||
public UniTaskVoid StartConnectionTime(Text updateText);
|
||||
public string GetConnectionTime();
|
||||
|
||||
public void StopConnectionTime();
|
||||
@@ -20,8 +21,8 @@ public interface IGlobalConfigSystem : ISystem
|
||||
public int GetConnectionTimeType();
|
||||
public void SetConnectionTimeType(int connectionTimeType);
|
||||
|
||||
public Texture2D GetConnectionTexture();
|
||||
public void SetConnectionTexture(Texture2D connectionTexture);
|
||||
public string GetConnectionTexture();
|
||||
public void SetConnectionTexture(string connectionTexture);
|
||||
|
||||
public string GetUserId();
|
||||
public void SetUserId(string userId);
|
||||
@@ -29,6 +30,11 @@ public interface IGlobalConfigSystem : ISystem
|
||||
|
||||
public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
{
|
||||
/// <summary>
|
||||
/// 连接图标
|
||||
/// </summary>
|
||||
private string _connectionAvatar;
|
||||
|
||||
/// <summary>
|
||||
/// 连接ID
|
||||
/// </summary>
|
||||
@@ -39,11 +45,6 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
/// </summary>
|
||||
private string _connectionName;
|
||||
|
||||
/// <summary>
|
||||
/// 连接图标
|
||||
/// </summary>
|
||||
private Texture2D _connectionTexture;
|
||||
|
||||
/// <summary>
|
||||
/// 连接时间
|
||||
/// </summary>
|
||||
@@ -68,7 +69,7 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
}
|
||||
|
||||
|
||||
public string IP => "http://127.0.0.1:8080";
|
||||
public string IP => "https://192.168.31.16:8080";
|
||||
|
||||
public string GetConnectionId()
|
||||
{
|
||||
@@ -102,13 +103,14 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
_connectionName = connectionName;
|
||||
}
|
||||
|
||||
public async UniTaskVoid StartConnectionTime()
|
||||
public async UniTaskVoid StartConnectionTime(Text updateText)
|
||||
{
|
||||
_cts = new CancellationTokenSource();
|
||||
_connectionTime = 0;
|
||||
while (!_cts.IsCancellationRequested)
|
||||
{
|
||||
_connectionTime += Time.deltaTime;
|
||||
updateText.text = GetConnectionTime();
|
||||
await UniTask.Yield(_cts.Token); // 等一帧,等价于 Update
|
||||
}
|
||||
}
|
||||
@@ -139,20 +141,15 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
_connectionTimeType = connectionTimeType;
|
||||
}
|
||||
|
||||
public Texture2D GetConnectionTexture()
|
||||
public string GetConnectionTexture()
|
||||
{
|
||||
if (_connectionTexture == null)
|
||||
if (string.IsNullOrEmpty(_connectionAvatar))
|
||||
{
|
||||
Debug.LogWarning("GlobalConfigSystem: GetConnectionTexture not set");
|
||||
return null;
|
||||
}
|
||||
|
||||
return _connectionTexture;
|
||||
}
|
||||
|
||||
public void SetConnectionTexture(Texture2D connectionTexture)
|
||||
{
|
||||
_connectionTexture = connectionTexture;
|
||||
return _connectionAvatar;
|
||||
}
|
||||
|
||||
public string GetUserId()
|
||||
@@ -171,6 +168,11 @@ public class GlobalConfigSystem : AbstractSystem, IGlobalConfigSystem
|
||||
_userId = userId;
|
||||
}
|
||||
|
||||
public void SetConnectionTexture(string connectionTexture)
|
||||
{
|
||||
_connectionAvatar = connectionTexture;
|
||||
}
|
||||
|
||||
protected override void OnInit()
|
||||
{
|
||||
}
|
||||
|
||||
@@ -9,11 +9,6 @@ public class Main : MonoBehaviour, IController
|
||||
{
|
||||
private void Start()
|
||||
{
|
||||
ServicePointManager.ServerCertificateValidationCallback =
|
||||
(sender, certificate, chain, sslPolicyErrors) =>
|
||||
{
|
||||
return true; // 信任所有证书,仅开发环境使用
|
||||
};
|
||||
this.GetSystem<IPanelSystem>().PushQueue<StartPanel>();
|
||||
}
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@ using System;
|
||||
using System.Collections;
|
||||
using System.IO;
|
||||
using RenderStreaming;
|
||||
using Script.Util;
|
||||
using Stary.Evo;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Script
|
||||
{
|
||||
@@ -20,7 +20,7 @@ namespace Script
|
||||
private MeetingContacts _meetingContacts;
|
||||
private Transform _messageText;
|
||||
private Transform _nameText;
|
||||
private MeetingContacts.UsersItem _usersItem;
|
||||
private MainPanel.UsersItem _usersItem;
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
@@ -33,14 +33,14 @@ namespace Script
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
|
||||
public void SetData(MeetingContacts.UsersItem item, MeetingContacts meetingContactsController)
|
||||
public void SetData(MainPanel.UsersItem item, MeetingContacts meetingContactsController)
|
||||
{
|
||||
_usersItem = item;
|
||||
_meetingContacts = meetingContactsController;
|
||||
///头像赋值
|
||||
if (string.IsNullOrEmpty(item.avatar))
|
||||
{
|
||||
var randomColor = GetRandomColor();
|
||||
var randomColor = WebRTCUtil.GetRandomColor();
|
||||
_background = transform.Find("headBackground");
|
||||
if (_background != null)
|
||||
{
|
||||
@@ -62,7 +62,7 @@ namespace Script
|
||||
if (_background != null)
|
||||
{
|
||||
var imageComponent = _background.GetComponent<Image>();
|
||||
if (imageComponent != null) DownloadAndSetAvatar(item.avatar, imageComponent);
|
||||
if (imageComponent != null) WebRTCUtil.DownloadAndSetAvatar(item.avatar, imageComponent);
|
||||
}
|
||||
|
||||
_backgroundName = _background.transform.Find("Name");
|
||||
@@ -161,41 +161,5 @@ namespace Script
|
||||
_confirmButton.interactable = true;
|
||||
_confirmBtnTime.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private Color GetRandomColor()
|
||||
{
|
||||
return new Color(
|
||||
Random.Range(0.2f, 0.8f),
|
||||
Random.Range(0.2f, 0.8f),
|
||||
Random.Range(0.2f, 0.8f),
|
||||
1f
|
||||
);
|
||||
}
|
||||
|
||||
private async void DownloadAndSetAvatar(string avatarUrl, Image targetImage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tempPath = Path.Combine(Application.temporaryCachePath, $"avatar_{Guid.NewGuid()}.png");
|
||||
var result = await WebRequestSystem.GetFile(avatarUrl, tempPath);
|
||||
|
||||
if (result.code == 200)
|
||||
{
|
||||
var bytes = File.ReadAllBytes(tempPath);
|
||||
var texture = new Texture2D(2, 2);
|
||||
texture.LoadImage(bytes);
|
||||
|
||||
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height),
|
||||
Vector2.one * 0.5f);
|
||||
targetImage.sprite = sprite;
|
||||
|
||||
File.Delete(tempPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"下载头像失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Stary.Evo;
|
||||
using Stary.Evo.UIFarme;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -12,13 +14,30 @@ namespace Script
|
||||
/// </summary>
|
||||
private Button _arrowLeft;
|
||||
|
||||
private Toggle _chatTog;
|
||||
private Toggle _contactsTog;
|
||||
private Toggle _meetingOrganizersTog;
|
||||
|
||||
/// <summary>
|
||||
/// 房间ID
|
||||
/// </summary>
|
||||
private Text _idText;
|
||||
|
||||
/// <summary>
|
||||
/// 会议联系人类和面板
|
||||
/// </summary>
|
||||
private MeetingContacts _meetingContacts;
|
||||
|
||||
/// <summary>
|
||||
/// 会议参与者列表和面板
|
||||
/// </summary>
|
||||
private MeetingInfoList _meetingInfoList;
|
||||
|
||||
/// <summary>
|
||||
/// 会议聊天面板
|
||||
/// </summary>
|
||||
private MeetingChat _meetingChat;
|
||||
|
||||
/// <summary>
|
||||
/// 房间人数
|
||||
/// </summary>
|
||||
@@ -46,15 +65,30 @@ namespace Script
|
||||
_arrowLeft = panelGo.transform.Find("Header/arrow-left").GetComponent<Button>();
|
||||
_idText = panelGo.transform.Find("MeetingInfoCard/meeting/id").GetComponent<Text>();
|
||||
_roomPeopleNumText = panelGo.transform.Find("MeetingInfoCard/numberOfPeople/number").GetComponent<Text>();
|
||||
_chatTog = panelGo.transform.Find("Tabs/Chat").GetComponent<Toggle>();
|
||||
_contactsTog = panelGo.transform.Find("Tabs/Contacts").GetComponent<Toggle>();
|
||||
_meetingOrganizersTog = panelGo.transform.Find("Tabs/MeetingOrganizers").GetComponent<Toggle>();
|
||||
|
||||
_meetingContacts = new MeetingContacts();
|
||||
_meetingContacts.Initialize(panelGo.transform.Find("MeetingContacts").gameObject);
|
||||
_meetingInfoList = new MeetingInfoList();
|
||||
_meetingInfoList.Initialize(panelGo.transform.Find("MeetingInfoList").gameObject);
|
||||
_meetingChat = new MeetingChat();
|
||||
_meetingChat.Initialize(panelGo.transform.Find("MeetingChat").gameObject);
|
||||
}
|
||||
|
||||
public override void OnEnter(Action complete = null)
|
||||
{
|
||||
base.OnEnter(complete);
|
||||
_meetingContacts.OnEnter();
|
||||
_meetingInfoList.OnEnter();
|
||||
|
||||
_titleText.text = this.GetSystem<IGlobalConfigSystem>().GetConnectionName();
|
||||
this.GetSystem<IGlobalConfigSystem>().StartConnectionTime(_timeText);
|
||||
|
||||
_arrowLeft.onClick.AddListener(OnArrowLeftClick);
|
||||
_chatTog.onValueChanged.AddListener(OnChatTog);
|
||||
_contactsTog.onValueChanged.AddListener(OnContactsTog);
|
||||
_meetingOrganizersTog.onValueChanged.AddListener(OnMeetingOrganizersTog);
|
||||
}
|
||||
|
||||
|
||||
@@ -62,7 +96,27 @@ namespace Script
|
||||
{
|
||||
base.OnExit(delay);
|
||||
_meetingContacts.OnExit();
|
||||
_meetingInfoList.OnExit();
|
||||
_arrowLeft.onClick.RemoveListener(OnArrowLeftClick);
|
||||
_chatTog.onValueChanged.RemoveListener(OnChatTog);
|
||||
_contactsTog.onValueChanged.RemoveListener(OnContactsTog);
|
||||
_meetingOrganizersTog.onValueChanged.RemoveListener(OnMeetingOrganizersTog);
|
||||
}
|
||||
|
||||
private void OnMeetingOrganizersTog(bool value)
|
||||
{
|
||||
_meetingInfoList.PanelGo.SetActive(value);
|
||||
}
|
||||
|
||||
private void OnContactsTog(bool value)
|
||||
{
|
||||
_meetingContacts.PanelGo.SetActive(value);
|
||||
if (value) _meetingContacts.OnEnter();
|
||||
}
|
||||
|
||||
private void OnChatTog(bool value)
|
||||
{
|
||||
_meetingChat.PanelGo.SetActive(value);
|
||||
}
|
||||
|
||||
private void OnArrowLeftClick()
|
||||
@@ -73,5 +127,49 @@ namespace Script
|
||||
{
|
||||
base.OnDestroy();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ResponseUsers
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public List<UsersItem> users { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int totalCount { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UsersItem
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string socketId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string connectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string participantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string role { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string userId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string avatar { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
29
Assets/Script/MainPanel/MeetingChat.cs
Normal file
29
Assets/Script/MainPanel/MeetingChat.cs
Normal file
@@ -0,0 +1,29 @@
|
||||
using RenderStreaming;
|
||||
using Stary.Evo;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Script
|
||||
{
|
||||
public class MeetingChat : IController
|
||||
{
|
||||
public GameObject PanelGo;
|
||||
|
||||
public void Initialize(GameObject panelGo)
|
||||
{
|
||||
PanelGo = panelGo;
|
||||
}
|
||||
|
||||
public async void OnEnter()
|
||||
{
|
||||
}
|
||||
|
||||
public async void OnExit()
|
||||
{
|
||||
}
|
||||
|
||||
public IArchitecture GetArchitecture()
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Script/MainPanel/MeetingChat.cs.meta
Normal file
3
Assets/Script/MainPanel/MeetingChat.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6a093f6facf40398f5a84d8c2c2e13f
|
||||
timeCreated: 1779162068
|
||||
@@ -16,7 +16,7 @@ namespace Script
|
||||
/// Key: 参与者ID
|
||||
/// Value: 联系人列表项实例
|
||||
/// </summary>
|
||||
private readonly Dictionary<GameObject, ContactEntryController> _contactEntries = new();
|
||||
private readonly List<ContactEntryController> _contactEntries = new();
|
||||
|
||||
private Image _avatarImage;
|
||||
private Button _cancelButton;
|
||||
@@ -39,10 +39,12 @@ namespace Script
|
||||
private Text _messageText;
|
||||
private Text _nameText;
|
||||
|
||||
private GameObject _panelGo;
|
||||
public GameObject PanelGo;
|
||||
|
||||
public ContactEntryController CurrentEntry { get; set; }
|
||||
|
||||
private GameObjectPool _objectPool;
|
||||
|
||||
public IArchitecture GetArchitecture()
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
@@ -50,12 +52,12 @@ namespace Script
|
||||
|
||||
public void Initialize(GameObject panelGo)
|
||||
{
|
||||
_panelGo = panelGo;
|
||||
PanelGo = panelGo;
|
||||
_contactEntryPrefab = Resources.Load<GameObject>("ContactEntry");
|
||||
_content = _panelGo.transform.Find("MeetingGrid/Viewport/Content");
|
||||
_content = PanelGo.transform.Find("MeetingGrid/Viewport/Content");
|
||||
|
||||
//邀请界面
|
||||
_confirmingPop = _panelGo.transform.Find("MeetingGrid/ConfirmingPop").gameObject;
|
||||
_confirmingPop = PanelGo.transform.Find("MeetingGrid/ConfirmingPop").gameObject;
|
||||
_confirmingPop.SetActive(false);
|
||||
//确认邀请
|
||||
_idText = _confirmingPop.transform.Find("bg/id").GetComponent<Text>();
|
||||
@@ -66,21 +68,28 @@ namespace Script
|
||||
_avatarImage = _confirmingPop.transform.Find("ParticipantEntry/head").GetComponent<Image>();
|
||||
_nameText = _confirmingPop.transform.Find("ParticipantEntry/Name").GetComponent<Text>();
|
||||
_messageText = _confirmingPop.transform.Find("ParticipantEntry/Message").GetComponent<Text>();
|
||||
|
||||
_objectPool = PanelGo.transform.Find("MeetingGrid/Pool").GetComponent<GameObjectPool>();
|
||||
}
|
||||
|
||||
public async void OnEnter()
|
||||
{
|
||||
foreach (var entry in _contactEntries)
|
||||
_objectPool.Release(entry.gameObject);
|
||||
_contactEntries.Clear();
|
||||
var response =
|
||||
await WebRequestSystem.Get<ResponseUsers>(this.GetSystem<IGlobalConfigSystem>().IP, "/signaling/users");
|
||||
await WebRequestSystem.Get<MainPanel.ResponseUsers>(this.GetSystem<IGlobalConfigSystem>().IP,
|
||||
"/signaling/users");
|
||||
if (response != null && response.totalCount > 0)
|
||||
for (var i = 0; i < response.totalCount; i++)
|
||||
{
|
||||
var item = response.users[i];
|
||||
if (string.IsNullOrEmpty(item.name) ||
|
||||
string.IsNullOrEmpty(item.userId)) continue;
|
||||
var entry = GameObject.Instantiate(_contactEntryPrefab, _content);
|
||||
var entry = _objectPool.Get();
|
||||
var contactEntryController = entry.GetOrAddComponent<ContactEntryController>();
|
||||
contactEntryController.SetData(item, this);
|
||||
_contactEntries.Add(contactEntryController);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,7 +98,7 @@ namespace Script
|
||||
{
|
||||
}
|
||||
|
||||
public void ClickContactEntry(Sprite avatarImage, string name, UsersItem item)
|
||||
public void ClickContactEntry(Sprite avatarImage, string name, MainPanel.UsersItem item)
|
||||
{
|
||||
_confirmingPop.SetActive(true);
|
||||
|
||||
@@ -119,7 +128,8 @@ namespace Script
|
||||
inviterName = this.GetSystem<IGlobalConfigSystem>().GetConnectionName(),
|
||||
inviterAvatar =
|
||||
$"{this.GetSystem<IGlobalConfigSystem>().IP}/images/head/" +
|
||||
$"{this.GetSystem<IGlobalConfigSystem>().GetConnectionTexture().name}.png"
|
||||
$"{this.GetSystem<IGlobalConfigSystem>().GetConnectionTexture()}.png",
|
||||
applyReason = _leaveMessage.text
|
||||
}
|
||||
};
|
||||
SignalingMessageHelper.SendMessage(JsonConvert.SerializeObject(userInfo));
|
||||
@@ -130,59 +140,5 @@ namespace Script
|
||||
CurrentEntry = null;
|
||||
});
|
||||
}
|
||||
|
||||
public class ContactEntryData
|
||||
{
|
||||
public string avatar;
|
||||
public GameObject entry;
|
||||
public Toggle invitationTog;
|
||||
public string name;
|
||||
public string participantId;
|
||||
public string role;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ResponseUsers
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public List<UsersItem> users { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public int totalCount { get; set; }
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class UsersItem
|
||||
{
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string socketId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string connectionId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string participantId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string role { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string userId { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string name { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// </summary>
|
||||
public string avatar { get; set; }
|
||||
}
|
||||
}
|
||||
}
|
||||
244
Assets/Script/MainPanel/MeetingInfoList.cs
Normal file
244
Assets/Script/MainPanel/MeetingInfoList.cs
Normal file
@@ -0,0 +1,244 @@
|
||||
using System.Collections.Generic;
|
||||
using RenderStreaming;
|
||||
using Script.Util;
|
||||
using Stary.Evo;
|
||||
using Unity.RenderStreaming;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Script
|
||||
{
|
||||
public class MeetingInfoList : IController
|
||||
{
|
||||
public GameObject PanelGo;
|
||||
|
||||
/// <summary>
|
||||
/// 联系人列表项预制体
|
||||
/// </summary>
|
||||
private GameObject _contactEntryPrefab;
|
||||
|
||||
/// <summary>
|
||||
/// 全部联系人列表容器
|
||||
/// </summary>
|
||||
private Transform _content;
|
||||
|
||||
private Text _meetingNum;
|
||||
|
||||
private Dictionary<string, MessageRecordInfo> _meetingList = new();
|
||||
|
||||
private GameObjectPool _objectPool;
|
||||
|
||||
public void Initialize(GameObject panelGo)
|
||||
{
|
||||
PanelGo = panelGo;
|
||||
_contactEntryPrefab = Resources.Load<GameObject>("ParticipantEntry");
|
||||
_content = panelGo.transform.Find("MeetingGrid/Viewport/Content");
|
||||
_meetingNum = panelGo.transform.Find("MeetingNum/Num").GetComponent<Text>();
|
||||
_objectPool = PanelGo.transform.Find("MeetingGrid/Pool").GetComponent<GameObjectPool>();
|
||||
}
|
||||
|
||||
public void OnEnter()
|
||||
{
|
||||
LoadUsers();
|
||||
|
||||
GameObject.FindObjectOfType<MessageChannel>().OnMediaStateChangeReceived += OnMediaStateChangeReceived;
|
||||
GameObject.FindObjectOfType<MessageChannel>().OnUserInfoMessageReceived += OnUserInfoMessageReceived;
|
||||
GameObject.FindObjectOfType<HostConnection>().OnParticipantDisconnected += OnParticipantDisconnected;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当有用户断开连接时调用
|
||||
/// </summary>
|
||||
/// <param name="id"></param>
|
||||
private void OnParticipantDisconnected(string id)
|
||||
{
|
||||
var userId = "";
|
||||
foreach (var value in _meetingList.Values)
|
||||
if (value.item.participantId == id)
|
||||
{
|
||||
_objectPool.Release(value.participant);
|
||||
userId = value.item.userId;
|
||||
break;
|
||||
}
|
||||
|
||||
_meetingList.Remove(userId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当有用户加入会议时调用
|
||||
/// </summary>
|
||||
/// <param name="arg1"></param>
|
||||
/// <param name="arg2"></param>
|
||||
private void OnUserInfoMessageReceived(string arg1, UserInfo arg2)
|
||||
{
|
||||
foreach (var info in _meetingList.Values) _objectPool.Release(info.participant);
|
||||
|
||||
_meetingList.Clear();
|
||||
|
||||
LoadUsers();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 当有用户媒体状态改变时调用
|
||||
/// </summary>
|
||||
/// <param name="connectionId"></param>
|
||||
/// <param name="message"></param>
|
||||
private async void OnMediaStateChangeReceived(string connectionId, MediaStateChange message)
|
||||
{
|
||||
Debug.Log($"OnMediaStateChangeReceived: {message}");
|
||||
|
||||
|
||||
if (_meetingList.ContainsKey(message.userId))
|
||||
{
|
||||
var info = _meetingList[message.userId];
|
||||
SetMediaStateMic(info.participant, message.audio);
|
||||
SetMediaStateVideo(info.participant, message.video);
|
||||
}
|
||||
}
|
||||
|
||||
private async void LoadUsers()
|
||||
{
|
||||
var response =
|
||||
await WebRequestSystem.Get<MainPanel.ResponseUsers>(this.GetSystem<IGlobalConfigSystem>().IP,
|
||||
$"/signaling/users?connectionId={this.GetSystem<IGlobalConfigSystem>().GetConnectionId()}");
|
||||
if (response != null && response.totalCount > 0)
|
||||
{
|
||||
_meetingNum.text = response.totalCount.ToString();
|
||||
for (var i = 0; i < response.totalCount; i++)
|
||||
{
|
||||
var item = response.users[i];
|
||||
if (string.IsNullOrEmpty(item.name) ||
|
||||
string.IsNullOrEmpty(item.userId)) continue;
|
||||
var entry = _objectPool.Get();
|
||||
SetData(entry, item);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void SetData(GameObject entry, MainPanel.UsersItem item)
|
||||
{
|
||||
var transform = entry.transform;
|
||||
///头像赋值
|
||||
var background = transform.Find("headBackground");
|
||||
var backgroundName = background.transform.Find("Name");
|
||||
if (string.IsNullOrEmpty(item.avatar))
|
||||
{
|
||||
var randomColor = WebRTCUtil.GetRandomColor();
|
||||
|
||||
if (background != null)
|
||||
{
|
||||
var image = background.GetComponent<Image>();
|
||||
if (image != null) image.color = randomColor;
|
||||
}
|
||||
|
||||
|
||||
if (backgroundName != null)
|
||||
{
|
||||
var textComponent = backgroundName.GetComponent<Text>();
|
||||
if (textComponent != null && !string.IsNullOrEmpty(item.name))
|
||||
textComponent.text = item.name.Substring(0, 1);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
background = transform.Find("headBackground");
|
||||
if (background != null)
|
||||
{
|
||||
var imageComponent = background.GetComponent<Image>();
|
||||
if (imageComponent != null) WebRTCUtil.DownloadAndSetAvatar(item.avatar, imageComponent);
|
||||
}
|
||||
|
||||
if (backgroundName != null) backgroundName.GetComponent<Text>().text = "";
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.name))
|
||||
{
|
||||
var nameText = transform.Find("Name");
|
||||
if (nameText != null)
|
||||
{
|
||||
var textComponent = nameText.GetComponent<Text>();
|
||||
if (textComponent != null) textComponent.text = item.name;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.userId))
|
||||
{
|
||||
var messageText = transform.Find("Message");
|
||||
if (messageText != null)
|
||||
{
|
||||
var textComponent = messageText.GetComponent<Text>();
|
||||
if (textComponent != null) textComponent.text = item.userId;
|
||||
}
|
||||
}
|
||||
|
||||
if (!string.IsNullOrEmpty(item.role))
|
||||
{
|
||||
var role = item.role;
|
||||
var participant = transform.Find("Name/state/participant");
|
||||
var host = transform.Find("Name/state/host");
|
||||
|
||||
if (role.Equals("host"))
|
||||
{
|
||||
host.gameObject.SetActive(true);
|
||||
participant.gameObject.SetActive(false);
|
||||
SetMediaStateMic(entry, true);
|
||||
SetMediaStateVideo(entry, true);
|
||||
}
|
||||
else if (role.Equals("participant"))
|
||||
{
|
||||
participant.gameObject.SetActive(true);
|
||||
host.gameObject.SetActive(false);
|
||||
SetMediaStateMic(entry, false);
|
||||
SetMediaStateVideo(entry, true);
|
||||
}
|
||||
}
|
||||
|
||||
_meetingList.Add(item.userId, new MessageRecordInfo(item, entry));
|
||||
}
|
||||
|
||||
private void SetMediaStateMic(GameObject entry, bool isAudio)
|
||||
{
|
||||
var mic = entry.transform.Find("mic");
|
||||
var micBackground = mic.transform.Find("Background");
|
||||
var micCheckmark = mic.transform.Find("Checkmark");
|
||||
|
||||
micCheckmark.gameObject.SetActive(isAudio);
|
||||
micBackground.gameObject.SetActive(!isAudio);
|
||||
}
|
||||
|
||||
private void SetMediaStateVideo(GameObject entry, bool isVideo)
|
||||
{
|
||||
var video = entry.transform.Find("video");
|
||||
var videoBackground = video.transform.Find("Background");
|
||||
var videoCheckmark = video.transform.Find("Checkmark");
|
||||
|
||||
|
||||
videoCheckmark.gameObject.SetActive(isVideo);
|
||||
videoBackground.gameObject.SetActive(!isVideo);
|
||||
}
|
||||
|
||||
public async void OnExit()
|
||||
{
|
||||
GameObject.FindObjectOfType<MessageChannel>().OnMediaStateChangeReceived -= OnMediaStateChangeReceived;
|
||||
GameObject.FindObjectOfType<MessageChannel>().OnUserInfoMessageReceived -= OnUserInfoMessageReceived;
|
||||
GameObject.FindObjectOfType<HostConnection>().OnParticipantDisconnected -= OnParticipantDisconnected;
|
||||
}
|
||||
|
||||
public class MessageRecordInfo
|
||||
{
|
||||
public MainPanel.UsersItem item;
|
||||
public GameObject participant;
|
||||
|
||||
public MessageRecordInfo(MainPanel.UsersItem item, GameObject participant)
|
||||
{
|
||||
this.item = item;
|
||||
this.participant = participant;
|
||||
}
|
||||
}
|
||||
|
||||
public IArchitecture GetArchitecture()
|
||||
{
|
||||
return MainArchitecture.Interface;
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Script/MainPanel/MeetingInfoList.cs.meta
Normal file
3
Assets/Script/MainPanel/MeetingInfoList.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 808f780c6849419d8c7235091a0295e7
|
||||
timeCreated: 1779162087
|
||||
8
Assets/Script/Pool.meta
Normal file
8
Assets/Script/Pool.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a2be89955a7639d44a282c31c15fb36c
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
37
Assets/Script/Pool/GameObjectPool.cs
Normal file
37
Assets/Script/Pool/GameObjectPool.cs
Normal file
@@ -0,0 +1,37 @@
|
||||
using UnityEngine;
|
||||
using System.Collections.Generic;
|
||||
|
||||
public class GameObjectPool : MonoBehaviour
|
||||
{
|
||||
[Tooltip("预制体")] public GameObject prefab;
|
||||
[Tooltip("初始预加载数量")] public int preload = 10;
|
||||
|
||||
private Stack<GameObject> _pool = new();
|
||||
public Transform parent;
|
||||
|
||||
private void Start()
|
||||
{
|
||||
for (var i = 0; i < preload; i++)
|
||||
{
|
||||
var go = Instantiate(prefab, transform);
|
||||
go.SetActive(false);
|
||||
_pool.Push(go);
|
||||
}
|
||||
}
|
||||
|
||||
public GameObject Get()
|
||||
{
|
||||
var go = _pool.Count > 0 ? _pool.Pop() : Instantiate(prefab, parent);
|
||||
go.transform.parent = parent;
|
||||
go.SetActive(true);
|
||||
return go;
|
||||
}
|
||||
|
||||
public void Release(GameObject go)
|
||||
{
|
||||
if (go == null) return;
|
||||
go.SetActive(false);
|
||||
go.transform.SetParent(transform, false);
|
||||
_pool.Push(go);
|
||||
}
|
||||
}
|
||||
11
Assets/Script/Pool/GameObjectPool.cs.meta
Normal file
11
Assets/Script/Pool/GameObjectPool.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1970feb7fdb702645b753cd8ed1be4ea
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
28
Assets/Script/SelfSignedCertHandler.cs
Normal file
28
Assets/Script/SelfSignedCertHandler.cs
Normal file
@@ -0,0 +1,28 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using System.IO;
|
||||
using System.Security.Cryptography.X509Certificates;
|
||||
|
||||
/// <summary>
|
||||
/// 信任指定自签名证书
|
||||
/// </summary>
|
||||
public class SelfSignedCertHandler : CertificateHandler
|
||||
{
|
||||
// 受信任的证书数据(从 StreamingAssets 加载)
|
||||
private X509Certificate2 _trustedCert;
|
||||
|
||||
public SelfSignedCertHandler(byte[] certData)
|
||||
{
|
||||
_trustedCert = new X509Certificate2(certData);
|
||||
}
|
||||
|
||||
protected override bool ValidateCertificate(byte[] certificateData)
|
||||
{
|
||||
// 方法1:严格匹配整本证书(推荐)
|
||||
var remoteCert = new X509Certificate2(certificateData);
|
||||
return remoteCert.Thumbprint == _trustedCert.Thumbprint;
|
||||
|
||||
// 方法2:宽松模式 - 只要证书能解析就信任(调试用,危险)
|
||||
// return true;
|
||||
}
|
||||
}
|
||||
11
Assets/Script/SelfSignedCertHandler.cs.meta
Normal file
11
Assets/Script/SelfSignedCertHandler.cs.meta
Normal file
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ae01fb0d54ce6934b8b553302876daaa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -170,7 +170,8 @@ namespace Unity.RenderStreaming
|
||||
{
|
||||
if (_profileSprites == null || _profileSprites.Length == 0) return;
|
||||
_profileImage.sprite = _profileSprites[_profileSpriteIndex];
|
||||
this.GetSystem<IGlobalConfigSystem>().SetConnectionTexture(_profileSprites[_profileSpriteIndex].texture);
|
||||
var avatar = _profileSprites[_profileSpriteIndex].name.Replace("(Clone)", "");
|
||||
this.GetSystem<IGlobalConfigSystem>().SetConnectionTexture(avatar);
|
||||
_profileSpriteIndex = (_profileSpriteIndex + 1) % _profileSprites.Length;
|
||||
}
|
||||
|
||||
@@ -197,7 +198,6 @@ namespace Unity.RenderStreaming
|
||||
this.GetSystem<IGlobalConfigSystem>().SetConnectionId(_meetingId.text);
|
||||
hostConnection.RoomConnectionId = this.GetSystem<IGlobalConfigSystem>().GetConnectionId();
|
||||
this.GetSystem<IGlobalConfigSystem>().SetConnectionName(_meetingNameInput.text);
|
||||
this.GetSystem<IGlobalConfigSystem>().SetConnectionTexture(_profileImage.sprite.texture);
|
||||
if (!SignalingMessageHelper.IsReady())
|
||||
{
|
||||
Debug.LogError("Signaling 未就绪");
|
||||
@@ -210,7 +210,6 @@ namespace Unity.RenderStreaming
|
||||
type = "host-userInfo",
|
||||
data = new
|
||||
{
|
||||
connectionId = hostConnection.RoomConnectionId,
|
||||
id = this.GetSystem<IGlobalConfigSystem>().GetUserId(),
|
||||
name = _meetingNameInput.text,
|
||||
avatar = $"{this.GetSystem<IGlobalConfigSystem>().IP}/images/head/{avatar}.png"
|
||||
|
||||
3
Assets/Script/Util.meta
Normal file
3
Assets/Script/Util.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: de21338fb2a746fc9d2ffc968c7c9204
|
||||
timeCreated: 1779180350
|
||||
48
Assets/Script/Util/WebRTCUtil.cs
Normal file
48
Assets/Script/Util/WebRTCUtil.cs
Normal file
@@ -0,0 +1,48 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using Stary.Evo;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
using Random = UnityEngine.Random;
|
||||
|
||||
namespace Script.Util
|
||||
{
|
||||
public static class WebRTCUtil
|
||||
{
|
||||
public static Color GetRandomColor()
|
||||
{
|
||||
return new Color(
|
||||
Random.Range(0.2f, 0.8f),
|
||||
Random.Range(0.2f, 0.8f),
|
||||
Random.Range(0.2f, 0.8f),
|
||||
1f
|
||||
);
|
||||
}
|
||||
|
||||
public static async void DownloadAndSetAvatar(string avatarUrl, Image targetImage)
|
||||
{
|
||||
try
|
||||
{
|
||||
var tempPath = Path.Combine(Application.temporaryCachePath, $"avatar_{Guid.NewGuid()}.png");
|
||||
var result = await WebRequestSystem.GetFile(avatarUrl, tempPath);
|
||||
|
||||
if (result.code == 200)
|
||||
{
|
||||
var bytes = File.ReadAllBytes(tempPath);
|
||||
var texture = new Texture2D(2, 2);
|
||||
texture.LoadImage(bytes);
|
||||
|
||||
var sprite = Sprite.Create(texture, new Rect(0, 0, texture.width, texture.height),
|
||||
Vector2.one * 0.5f);
|
||||
targetImage.sprite = sprite;
|
||||
|
||||
File.Delete(tempPath);
|
||||
}
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"下载头像失败: {e.Message}");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
3
Assets/Script/Util/WebRTCUtil.cs.meta
Normal file
3
Assets/Script/Util/WebRTCUtil.cs.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4decb134134b44de9674419f4b392d6e
|
||||
timeCreated: 1779180377
|
||||
@@ -13,6 +13,7 @@ namespace Stary.Evo
|
||||
public static class WebRequestSystem
|
||||
{
|
||||
private static string authorization;
|
||||
private static byte[] certificateData;
|
||||
|
||||
static WebRequestSystem()
|
||||
{
|
||||
@@ -21,6 +22,8 @@ namespace Stary.Evo
|
||||
#else
|
||||
authorization = CustomPlayerPrefs.GetString("Authorization");
|
||||
#endif
|
||||
var certPath = Path.Combine(Application.streamingAssetsPath, "server.crt");
|
||||
certificateData = File.ReadAllBytes(certPath);
|
||||
}
|
||||
|
||||
public static async Task<bool> Login(string url, string username, string password)
|
||||
@@ -220,6 +223,8 @@ namespace Stary.Evo
|
||||
{
|
||||
using var webRequest = UnityWebRequest.Get(url);
|
||||
webRequest.downloadHandler = new DownloadHandlerFile(tempPath);
|
||||
webRequest.certificateHandler = new SelfSignedCertHandler(certificateData);
|
||||
|
||||
if (authorization != null)
|
||||
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
|
||||
|
||||
@@ -279,6 +284,7 @@ namespace Stary.Evo
|
||||
var fullUrl = url.TrimEnd('/') + "/" + path.TrimStart('/');
|
||||
using var webRequest = new UnityWebRequest(fullUrl, UnityWebRequest.kHttpVerbGET);
|
||||
webRequest.downloadHandler = new DownloadHandlerBuffer();
|
||||
webRequest.certificateHandler = new SelfSignedCertHandler(certificateData);
|
||||
if (authorization != null)
|
||||
webRequest.SetRequestHeader("Authorization", authorization); // 修正请求头名称规范
|
||||
|
||||
|
||||
@@ -30,6 +30,7 @@ namespace Unity.RenderStreaming
|
||||
public event Action<string, UserInfo> OnUserInfoMessageReceived;
|
||||
public event Action<string, MediaStateChange> OnMediaStateChangeReceived;
|
||||
|
||||
|
||||
public override void OnMessage(string message)
|
||||
{
|
||||
try
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
// Assets/Script/WebRtc/MessageTypes.cs
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
|
||||
@@ -10,7 +12,7 @@ namespace Unity.RenderStreaming
|
||||
public const string Chat = "chat";
|
||||
public const string UserInfo = "user-info";
|
||||
public const string MediaStateChange = "media-state-changed";
|
||||
public const string Image = "image";
|
||||
public const string ParticipantsSync = "participants-sync";
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
@@ -37,7 +39,6 @@ namespace Unity.RenderStreaming
|
||||
public bool audio;
|
||||
public bool video;
|
||||
public bool screenShare;
|
||||
public bool recording;
|
||||
public bool isSpeaking;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user