using WingInterfaceLibrary.LiveConsultation; using WingInterfaceLibrary.Enum; using WingInterfaceLibrary.Request.Notification; using WingServerCommon.Config; using WingInterfaceLibrary.Notifications; using WingServerCommon.Interfaces.Cache; using WingInterfaceLibrary.Rtc; using WingServerCommon.Log; using System.Text; using WingInterfaceLibrary.DTO.User; using WingInterfaceLibrary.LiveConsultation.Consultation; namespace WingLiveConsultationService { /// /// 会诊房间 /// public partial class LiveConsultationRoom : LiveConsultationRoomDTO { public static Func OnRtcGenerateRoomUrl; public static Func OnGetUserSign; public LiveConsultationRoom(string roomId, int roomNo, string patientName, DateTime consultationTime, TransactionStatusEnum consultationStatus , string applyOrganizationCode, string applyUserCode, string expertOrganizationCode, List liveMembers, string expertUserCode, bool isEmergency) : base(roomId) { RoomId = roomId; RoomNo = roomNo; PatientName = patientName ?? string.Empty; ConsultationTime = consultationTime; ConsultationStatus = consultationStatus; ApplyOrganizationCode = applyOrganizationCode; ApplyUserCode = applyUserCode; ExpertOrganizationCode = expertOrganizationCode; Members = liveMembers ?? new List(); ExpertUserCode = expertUserCode; IsEmergency = isEmergency; InteractiveBoardDatas = new List(); } /// /// 修改预约记录状态 /// /// public void ChangeConsultationStatus(TransactionStatusEnum status) { WriteDebugLogs("ChangeConsultationStatus", null, $"{ConsultationStatus.ToString()}>>{status.ToString()}"); ConsultationStatus = status; } /// /// 参与人员同意参加会诊 /// /// public void Agree(string userCode) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null) { liveMember.Status = LiveConsultationMemberStatus.Default; } else { liveMember = InitLiveMemberByCode(userCode); liveMember.Status = LiveConsultationMemberStatus.Default; Members.Add(liveMember); } WriteDebugLogs("Agree", liveMember); } /// /// 开始会诊 /// /// /// /// /// public void Initiate(string initiatorCode, int integerRoomId, int timeout, int sdkAppId, bool pushMessage = false) { var initiator = Members.FirstOrDefault(x => x.Id == initiatorCode); if (initiator != null) { initiator.IsInitiator = true; initiator.Status = LiveConsultationMemberStatus.Joined; } else { initiator = InitLiveMemberByCode(initiatorCode); initiator.IsInitiator = true; initiator.Status = LiveConsultationMemberStatus.Joined; Members.Add(initiator); } foreach (var liveMember in Members) { if (liveMember.Id != initiatorCode) { liveMember.IsInitiator = false; liveMember.Status = LiveConsultationMemberStatus.Default; } liveMember.Mute = false; liveMember.VideoOpend = true; liveMember.IsControllingParameter = false; } RoomNo = integerRoomId; ConsultationStatus = TransactionStatusEnum.InProgress; Status = LiveConsultationRoomStatus.Initiating; InteractiveBoardDatas = new List(); EmergencyAccepted = false; RefreshMemberInfosByToken(); //StartCheckConnectionTimeout(timeout); if (pushMessage) { PushInitiateMessage(sdkAppId); } WriteDebugLogs("Initiate", initiator); } /// /// 接受会诊邀请-参与人员 /// /// public void Accept(string userCode, bool pushMessage = false) { var accepter = Members.FirstOrDefault(x => x.Id == userCode); if (accepter != null) { accepter.Status = LiveConsultationMemberStatus.Accepted; accepter.Mute = false; accepter.IsControllingParameter = false; accepter.VideoOpend = true; RemoveInteractiveBoardDatasByUserCode(userCode); if (Status == LiveConsultationRoomStatus.Connected) { Status = LiveConsultationRoomStatus.Initiating; } if (pushMessage) { PushCancelInviteInMessage(new List { accepter.Id }, true);//取消其他端的呼叫行为 PushAcceptMessage(accepter); } } WriteDebugLogs("Accept", accepter); } /// /// 接受会诊邀请-急诊专家 /// /// /// /// public void EmergencyAccept(string userCode, string orgCode, bool pushMessage = false) { EmergencyAccepted = true; var accepter = Members.FirstOrDefault(x => x.Id == userCode); if (accepter == null) { accepter = InitLiveMemberByCode(userCode); accepter.Status = LiveConsultationMemberStatus.Accepted; Members.Add(accepter); //急诊专家信息 ExpertUserCode = userCode; ExpertOrganizationCode = orgCode; } accepter.Status = LiveConsultationMemberStatus.Accepted; accepter.Mute = false; accepter.VideoOpend = true; accepter.IsControllingParameter = false; if (Status == LiveConsultationRoomStatus.Connected) { Status = LiveConsultationRoomStatus.Initiating; } if (pushMessage) { PushAcceptMessage(accepter); } WriteDebugLogs("EmergencyAccept", accepter); } /// /// 拒绝会诊邀请-参与人员 /// /// public void Reject(string userCode, bool pushMessage = false) { var rejecter = Members.FirstOrDefault(x => x.Id == userCode); if (rejecter != null) { rejecter.Status = LiveConsultationMemberStatus.Rejected; if (pushMessage) { PushCancelInviteInMessage(new List { rejecter.Id }, true);//取消其他端的呼叫行为 PushRejectMessage(rejecter); } } WriteDebugLogs("Reject", rejecter); } /// /// 取消会诊 /// public void CancelInitiate(bool pushMessage = false) { Status = LiveConsultationRoomStatus.Cancelled; ConsultationStatus = TransactionStatusEnum.ToStart; if (pushMessage) { PushCancelMessage(); PushCloseMessage(); } foreach (var liveMember in Members) { if (liveMember.Status == LiveConsultationMemberStatus.Joined) { liveMember.Status = LiveConsultationMemberStatus.Left; } } WriteDebugLogs("CancelInitiate", Initiator); } /// /// 会诊心跳,进入房间 /// /// public void HeartRateJoin(string userCode, bool pushMessage = false) { var joiner = Members.FirstOrDefault(x => x.Id == userCode); if (joiner != null && joiner.Status != LiveConsultationMemberStatus.Joined) { joiner.Status = LiveConsultationMemberStatus.Joined; if (pushMessage) { PushHeartRateJoinMessage(joiner); } } WriteDebugLogs("HeartRateJoin", joiner); } /// /// 会诊心跳,网络质量不佳 /// /// public void NetworkErr(string userCode, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { if (pushMessage) { PushNetworkErrMessage(liveMember); } } WriteDebugLogs("NetworkErr", liveMember); } /// /// 会诊心跳,离开房间 /// /// public bool HeartRateLeave(string userCode, bool pushMessage = false) { var leaver = Members.FirstOrDefault(x => x.Id == userCode); var needClose = false; if (leaver != null && leaver.Status == LiveConsultationMemberStatus.Joined) { leaver.Status = LiveConsultationMemberStatus.Left; if (pushMessage) { PushHeartRateLeaveMessage(leaver); } if (MainUserInfos == null || MainUserInfos.All(x => x.Status != LiveConsultationMemberStatus.Joined)) { Close(pushMessage); needClose = true; } } WriteDebugLogs("HeartRateLeave", leaver); return needClose; } /// /// 离开房间,含结束会诊 /// /// public bool Leave(string userCode, bool pushMessage = false) { var leaver = Members.FirstOrDefault(x => x.Id == userCode); var needClose = false; if (leaver != null && leaver.Status == LiveConsultationMemberStatus.Joined) { leaver.Status = LiveConsultationMemberStatus.Left; leaver.Mute = false; leaver.IsControllingParameter = false; leaver.VideoOpend = true; RemoveInteractiveBoardDatasByUserCode(userCode); if (pushMessage) { PushLeaveMessage(leaver); } if (MainUserInfos == null || MainUserInfos.All(x => x.Status != LiveConsultationMemberStatus.Joined)) { Close(pushMessage); needClose = true; } } WriteDebugLogs("Leave", leaver, $"close:{needClose.ToString()}"); return needClose; } /// /// 结束会诊 /// public void Close(bool pushMessage = false) { Status = LiveConsultationRoomStatus.Closed; ConsultationStatus = TransactionStatusEnum.PendingReport; if (pushMessage) { PushCancelMessage(); PushCloseMessage(); } foreach (var liveMember in Members) { if (liveMember.Status == LiveConsultationMemberStatus.Joined) { liveMember.Status = LiveConsultationMemberStatus.Left; } } InteractiveBoardDatas = new List(); WriteDebugLogs("Close"); } /// /// 开启关闭静音 /// /// /// public void ChangeMuteState(string userCode, bool mute, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { liveMember.Mute = mute; if (pushMessage) { PushMuteStateMessage(liveMember); } } WriteDebugLogs("ChangeMuteState", liveMember, $"mute:{mute.ToString()}"); } /// /// 开启关闭视频 /// /// /// public void ChangeVideoOpenState(string userCode, bool isVideoOpen, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { liveMember.VideoOpend = isVideoOpen; if (pushMessage) { PushVideoOpenStateMessage(liveMember); } } WriteDebugLogs("ChangeVideoOpenState", liveMember, $"isVideoOpen:{isVideoOpen.ToString()}"); } /// /// 更改调参状态 /// /// /// public void ChangeControllingParameterState(string userCode, bool isControllingParameter) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { liveMember.IsControllingParameter = isControllingParameter; } WriteDebugLogs("ChangeControllingParameterState", liveMember, $"isControllingParameter:{isControllingParameter.ToString()}"); } /// /// 会诊中邀请 /// /// /// public void InviteIn(string userCode, List clientIds, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { if (pushMessage) { PushInviteInMessage(liveMember, clientIds); } } WriteDebugLogs("InviteIn", liveMember); } /// /// 取消会诊中邀请 /// /// /// public void CancelInviteIn(string userCode, List clientIds, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { var notifyUserCodes = new List(); foreach (var clientId in clientIds) { if (Members.Any(x => x.Id == clientId && x.Status == LiveConsultationMemberStatus.Joined)) { continue; } notifyUserCodes.Add(clientId); } if (notifyUserCodes.Any()) { if (pushMessage) { PushCancelInviteInMessage(notifyUserCodes); } } } WriteDebugLogs("CancelInviteIn", liveMember); } /// /// 接受会诊中邀请 /// /// public void AcceptIn(string userCode, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null) { liveMember.Status = LiveConsultationMemberStatus.Accepted; liveMember.Mute = false; liveMember.IsControllingParameter = false; liveMember.VideoOpend = true; } else { liveMember = InitLiveMemberByCode(userCode); liveMember.Status = LiveConsultationMemberStatus.Accepted; liveMember.Mute = false; liveMember.IsControllingParameter = false; liveMember.VideoOpend = true; Members.Add(liveMember); } RemoveInteractiveBoardDatasByUserCode(userCode); if (pushMessage) { PushCancelInviteInMessage(new List { liveMember.Id }, true);//取消其他端的呼叫行为 PushAcceptInMessage(liveMember); } WriteDebugLogs("AcceptIn", liveMember); } /// /// 拒绝会诊中邀请 /// /// public void RejectIn(string rejecterCode, bool pushMessage = false) { if (Initiator != null && Initiator.Status == LiveConsultationMemberStatus.Joined) { var userInfo = CacheMaintenance.Instance.Get().Get(rejecterCode); WriteDebugLogs("RejectIn", Initiator, $"rejecter name:{userInfo.UserName};{userInfo.FullName}"); if (pushMessage) { PushCancelInviteInMessage(new List { userInfo.Code }, true);//取消其他端的呼叫行为 PushRejectInMessage(Initiator, userInfo); } } else { WriteDebugLogs("RejectIn", Initiator); } } /// /// 发送白板交互数据 /// /// /// /// public void SendBoardData(string userCode, string boardData, DateTime interactiveTime, bool isClear, bool pushMessage = false) { var liveMember = Members.FirstOrDefault(x => x.Id == userCode); if (liveMember != null && liveMember.Status == LiveConsultationMemberStatus.Joined) { if (!isClear) { InteractiveBoardDatas.Add(new InteractiveBoardDataDTO { InteractiveTime = interactiveTime, UserCode = userCode, BoardData = boardData, }); } else { RemoveInteractiveBoardDatasByUserCode(userCode); } if (pushMessage) { PushBoardDataMessage(liveMember, boardData, isClear); } } WriteDebugLogs("SendBoardData", liveMember); } /// /// 呼叫急诊专家 /// /// /// public void CallEmergencyDoctor(UserDTO doctor, int timeOut) { if (!EmergencyAccepted) { PushEmergencyMessage(doctor, timeOut); } } /// /// 急诊呼叫失败 /// public void EmergencyFailed() { if (!EmergencyAccepted) { PushEmergencyFailedMessage(); } } /// /// 切换会诊房间 /// /// /// /// /// /// public void ChangeRoom(string userCode, LiveConsultationRoom current, int timeout, int sdkAppId) { current.Initiate(Initiator.Id, RoomNo, timeout, sdkAppId, false); var closeMemberCodes = new List(); foreach (var origMember in Members) { if (origMember.Status != LiveConsultationMemberStatus.Joined) { continue; } var liveMember = current.Members.FirstOrDefault(x => x.Id == origMember.Id); if (liveMember != null) { liveMember.Status = LiveConsultationMemberStatus.Accepted; liveMember.Mute = origMember.Mute; liveMember.VideoOpend = origMember.VideoOpend; liveMember.IsControllingParameter = origMember.IsControllingParameter; } else { closeMemberCodes.Add(origMember.Id); } } PushCloseDueToChangeMessage(closeMemberCodes); PushChangeRoomMessage(userCode, current); Close(false); } private void StartCheckConnectionTimeout(int timeout) { Task.Run(async () => { Status = LiveConsultationRoomStatus.Initiating; await Task.Delay(timeout * 1000); if (Status != LiveConsultationRoomStatus.Connected) { Status = LiveConsultationRoomStatus.ConnectionTimeout; } }); } public LiveConsultationMember InitLiveMemberByCode(string userCode) { var user = CacheMaintenance.Instance.Get().Get(userCode); var userName = !string.IsNullOrWhiteSpace(user.FullName) ? user.FullName : user.UserName; var liveMember = new LiveConsultationMember { Id = userCode, MemberType = LiveMemberEnum.User, Name = userName, HeadImageToken = user.HeadImageToken, IsInitiator = false, Status = LiveConsultationMemberStatus.Default, //LiveData = liveData, }; var userToken = CacheMaintenance.Instance.Get().Where(t => t.ClientId == userCode)?.OrderByDescending(x => x.IsOnline)?.FirstOrDefault(); if (userToken != null) { var loginSource = (LoginSource)userToken.LoginSource; liveMember.LoginServerUrl = userToken.LoginServer; liveMember.LoginSource = (LoginSource)userToken.LoginSource; liveMember.IsOnline = userToken.IsOnline; liveMember.IsBusy = false; } return liveMember; } private void RefreshMemberInfosByToken(string liveMemberId = "") { var tokenManager = CacheMaintenance.Instance.Get(); foreach (var liveMember in Members) { var id = liveMember.Id; if (!string.IsNullOrWhiteSpace(liveMemberId) && id != liveMemberId) { continue; } var userToken = tokenManager.Where(t => t.ClientId == id)?.OrderByDescending(x => x.IsOnline)?.FirstOrDefault(); if (userToken != null) { var loginSource = (LoginSource)userToken.LoginSource; liveMember.LoginServerUrl = userToken.LoginServer; liveMember.LoginSource = (LoginSource)userToken.LoginSource; liveMember.IsOnline = userToken.IsOnline; } var agenerateRoomUrlResult = OnRtcGenerateRoomUrl.Invoke(RoomNo, id); liveMember.LiveData = new LiveData { RtmpPullUrl = agenerateRoomUrlResult.RtmpUrl, HlsPullUrl = agenerateRoomUrlResult.HlsUrl, HttpPullUrl = agenerateRoomUrlResult.FlvUrl, }; } } private void WriteDebugLogs(string actionName, LiveConsultationMember liveMember = null, string log = "") { var logs = new StringBuilder(); logs.AppendLine($"LiveConsultationRoom action:{actionName}, patientName:{PatientName}, roomId:{RoomId}, room status:{Status.ToString()}"); if (liveMember != null) { logs.AppendLine($"user:{liveMember.Name}, status:{liveMember.Status.ToString()}"); } else { logs.AppendLine($"user:not existed"); } logs.AppendLine($"log:{log}"); Logger.WriteLineInfo($"{logs.ToString()}"); } /// /// 清除白板数据 /// /// private void RemoveInteractiveBoardDatasByUserCode(string userCode) { InteractiveBoardDatas = InteractiveBoardDatas.Where(x => x.UserCode != userCode)?.ToList() ?? new List(); } } public class LiveConsultationRoomDTO { public LiveConsultationRoomDTO(string roomId) { RoomId = roomId; } /// /// The consultation unique id /// /// public string RoomId { get; set; } /// /// The diagnosis room No /// /// public int RoomNo { get; set; } public string MsgQueueId { get; set; } public IList Members { get; set; } = new List(); public LiveConsultationMember Initiator { get { return Members.FirstOrDefault(x => x.IsInitiator); } } public IEnumerable UserInfos { get { return Members.Where(x => x.MemberType == LiveMemberEnum.User); } } public IEnumerable DeviceInfos { get { return Members.Where(x => x.MemberType == LiveMemberEnum.Device); } } public IEnumerable MainUserInfos { get { return Members.Where(x => x.IsInitiator || x.Id == ApplyUserCode || x.Id == ExpertUserCode); } } /// /// The diagnosis room status /// /// public LiveConsultationRoomStatus Status { get; set; } /// /// 病人名称 /// public string PatientName { get; set; } /// /// 会诊时间 /// public DateTime ConsultationTime { get; set; } /// /// 会诊状态 /// public TransactionStatusEnum ConsultationStatus { get; set; } /// /// 申请机构编码 /// public string ApplyOrganizationCode { get; set; } /// /// 申请医师编码 /// public string ApplyUserCode { get; set; } /// /// 会诊机构编码 /// public string ExpertOrganizationCode { get; set; } /// /// 会诊专家编码 /// public string ExpertUserCode { get; set; } /// /// 是否急诊标识 /// /// public bool IsEmergency { get; set; } /// /// 急诊已接通 /// /// public bool EmergencyAccepted { get; set; } /// /// 白板数据集合 /// /// /// public IList InteractiveBoardDatas { get; set; } = new List(); } }