/// <summary> /// 设置显示的呼叫 /// </summary> /// <param name="call">呼叫</param> private void SetCurrentCall(QLCall call) { if (null != _currentCall) { _currentCall.PropertyChanged -= OnCallPropertyChangedHandle; _currentCall.Channels.CollectionChanged -= OnChannelsCllectionChangedHandle; } channelViews.Clear(); this.Controls.Clear(); _currentCall = call; localChannel = null; contentChannel = null; if (null != _currentCall) { foreach (var channel in _currentCall.Channels) { var channelView = new ChannelView(channel); channelViews.Add(channel, channelView); this.Controls.Add(channelView); switch (channel.MediaType) { case MediaType.LOCAL: localChannel = channel; break; case MediaType.CONTENT: contentChannel = channel; break; case MediaType.LOCALCONTENT: contentChannel = channel; break; } } _currentCall.PropertyChanged += OnCallPropertyChangedHandle; _currentCall.Channels.CollectionChanged += OnChannelsCllectionChangedHandle; } }
internal void AddChannel(QLChannel channel) { if (null == GetChannel(channel.ChannelID)) { var isActive = channel.IsActive; _channels.Add(channel); if (isActive) { CurrentChannel = channel; } } }
internal void AddChannel(int channelID, MediaType mediaType) { if (null == GetChannel(channelID)) { var isActive = channelID == ActiveSpeakerId; var channel = new QLChannel(this, channelID, mediaType, isActive); _channels.Add(channel); if (isActive) { CurrentChannel = channel; } } }
internal ChannelView(QLChannel channel) { _channel = channel; InitializeComponent(); _channel.PropertyChanged += OnPropertyChangedEventHandler; this.Disposed += OnDisposed; //防止抖动 if (channel.MediaType == MediaType.LOCALCONTENT) { this.DoubleBuffered = true; SetStyle(ControlStyles.UserPaint, true); SetStyle(ControlStyles.AllPaintingInWmPaint, true); // 禁止擦除背景. SetStyle(ControlStyles.DoubleBuffer, true); // 双缓冲 } }
public ContentRegion(QLCall call, QLChannel channel) { InitializeComponent(); if (null == call || !call.IsActive()) { throw new Exception("呼叫不存在或处理非活动状态"); } this.call = call; this.channel = channel; this.call.PropertyChanged += OnCallPropertyChangedHandle; shareTimer = new Timer() { Interval = 1000 }; shareTimer.Tick += onShareTimerTickHandle; shareTimer.Start(); }
/// <summary> /// 处理Poly核心事件 /// </summary> /// <param name="evt">事件</param> internal void QLEventHandle(QLEvent evt) { log.Debug("evt:" + evt.EventType); try { switch (evt.EventType) { #region Register case EventType.UNKNOWN: break; case EventType.SIP_REGISTER_SUCCESS: break; case EventType.SIP_REGISTER_FAILURE: { CurrentCall = null; _contentRegion?.Close(); throw new Exception("注册失败"); } break; case EventType.SIP_REGISTER_UNREGISTERED: { CurrentCall = null; _contentRegion?.Close(); throw new Exception("未注册"); } break; #endregion #region QLCall case EventType.SIP_CALL_INCOMING: { #region Sound try { //播放呼入响铃 deviceManager.StopSound(); var incomingSound = qlConfig.GetProperty(PropertyKey.SOUND_INCOMING); if (!string.IsNullOrWhiteSpace(incomingSound)) { deviceManager.PlaySound(incomingSound, true, 2000); } } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); call.CallName = evt.CallerName; call.CallType = CallType.INCOMING; call.CallState = CallState.SIP_INCOMING_INVITE; evt.Call = call; var msg = string.Format("【{0}】呼入中,是否接听?", evt.CallerName); if (null != this.CurrentCall && this.CurrentCall.IsActive()) { var callStateText = this.CurrentCall.CallStateText(); if (!string.IsNullOrEmpty(callStateText)) { msg += '\n' + callStateText; msg += '\n' + "接听将挂断当前通话。"; } } Action answerAction = () => { try { if (null != this.CurrentCall && this.CurrentCall.IsActive()) { this.CurrentCall.HangUpCall(); } var callMode = call.CallMode; if (null == deviceManager.CurrentVideoInputDevice) { //当前视频设备为空时,只能语音通话 callMode = CallMode.AUDIO; } call.AnswerCall(callMode); } catch (Exception ex) { log.Error(ex.Message); call.RejectCall(); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; Action hangupAction = () => { try { call.RejectCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(true, msg, MessageBoxButtonsType.AnswerHangup, MessageBoxIcon.Question , answerAction, hangupAction); } break; case EventType.SIP_CALL_TRYING: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } call.CallType = CallType.OUTGOING; call.CallState = CallState.SIP_OUTGOING_TRYING; evt.Call = call; if (call == this.CurrentCall) { var msg = string.Format("尝试呼出【{0}】连接中...", call.CallName); Action hangupAction = () => { try { call.HangUpCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(false, msg, MessageBoxButtonsType.Hangup, MessageBoxIcon.Information , hangupAction); } } break; case EventType.SIP_CALL_RINGING: { #region Sound try { //播放呼叫响铃 deviceManager.StopSound(); var ringingSound = qlConfig.GetProperty(PropertyKey.SOUND_RINGING); if (!string.IsNullOrWhiteSpace(ringingSound)) { deviceManager.PlaySound(ringingSound, true, 2000); } } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } call.CallType = CallType.OUTGOING; call.CallState = CallState.SIP_OUTGOING_RINGING; evt.Call = call; if (call == this.CurrentCall) { var msg = string.Format("呼出【{0}】响铃中...", call.CallName); Action hangupAction = () => { try { call.HangUpCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(false, msg, MessageBoxButtonsType.Hangup, MessageBoxIcon.Information , hangupAction); } } break; case EventType.SIP_CALL_HOLD: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.CallState = CallState.SIP_CALL_HOLD; if (call == CurrentCall) { var msg = string.Format("呼叫【{0}】中断保持,是否需要恢复通话?", call.CallName); Action yesAction = () => { try { call.ResumeCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(false, msg, MessageBoxButtonsType.YesNoCancel, MessageBoxIcon.Question , yesAction); } } break; case EventType.SIP_CALL_HELD: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.CallState = CallState.SIP_CALL_HELD; if (call == CurrentCall) { var msg = string.Format("呼叫【{0}】被保持", call.CallName); Action hangupAction = () => { try { call.HangUpCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(false, msg, MessageBoxButtonsType.Hangup, MessageBoxIcon.Information, hangupAction); } } break; case EventType.SIP_CALL_DOUBLE_HOLD: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.CallState = CallState.SIP_CALL_DOUBLE_HOLD; if (call == CurrentCall) { var msg = string.Format("呼叫【{0}】双方中断保持,是否需要恢复通话?", call.CallName); var yesAction = new Action(() => { try { call.ResumeCall(); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }); callView.ShowMessage(false, msg, MessageBoxButtonsType.YesNo, MessageBoxIcon.Question , yesAction); } } break; case EventType.SIP_CALL_UAS_CONNECTED: { #region Sound try { deviceManager.StopSound(); } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; log.Info(string.Format("呼入{0}接听通话中", call.CallName)); call.ConnectedTime = DateTime.Now; call.CallType = CallType.INCOMING; call.CallState = CallState.SIP_INCOMING_CONNECTED; this.CurrentCall = call; callView.HideMessage(); } break; case EventType.SIP_CALL_UAC_CONNECTED: { #region Sound try { deviceManager.StopSound(); } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); log.Info(string.Format("呼入{0}接听通话中", call.CallName)); evt.Call = call; log.Info(string.Format("呼出{0}接听通话中", call.CallName)); call.ConnectedTime = DateTime.Now; call.CallType = CallType.OUTGOING; call.CallState = CallState.SIP_OUTGOING_CONNECTED; this.CurrentCall = call; callView.HideMessage(); } break; case EventType.SIP_CALL_FAILURE: { #region Sound try { deviceManager.StopSound(); } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } call.StopTime = DateTime.Now; call.CallType = CallType.OUTGOING; call.CallState = CallState.SIP_OUTGOING_FAILURE; evt.Call = call; call.Reason = string.IsNullOrEmpty(evt.Reason) ? "unknown reason" : evt.Reason; if (call == CurrentCall) { var msg = string.Format("呼出【{0}】失败,原因:{1}", call.CallName, call.Reason); log.Error(msg); callView.ShowMessage(false, msg, MessageBoxButtonsType.OK, MessageBoxIcon.Error); CurrentCall = null; } } break; case EventType.SIP_CALL_CLOSED: { #region Sound try { deviceManager.StopSound(); var closedSound = qlConfig.GetProperty(PropertyKey.SOUND_CLOSED); if (!string.IsNullOrWhiteSpace(closedSound)) { deviceManager.PlaySound(closedSound, false, 0); } } catch (Exception ex) { log.Error(ex.Message); } #endregion var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.Reason = string.IsNullOrEmpty(evt.Reason) ? "unknown reason" : evt.Reason; call.UnconnectedTime = DateTime.Now; call.StopTime = DateTime.Now; call.CallState = CallState.SIP_CALL_CLOSED; if (call == CurrentCall) { var msg = string.Format("呼出【{0}】关闭,原因:{1}", call.CallName, call.Reason); log.Info(msg); callView.ShowMessage(false, msg, MessageBoxButtonsType.OK, MessageBoxIcon.Information); CurrentCall = null; } } break; case EventType.SIP_CALL_MODE_UPGRADE_REQ: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; var msg = string.Format("【{0}】请求中,是否接听?", evt.CallMode == CallMode.VIDEO ? "视频通话" : "语言通话"); Action yesAction = () => { try { if (null != this.CurrentCall && this.CurrentCall.IsActive()) { this.CurrentCall.HangUpCall(); } var callMode = evt.CallMode; if (null == deviceManager.CurrentVideoInputDevice) { //当前视频设备为空时,只能语音通话 callMode = CallMode.AUDIO; } call.AnswerCall(callMode); call.CallMode = callMode; } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; Action noAction = () => { try { if (null != this.CurrentCall && this.CurrentCall.IsActive()) { this.CurrentCall.HangUpCall(); } var callMode = call.CallMode; if (null == deviceManager.CurrentVideoInputDevice) { //当前视频设备为空时,只能语音通话 callMode = CallMode.AUDIO; } call.AnswerCall(callMode); } catch (Exception ex) { log.Error(ex.Message); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }; callView.ShowMessage(true, msg, MessageBoxButtonsType.YesNo, MessageBoxIcon.Question , yesAction, noAction); } break; #endregion #region Content case EventType.SIP_CONTENT_INCOMING: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; #region ContentChannel var contentChannel = call.GetContentChannel(); if (null != contentChannel) { call.RemoveChannel(contentChannel.ChannelID); } contentChannel = new QLChannel(call, evt.StreamId, MediaType.CONTENT); contentChannel.ChannelName = "远端共享流"; call.AddChannel(contentChannel); contentChannel.Size = new Size(evt.WndWidth, evt.WndHeight); contentChannel.IsVideo = true; #endregion call.IsContentSupported = true; call.IsContentIdle = false; _contentRegion?.Close(); } break; case EventType.SIP_CONTENT_SENDING: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; #region ContentChannel var contentChannel = call.GetLocalContentChannel(); if (null != contentChannel) { call.RemoveChannel(contentChannel.ChannelID); } contentChannel = new QLChannel(call, -1, MediaType.LOCALCONTENT); contentChannel.ChannelName = "本地共享流"; call.AddChannel(contentChannel); contentChannel.IsVideo = true; #endregion call.IsContentSupported = true; call.IsContentIdle = false; /* * Action unSharedAction = () => * { * _currentCall?.StopSendContent(); * }; * * callView.ShowMessage(false, "共享内容中,确认停止共享吗?", MessageBoxButtonsType.OK, MessageBoxIcon.Question * , unSharedAction); */ #region 显示共享区域 _contentRegion?.Close(); _contentRegion = new ContentRegion(_currentCall, contentChannel); #endregion } break; case EventType.SIP_CONTENT_IDLE: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.IsContentSupported = true; call.IsContentIdle = true; _contentRegion?.Close(); } break; case EventType.SIP_CONTENT_UNSUPPORTED: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.IsContentSupported = false; call.IsContentIdle = false; _contentRegion?.Close(); } break; case EventType.SIP_CONTENT_CLOSED: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; #region ContentChannel var contentChannel = call.GetContentChannel(); if (null != contentChannel) { call.RemoveChannel(contentChannel.ChannelID); } var localContentChannel = call.GetLocalContentChannel(); if (null != localContentChannel) { call.RemoveChannel(localContentChannel.ChannelID); } #endregion call.IsContentSupported = true; call.IsContentIdle = true; _contentRegion?.Close(); callView.HideMessage(); } break; #endregion #region Device /* * case EventType.DEVICE_VIDEOINPUTCHANGED: break; * case EventType.DEVICE_AUDIOINPUTCHANGED: break; * case EventType.DEVICE_AUDIOOUTPUTCHANGED: break; * case EventType.DEVICE_VOLUMECHANGED: break; * case EventType.DEVICE_MONITORINPUTSCHANGED:break; */ #endregion #region Stream case EventType.STREAM_VIDEO_LOCAL_RESOLUTIONCHANGED: { var call = CurrentCall; if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; var localChannel = call.GetLocalChannel(); if (null == localChannel) { localChannel = new QLChannel(call, 0, MediaType.LOCAL, false); localChannel.ChannelName = "本地视频"; call.AddChannel(localChannel); } localChannel.Size = new Size(evt.WndWidth, evt.WndHeight); localChannel.IsVideo = true; callView.HideMessage(); } break; case EventType.STREAM_VIDEO_REMOTE_RESOLUTIONCHANGED: { var call = CurrentCall; if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; var channel = call.GetChannel(evt.StreamId); if (null == channel) { channel = new QLChannel(call, evt.StreamId, MediaType.REMOTE, false); channel.ChannelName = evt.RemoteChannelDisplayName; call.AddChannel(channel); } channel.Size = new Size(evt.WndWidth, evt.WndHeight); channel.IsVideo = true; callView.HideMessage(); } break; #endregion case EventType.NETWORK_CHANGED: break; case EventType.MFW_INTERNAL_TIME_OUT: break; #region Remote Refresh case EventType.REFRESH_ACTIVE_SPEAKER: { var call = GetCall(evt.CallHandle, true, evt); evt.Call = call; call.ActiveSpeakerId = evt.ActiveSpeakerStreamId; if (call == CurrentCall) { callView.HideMessage(); } } break; case EventType.REMOTE_VIDEO_REFRESH: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.ClearRemoteChannels(); call.ChannelNumber = evt.RemoteVideoChannelNum; call.ActiveSpeakerId = evt.ActiveSpeakerStreamId; if (call == CurrentCall) { callView.HideMessage(); } } break; case EventType.REMOTE_VIDEO_CHANNELSTATUS_CHANGED: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.AddChannel(evt.StreamId, MediaType.REMOTE); if (call.ActiveSpeakerId <= 0) { call.ActiveSpeakerId = evt.StreamId; } if (call == CurrentCall) { callView.HideMessage(); } } break; case EventType.REMOTE_VIDEO_DISPLAYNAME_UPDATE: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.SetChannelName(evt.StreamId, evt.RemoteChannelDisplayName); if (call == CurrentCall) { callView.HideMessage(); } } break; case EventType.SIP_CALL_MODE_CHANGED: { var call = GetCall(evt.CallHandle, true, evt); if (null == call) { throw new Exception("呼叫不存在"); } evt.Call = call; call.CallMode = evt.CallMode; } break; #endregion case EventType.IS_TALKING_STATUS_CHANGED: break; case EventType.CERTIFICATE_VERIFY: break; case EventType.TRANSCODER_FINISH: break; case EventType.ICE_STATUS_CHANGED: break; case EventType.SUTLITE_INCOMING_CALL: break; case EventType.SUTLITE_TERMINATE_CALL: break; case EventType.NOT_SUPPORT_VIDEOCODEC: break; case EventType.BANDWIDTH_LIMITATION: break; case EventType.MEDIA_ADDRESS_UPDATED: break; case EventType.AUTODISCOVERY_STATUS_CHANGED: break; } } catch (Exception ex) { log.Error(string.Format("Event 异常,ex={0},{1}", ex.Message, ex.StackTrace)); callView.ShowMessage(false, ex.Message, MessageBoxButtonsType.OK, MessageBoxIcon.Error); } }
private void OnChannelsCllectionChangedHandle(object sender, NotifyCollectionChangedEventArgs args) { #region ChannelView switch (args.Action) { case NotifyCollectionChangedAction.Add: { foreach (var item in args.NewItems) { var channel = item as QLChannel; if (null != channel) { var channelView = new ChannelView(channel); channelViews.Add(channel, channelView); this.Controls.Add(channelView); switch (channel.MediaType) { case MediaType.LOCAL: localChannel = channel; break; case MediaType.CONTENT: contentChannel = channel; break; case MediaType.LOCALCONTENT: contentChannel = channel; break; } } } } break; case NotifyCollectionChangedAction.Remove: { foreach (var item in args.OldItems) { var channel = item as QLChannel; if (channelViews.ContainsKey(channel)) { var channelView = channelViews[channel]; if (null != channelView) { this.Controls.Remove(channelView); channelView.Dispose(); } channelViews.Remove(channel); switch (channel.MediaType) { case MediaType.LOCAL: localChannel = null; break; case MediaType.CONTENT: contentChannel = null; break; case MediaType.LOCALCONTENT: contentChannel = null; break; } } } } break; case NotifyCollectionChangedAction.Reset: break; case NotifyCollectionChangedAction.Move: break; case NotifyCollectionChangedAction.Replace: break; } #endregion ViewRender(); }