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 List <Endpoint>(); foreach (var server in ready.Servers) { if (server.Type is CallServerTypeTelegramReflector telegramReflector) { endpoints.Add(new Endpoint { id = server.Id, ipv4 = server.IpAddress, ipv6 = server.Ipv6Address, peerTag = telegramReflector.PeerTag.ToArray(), port = (ushort)server.Port }); } } _controller.SetEncryptionKey(ready.EncryptionKey.ToArray(), update.Call.IsOutgoing); _controller.SetPublicEndpoints(endpoints.ToArray(), 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; } }); }