Exemple #1
0
 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);
            });
        }
Exemple #3
0
        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;
                }
            });
        }
Exemple #4
0
        public async void OnCallStateChanged(VoIPControllerWrapper sender, CallState newState)
        {
            if (newState == CallState.Failed)
            {
                var error = _controller.GetLastError();
            }

            await UpdateStateAsync((TLPhoneCallState)newState);
        }
Exemple #5
0
        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) } });
            }
        }
Exemple #6
0
        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
        }
Exemple #7
0
        public void Dispose()
        {
            _disposed = true;
            _debugTimer.Stop();
            _durationTimer.Stop();

            if (_controller != null)
            {
                //_controller.CallStateChanged -= OnCallStateChanged;
                //_controller.SignalBarsChanged -= OnSignalBarsChanged;
                _controller = null;
            }
        }
Exemple #8
0
        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());
        }
Exemple #9
0
        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;
            }
        }
Exemple #10
0
        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);
            });
        }
Exemple #11
0
        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;
                }
            });
        }
Exemple #12
0
        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;
                }
            });
        }
Exemple #14
0
        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();
        }
Exemple #15
0
        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);
                    }
                }
            }
        }