private void OnSignalBarsChanged(VoIPControllerWrapper sender, int newCount) { this.BeginOnUIThread(() => { SetSignalBars(newCount); }); }
private async void Show(Call call, VoIPControllerWrapper controller, DateTime started) { if (_callPage == null) { if (ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay)) { _callLifetime = await _viewService.OpenAsync(() => _callPage = _callPage ?? new VoIPPage(ProtoService, CacheService, Aggregator, _call, _controller, _callStarted), call.Id); _callLifetime.WindowWrapper.ApplicationView().Consolidated -= ApplicationView_Consolidated; _callLifetime.WindowWrapper.ApplicationView().Consolidated += ApplicationView_Consolidated; } else { _callPage = new VoIPPage(ProtoService, CacheService, Aggregator, _call, _controller, _callStarted); _callDialog = new OverlayPage(); _callDialog.HorizontalAlignment = HorizontalAlignment.Stretch; _callDialog.VerticalAlignment = VerticalAlignment.Stretch; _callDialog.Content = _callPage; _callDialog.IsOpen = true; } Aggregator.Publish(new UpdateCallDialog(call, true)); } await _callPage.Dispatcher.RunAsync(Windows.UI.Core.CoreDispatcherPriority.Normal, () => { if (controller != null) { _callPage.Connect(controller); } _callPage.Update(call, started); }); }
private void OnCallStateChanged(VoIPControllerWrapper sender, libtgvoip.CallState newState) { this.BeginOnUIThread(() => { switch (newState) { case libtgvoip.CallState.WaitInit: case libtgvoip.CallState.WaitInitAck: _state = newState; StateLabel.Content = Strings.Resources.VoipConnecting; break; case libtgvoip.CallState.Established: _state = newState; StateLabel.Content = "00:00"; SignalBarsLabel.Visibility = Visibility.Visible; StartUpdatingCallDuration(); break; case libtgvoip.CallState.Failed: switch (sender.GetLastError()) { case libtgvoip.Error.Incompatible: case libtgvoip.Error.Timeout: case libtgvoip.Error.Unknown: _state = newState; StateLabel.Content = Strings.Resources.VoipFailed; break; } break; } }); }
public async void OnCallStateChanged(VoIPControllerWrapper sender, CallState newState) { if (newState == CallState.Failed) { var error = _controller.GetLastError(); } await UpdateStateAsync((TLPhoneCallState)newState); }
public async void OnSignalBarsChanged(VoIPControllerWrapper sender, int count) { if (_connection != null) { VoIPCallTask.Log("Mediator initialized", "Informing foreground about signal bars"); var data = TLTuple.Create(count); await _connection.SendMessageAsync(new ValueSet { { "caption", "voip.signalBars" }, { "request", TLSerializationService.Current.Serialize(data) } }); } }
private void InitiateActualEncryptedCall() { #if WINDOWS_PHONE _mtProtoService.GetCallConfigAsync(result => { VoIPControllerWrapper.UpdateServerConfig(result.Data.ToString()); var logFile = ApplicationData.Current.LocalFolder.Path + "\\tgvoip.logFile.txt"; var statsDumpFile = ApplicationData.Current.LocalFolder.Path + "\\tgvoip.statsDump.txt"; if (_controller != null) { //_controller.Dispose(); _controller = null; } _cacheService.GetConfigAsync(config => { var config60 = config as TLConfig60; if (config60 != null) { _controller = new VoIPControllerWrapper(); _controller.SetConfig(config60.CallPacketTimeoutMs.Value / 1000.0, config60.CallConnectTimeoutMs.Value / 1000.0, DataSavingMode.Never, false, false, true, logFile, statsDumpFile); _controller.SetStateCallback(this); _controller.SetEncryptionKey(_authKey, _outgoing); var phoneCall = _call.PhoneCall as TLPhoneCall; if (phoneCall != null) { var connection = phoneCall.Connection; var endpoints = new Endpoint[phoneCall.AlternativeConnections.Count + 1]; endpoints[0] = connection.ToEndpoint(); for (int i = 0; i < phoneCall.AlternativeConnections.Count; i++) { connection = phoneCall.AlternativeConnections[i]; endpoints[i + 1] = connection.ToEndpoint(); } _controller.SetPublicEndpoints(endpoints, phoneCall.Protocol.UdpP2P); _controller.Start(); _controller.Connect(); } } }); }, error => { }); #endif }
public void Dispose() { _disposed = true; _debugTimer.Stop(); _durationTimer.Stop(); if (_controller != null) { //_controller.CallStateChanged -= OnCallStateChanged; //_controller.SignalBarsChanged -= OnSignalBarsChanged; _controller = null; } }
public void Connect(VoIPControllerWrapper controller) { _controller = controller; // Let's avoid duplicated events _controller.CallStateChanged -= OnCallStateChanged; _controller.CallStateChanged += OnCallStateChanged; _controller.SignalBarsChanged -= OnSignalBarsChanged; _controller.SignalBarsChanged += OnSignalBarsChanged; _controller.SetMicMute(_isMuted); OnCallStateChanged(controller, controller.GetConnectionState()); OnSignalBarsChanged(controller, controller.GetSignalBarsCount()); }
public void Dispose() { _disposed = true; _debugTimer.Stop(); _durationTimer.Stop(); if (_controller != null) { //_controller.CallStateChanged -= OnCallStateChanged; //_controller.SignalBarsChanged -= OnSignalBarsChanged; _controller = null; } if (ApiInformation.IsApiContractPresent("Windows.Phone.PhoneContract", 1)) { AudioRoutingManager.GetDefault().AudioEndpointChanged -= AudioEndpointChanged; } }
private async void Show(Call call, VoIPControllerWrapper controller) { if (_callPage == null) { if (ApiInformation.IsMethodPresent("Windows.UI.ViewManagement.ApplicationView", "IsViewModeSupported") && ApplicationView.GetForCurrentView().IsViewModeSupported(ApplicationViewMode.CompactOverlay)) { _callLifetime = await _viewService.OpenAsync(() => _callPage = _callPage ?? new PhoneCallPage(ProtoService, CacheService, Aggregator, _call, _controller), 0); _callLifetime.Released += (s, args) => { _callPage.Dispose(); _callPage = null; }; } else { _callPage = new PhoneCallPage(ProtoService, CacheService, Aggregator, _call, _controller); _callDialog = new ContentDialogBase(); _callDialog.HorizontalAlignment = HorizontalAlignment.Stretch; _callDialog.VerticalAlignment = VerticalAlignment.Stretch; _callDialog.Content = _callPage; _callDialog.IsOpen = true; } } _callPage.BeginOnUIThread(() => { if (controller != null) { _callPage.Connect(controller); } _callPage.Update(call); }); }
public void Handle(UpdateCall update) { _call = update.Call; if (update.Call.State is CallStatePending pending) { if (update.Call.IsOutgoing && pending.IsCreated && pending.IsReceived) { if (pending.IsCreated && pending.IsReceived) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_ringback.mp3")); _mediaPlayer.IsLoopingEnabled = true; _mediaPlayer.Play(); } } } if (update.Call.State is CallStateReady ready) { var user = CacheService.GetUser(update.Call.UserId); if (user == null) { return; } VoIPControllerWrapper.UpdateServerConfig(ready.Config); var logFile = Path.Combine(ApplicationData.Current.LocalFolder.Path, $"{SessionId}", "tgvoip.logFile.txt"); var statsDumpFile = Path.Combine(ApplicationData.Current.LocalFolder.Path, $"{SessionId}", "tgvoip.statsDump.txt"); var call_packet_timeout_ms = CacheService.GetOption <OptionValueInteger>("call_packet_timeout_ms"); var call_connect_timeout_ms = CacheService.GetOption <OptionValueInteger>("call_connect_timeout_ms"); if (_controller != null) { _controller.Dispose(); _controller = null; } _controller = new VoIPControllerWrapper(); _controller.SetConfig(call_packet_timeout_ms.Value / 1000.0, call_connect_timeout_ms.Value / 1000.0, base.Settings.UseLessData, true, true, true, logFile, statsDumpFile); _controller.CallStateChanged += (s, args) => { BeginOnUIThread(() => { if (args == libtgvoip.CallState.WaitInit || args == libtgvoip.CallState.WaitInitAck) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_connecting.mp3")); _mediaPlayer.IsLoopingEnabled = false; _mediaPlayer.Play(); } else if (args == libtgvoip.CallState.Established) { _mediaPlayer.Source = null; } }); }; BeginOnUIThread(() => { Show(update.Call, _controller); }); var p2p = base.Settings.PeerToPeerMode == 0 || (base.Settings.PeerToPeerMode == 1 && user.OutgoingLink is LinkStateIsContact); var endpoints = new Endpoint[ready.Connections.Count]; for (int i = 0; i < endpoints.Length; i++) { endpoints[i] = new Endpoint { id = ready.Connections[i].Id, ipv4 = ready.Connections[i].Ip, ipv6 = ready.Connections[i].Ipv6, peerTag = ready.Connections[i].PeerTag.ToArray(), port = (ushort)ready.Connections[i].Port }; } _controller.SetEncryptionKey(ready.EncryptionKey.ToArray(), update.Call.IsOutgoing); _controller.SetPublicEndpoints(endpoints, ready.Protocol.UdpP2p && p2p, 74); _controller.Start(); _controller.Connect(); } else if (update.Call.State is CallStateDiscarded discarded) { if (discarded.NeedDebugInformation) { ProtoService.Send(new SendCallDebugInformation(update.Call.Id, _controller.GetDebugLog())); } if (discarded.NeedRating) { BeginOnUIThread(async() => { var dialog = new PhoneCallRatingView(); var confirm = await dialog.ShowQueuedAsync(); if (confirm == ContentDialogResult.Primary) { ProtoService.Send(new SendCallRating(update.Call.Id, dialog.Rating + 1, dialog.Rating >= 0 && dialog.Rating <= 3 ? dialog.Comment : null)); } }); } _controller?.Dispose(); _controller = null; _call = null; } BeginOnUIThread(() => { switch (update.Call.State) { case CallStateDiscarded discarded: if (update.Call.IsOutgoing && discarded.Reason is CallDiscardReasonDeclined) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_busy.mp3")); _mediaPlayer.IsLoopingEnabled = true; _mediaPlayer.Play(); Show(update.Call, null); } else { _mediaPlayer.Source = null; Hide(); } break; case CallStateError error: Hide(); break; default: Show(update.Call, null); break; } }); }
public VoIPPage(IProtoService protoService, ICacheService cacheService, IEventAggregator aggregator, Call call, VoIPControllerWrapper controller, DateTime started) { this.InitializeComponent(); _protoService = protoService; _cacheService = cacheService; _aggregator = aggregator; _durationTimer = new DispatcherTimer(); _durationTimer.Interval = TimeSpan.FromMilliseconds(500); _durationTimer.Tick += DurationTimer_Tick; _debugTimer = new DispatcherTimer(); _debugTimer.Interval = TimeSpan.FromMilliseconds(500); _debugTimer.Tick += DebugTimer_Tick; #region Reset LargeEmoji0.Source = null; LargeEmoji1.Source = null; LargeEmoji2.Source = null; LargeEmoji3.Source = null; #endregion #region Composition _descriptionVisual = ElementCompositionPreview.GetElementVisual(DescriptionLabel); _largeVisual = ElementCompositionPreview.GetElementVisual(LargePanel); _compositor = _largeVisual.Compositor; var graphicsEffect = new GaussianBlurEffect { Name = "Blur", BlurAmount = 0, BorderMode = EffectBorderMode.Hard, Source = new CompositionEffectSourceParameter("backdrop") }; var effectFactory = _compositor.CreateEffectFactory(graphicsEffect, new[] { "Blur.BlurAmount" }); var effectBrush = effectFactory.CreateBrush(); var backdrop = _compositor.CreateBackdropBrush(); effectBrush.SetSourceParameter("backdrop", backdrop); _blurBrush = effectBrush; _blurVisual = _compositor.CreateSpriteVisual(); _blurVisual.Brush = _blurBrush; // Why does this crashes due to an access violation exception on certain devices? ElementCompositionPreview.SetElementChildVisual(BlurPanel, _blurVisual); #endregion var titleBar = ApplicationView.GetForCurrentView().TitleBar; titleBar.ButtonBackgroundColor = Colors.Transparent; titleBar.ButtonForegroundColor = Colors.White; titleBar.ButtonInactiveBackgroundColor = Colors.Transparent; titleBar.ButtonInactiveForegroundColor = Colors.White; Window.Current.SetTitleBar(BlurPanel); if (call != null) { Update(call, started); } if (controller != null) { Connect(controller); } }
public async void Handle(UpdateCall update) { _call = update.Call; if (update.Call.State is CallStatePending pending) { if (update.Call.IsOutgoing && pending.IsCreated && pending.IsReceived) { if (pending.IsCreated && pending.IsReceived) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_ringback.mp3")); _mediaPlayer.IsLoopingEnabled = true; _mediaPlayer.Play(); } } } if (update.Call.State is CallStateReady ready) { var user = CacheService.GetUser(update.Call.UserId); if (user == null) { return; } VoIPControllerWrapper.UpdateServerConfig(ready.Config); var logFile = Path.Combine(ApplicationData.Current.LocalFolder.Path, $"{SessionId}", $"voip{update.Call.Id}.txt"); var statsDumpFile = Path.Combine(ApplicationData.Current.LocalFolder.Path, $"{SessionId}", "tgvoip.statsDump.txt"); var call_packet_timeout_ms = CacheService.Options.CallPacketTimeoutMs; var call_connect_timeout_ms = CacheService.Options.CallConnectTimeoutMs; if (_controller != null) { _controller.Dispose(); _controller = null; } var config = new VoIPConfig { initTimeout = call_packet_timeout_ms / 1000.0, recvTimeout = call_connect_timeout_ms / 1000.0, dataSaving = base.Settings.UseLessData, enableAEC = true, enableNS = true, enableAGC = true, enableVolumeControl = true, logFilePath = logFile, statsDumpFilePath = statsDumpFile }; _controller = new VoIPControllerWrapper(); _controller.SetConfig(config); _controller.CurrentAudioInput = SettingsService.Current.VoIP.InputDevice; _controller.CurrentAudioOutput = SettingsService.Current.VoIP.OutputDevice; _controller.SetInputVolume(SettingsService.Current.VoIP.InputVolume); _controller.SetOutputVolume(SettingsService.Current.VoIP.OutputVolume); _controller.CallStateChanged += (s, args) => { BeginOnUIThread(() => { if (args == libtgvoip.CallState.WaitInit || args == libtgvoip.CallState.WaitInitAck) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_connecting.mp3")); _mediaPlayer.IsLoopingEnabled = false; _mediaPlayer.Play(); } else if (args == libtgvoip.CallState.Established) { _callStarted = DateTime.Now; _mediaPlayer.Source = null; } }); }; BeginOnUIThread(() => { Show(update.Call, _controller, _callStarted); }); var endpoints = new Endpoint[ready.Connections.Count]; for (int i = 0; i < endpoints.Length; i++) { endpoints[i] = ready.Connections[i].ToEndpoint(); } _controller.SetEncryptionKey(ready.EncryptionKey.ToArray(), update.Call.IsOutgoing); _controller.SetPublicEndpoints(endpoints, ready.Protocol.UdpP2p && ready.AllowP2p, ready.Protocol.MaxLayer); _controller.Start(); _controller.Connect(); } else if (update.Call.State is CallStateDiscarded discarded) { if (discarded.NeedDebugInformation) { ProtoService.Send(new SendCallDebugInformation(update.Call.Id, _controller.GetDebugLog())); } if (discarded.NeedRating) { BeginOnUIThread(async() => await SendRatingAsync(update.Call.Id)); } _controller?.Dispose(); _controller = null; _call = null; } await Dispatcher.DispatchAsync(() => { switch (update.Call.State) { case CallStateDiscarded discarded: if (update.Call.IsOutgoing && discarded.Reason is CallDiscardReasonDeclined) { _mediaPlayer.Source = MediaSource.CreateFromUri(new Uri("ms-appx:///Assets/Audio/voip_busy.mp3")); _mediaPlayer.IsLoopingEnabled = true; _mediaPlayer.Play(); Show(update.Call, null, _callStarted); } else { _mediaPlayer.Source = null; Hide(); } break; case CallStateError error: Hide(); break; default: Show(update.Call, null, _callStarted); break; } }); }
private async void OnRequestReceived(AppServiceConnection sender, AppServiceRequestReceivedEventArgs args) { var deferral = args.GetDeferral(); var message = args.Request.Message; if (message.ContainsKey("update")) { var buffer = message["update"] as string; var update = TLSerializationService.Current.Deserialize(buffer) as TLUpdatePhoneCall; if (update != null) { Handle(update); } } else if (message.ContainsKey("caption")) { var caption = message["caption"] as string; if (caption.Equals("phone.discardCall")) { if (_phoneCall != null) { var buffer = message["request"] as string; var payload = TLSerializationService.Current.Deserialize <byte[]>(buffer); var reader = new TLBinaryReader(payload); var req = new TLTuple <double>(reader); reader.Dispose(); var missed = _state == TLPhoneCallState.Ringing || (_state == TLPhoneCallState.Waiting && _outgoing); var declined = _state == TLPhoneCallState.WaitingIncoming; TLPhoneCallDiscardReasonBase reason = missed ? new TLPhoneCallDiscardReasonMissed() : declined ? (TLPhoneCallDiscardReasonBase) new TLPhoneCallDiscardReasonBusy() : new TLPhoneCallDiscardReasonHangup(); var req2 = new TLPhoneDiscardCall { Peer = _phoneCall.ToInputPhoneCall(), Reason = reason, Duration = (int)req.Item1 }; const string caption2 = "phone.discardCall"; var response = await SendRequestAsync <TLUpdatesBase>(caption2, req2); if (response.IsSucceeded) { if (response.Result is TLUpdates updates) { var update = updates.Updates.FirstOrDefault(x => x is TLUpdatePhoneCall) as TLUpdatePhoneCall; if (update != null) { Handle(update); } } } } else if (_systemCall != null) { _systemCall.AnswerRequested -= OnAnswerRequested; _systemCall.RejectRequested -= OnRejectRequested; _systemCall.NotifyCallEnded(); _systemCall = null; } else if (_deferral != null) { _deferral.Complete(); } } else if (caption.Equals("phone.mute") || caption.Equals("phone.unmute")) { if (_controller != null) { _controller.SetMicMute(caption.Equals("phone.mute")); var coordinator = VoipCallCoordinator.GetDefault(); if (caption.Equals("phone.mute")) { coordinator.NotifyMuted(); } else { coordinator.NotifyUnmuted(); } } } else if (caption.Equals("voip.startCall")) { var buffer = message["request"] as string; var req = TLSerializationService.Current.Deserialize <TLUser>(buffer); _user = req; OutgoingCall(req.Id, req.AccessHash.Value); } else if (caption.Equals("voip.debugString")) { if (_controller != null) { await args.Request.SendResponseAsync(new ValueSet { { "result", _controller.GetDebugString() }, { "version", VoIPControllerWrapper.GetVersion() } }); } } } else if (message.ContainsKey("voip.callInfo")) { if (_phoneCall != null) { await args.Request.SendResponseAsync(new ValueSet { { "result", TLSerializationService.Current.Serialize(_phoneCall) } }); } else { await args.Request.SendResponseAsync(new ValueSet { { "error", false } }); } } deferral.Complete(); }
private async void ProcessUpdates() { while (_queue.Count > 0) { var update = _queue.Dequeue(); _phoneCall = update.PhoneCall; if (update.PhoneCall is TLPhoneCallRequested requested) { _peer = requested.ToInputPhoneCall(); var req = new TLPhoneReceivedCall { Peer = new TLInputPhoneCall { Id = requested.Id, AccessHash = requested.AccessHash } }; const string caption = "phone.receivedCall"; var response = await SendRequestAsync <bool>(caption, req); var responseUser = await SendRequestAsync <TLUser>("voip.getUser", new TLPeerUser { UserId = requested.AdminId }); if (responseUser.Result == null) { return; } var user = responseUser.Result; var photo = new Uri("ms-appx:///Assets/Logos/Square150x150Logo/Square150x150Logo.png"); if (user.Photo is TLUserProfilePhoto profile && profile.PhotoSmall is TLFileLocation location) { var fileName = string.Format("{0}_{1}_{2}.jpg", location.VolumeId, location.LocalId, location.Secret); var temp = FileUtils.GetTempFileUri(fileName); photo = temp; } var coordinator = VoipCallCoordinator.GetDefault(); var call = coordinator.RequestNewIncomingCall("Unigram", user.FullName, user.DisplayName, photo, "Unigram", null, "Unigram", null, VoipPhoneCallMedia.Audio, TimeSpan.FromSeconds(128)); _user = user; _outgoing = false; _systemCall = call; _systemCall.AnswerRequested += OnAnswerRequested; _systemCall.RejectRequested += OnRejectRequested; } else if (update.PhoneCall is TLPhoneCallDiscarded discarded) { if (false) { discarded.IsNeedRating = true; } if (discarded.IsNeedRating) { await _connection.SendMessageAsync(new ValueSet { { "caption", "voip.setCallRating" }, { "request", TLSerializationService.Current.Serialize(_peer) } }); } if (discarded.IsNeedDebug) { var req = new TLPhoneSaveCallDebug(); req.Debug = new TLDataJSON { Data = _controller.GetDebugLog() }; req.Peer = _peer; await SendRequestAsync <bool>("phone.saveCallDebug", req); } await UpdateStateAsync(TLPhoneCallState.Ended); if (_controller != null) { _controller.Dispose(); _controller = null; } if (_connection != null) { _connection.RequestReceived -= OnRequestReceived; _connection = null; } if (_systemCall != null) { try { _systemCall.AnswerRequested -= OnAnswerRequested; _systemCall.RejectRequested -= OnRejectRequested; _systemCall.NotifyCallEnded(); _systemCall = null; } catch { if (_deferral != null) { _deferral.Complete(); } } Debug.WriteLine("VoIP call disposed"); } else if (_deferral != null) { _deferral.Complete(); } } else if (update.PhoneCall is TLPhoneCallAccepted accepted) { await UpdateStateAsync(TLPhoneCallState.ExchangingKeys); _phoneCall = accepted; auth_key = computeAuthKey(accepted); byte[] authKeyHash = Utils.ComputeSHA1(auth_key); byte[] authKeyId = new byte[8]; Buffer.BlockCopy(authKeyHash, authKeyHash.Length - 8, authKeyId, 0, 8); long fingerprint = Utils.BytesToLong(authKeyId); //this.authKey = authKey; //keyFingerprint = fingerprint; var request = new TLPhoneConfirmCall { GA = g_a, KeyFingerprint = fingerprint, Peer = new TLInputPhoneCall { Id = accepted.Id, AccessHash = accepted.AccessHash }, Protocol = new TLPhoneCallProtocol { IsUdpP2p = true, IsUdpReflector = true, MinLayer = Telegram.Api.Constants.CallsMinLayer, MaxLayer = Telegram.Api.Constants.CallsMaxLayer, } }; var response = await SendRequestAsync <TLPhonePhoneCall>("phone.confirmCall", request); if (response.IsSucceeded) { _systemCall.NotifyCallActive(); Handle(new TLUpdatePhoneCall { PhoneCall = response.Result.PhoneCall }); } } else if (update.PhoneCall is TLPhoneCall call) { _phoneCall = call; if (auth_key == null) { auth_key = computeAuthKey(call); g_a = call.GAOrB; } var buffer = TLUtils.Combine(auth_key, g_a); var sha256 = Utils.ComputeSHA256(buffer); _emojis = EncryptionKeyEmojifier.EmojifyForCall(sha256); var response = await SendRequestAsync <TLDataJSON>("phone.getCallConfig", new TLPhoneGetCallConfig()); if (response.IsSucceeded) { var responseConfig = await SendRequestAsync <TLConfig>("voip.getConfig", new TLPeerUser()); var config = responseConfig.Result; VoIPControllerWrapper.UpdateServerConfig(response.Result.Data); var logFile = ApplicationData.Current.LocalFolder.Path + "\\tgvoip.logFile.txt"; var statsDumpFile = ApplicationData.Current.LocalFolder.Path + "\\tgvoip.statsDump.txt"; if (_controller != null) { _controller.Dispose(); _controller = null; } _controller = new VoIPControllerWrapper(); _controller.SetConfig(config.CallPacketTimeoutMs / 1000.0, config.CallConnectTimeoutMs / 1000.0, DataSavingMode.Never, true, true, true, logFile, statsDumpFile); SettingsHelper.CleanUp(); if (SettingsHelper.IsCallsProxyEnabled) { var server = SettingsHelper.ProxyServer ?? string.Empty; var port = SettingsHelper.ProxyPort; var user = SettingsHelper.ProxyUsername ?? string.Empty; var pass = SettingsHelper.ProxyPassword ?? string.Empty; _controller.SetProxy(ProxyProtocol.SOCKS5, server, (ushort)port, user, pass); } else { _controller.SetProxy(ProxyProtocol.None, string.Empty, 0, string.Empty, string.Empty); } _controller.SetStateCallback(this); _controller.SetEncryptionKey(auth_key, _outgoing); var connection = call.Connection; var endpoints = new Endpoint[call.AlternativeConnections.Count + 1]; endpoints[0] = connection.ToEndpoint(); for (int i = 0; i < call.AlternativeConnections.Count; i++) { connection = call.AlternativeConnections[i]; endpoints[i + 1] = connection.ToEndpoint(); } _controller.SetPublicEndpoints(endpoints, call.Protocol.IsUdpP2p && ApplicationSettings.Current.IsPeerToPeer); _controller.Start(); _controller.Connect(); } //await Task.Delay(50000); //var req = new TLPhoneDiscardCall { Peer = new TLInputPhoneCall { Id = call.Id, AccessHash = call.AccessHash }, Reason = new TLPhoneCallDiscardReasonHangup() }; //const string caption = "phone.discardCall"; //await SendRequestAsync<TLUpdatesBase>(caption, req); //_systemCall.NotifyCallEnded(); } else if (update.PhoneCall is TLPhoneCallWaiting waiting) { _peer = waiting.ToInputPhoneCall(); if (_state == TLPhoneCallState.Waiting && waiting.HasReceiveDate && waiting.ReceiveDate != 0) { await UpdateStateAsync(TLPhoneCallState.Ringing); } } } }