public AudioVerifyViewModel(ISpeakerVerification verificationService)
        {
            StateMessage = "Hold on...";

            _beeper = DependencyService.Get <IBeepPlayer>();
            _verificationService = verificationService;

            Recorder.AudioInputReceived += async(object sender, string e) => { await Recorder_AudioInputReceived(sender, e); };
        }
Beispiel #2
0
        public RopuClient(
            ProtocolSwitch protocolSwitch,
            ServingNodeClient servingNodeClient,
            IMediaClient mediaClient,
            LoadBalancerProtocol loadBalancerProtocol,
            IClientSettings clientSettings,
            IBeepPlayer beepPlayer,
            RopuWebClient webClient,
            KeysClient keysClient)
        {
            _webClient            = webClient;
            _beepPlayer           = beepPlayer;
            _clientSettings       = clientSettings;
            _loadBalancerProtocol = loadBalancerProtocol;
            _protocolSwitch       = protocolSwitch;
            _servingNodeClient    = servingNodeClient;
            _mediaClient          = mediaClient;
            _servingNodeClient.SetControllingFunctionHandler(this);
            _retryTimer = new Ropu.Shared.Timer();
            _keysClient = keysClient;

            var allEvents = (EventId[])Enum.GetValues(typeof(EventId));

            //start
            _start        = new RopuState(StateId.Start);
            _stateManager = new StateManager <StateId, EventId>(_start);
            _stateManager.AddState(_start);
            _start.AddTransitions(allEvents, () => _start);

            //registered
            _registered = new RopuState(StateId.Registered)
            {
                Entry = async token =>
                {
                    if (_clientSettings.UserId == null)
                    {
                        throw new InvalidOperationException("UserId is not set");
                    }
                    _callGroup        = IdleGroup;
                    _registeredUserId = _clientSettings.UserId.Value;
                    if (_heartbeatTask == null)
                    {
                        _heartbeatTask = Heartbeat(_heartbeatCancellationTokenSource.Token);
                    }
                    _heartbeatOnEvent.Set(); //allows the heartbeat to continue
                    await Task.Run(() => {});
                },
            };
            _stateManager.AddState(_registered);
            _registered.AddTransition(EventId.CallRequest, () => _startingCall !);
            _registered.AddTransition(EventId.PttDown, () => _startingCall !);
            _registered.AddTransition(EventId.RegistrationResponseReceived, () => _registered);
            _registered.AddTransition(EventId.CallStartFailed, () => _registered);
            _registered.AddTransition(EventId.PttUp, () => _registered);
            _registered.AddTransition(EventId.GroupSelected, () => _registered);

            //unregistered
            _noGroup      = new RopuState(StateId.NoGroup);
            _unregistered = new RopuState(StateId.Unregistered)
            {
                Entry = async token =>
                {
                    _heartbeatOnEvent.Reset(); //stops the heartbeat
                    await Register(token);
                }
            };
            _unregistered.AddTransition(EventId.RegistrationResponseReceived, () => IdleGroup == null ? _noGroup : _registered);
            _unregistered.AddTransition(EventId.FloorIdle, () => _unregistered);
            _unregistered.AddTransition(EventId.FloorTaken, () => _unregistered);
            _unregistered.AddTransition(EventId.CallEnded, () => _unregistered);
            _unregistered.AddTransition(EventId.CallRequest, () => _unregistered);
            _unregistered.AddTransition(EventId.CallStartFailed, () => _unregistered);
            _unregistered.AddTransition(EventId.HeartbeatFailed, () => _unregistered);
            _unregistered.AddTransition(EventId.PttUp, () => _unregistered);
            _unregistered.AddTransition(EventId.PttDown, () => _unregistered);
            _unregistered.AddTransition(EventId.GroupSelected, () => _unregistered);

            _stateManager.AddState(_unregistered);

            //no group
            _noGroup.AddTransition(EventId.PttUp, () => _noGroup);
            _noGroup.AddTransition(EventId.PttDown, () => _noGroup);
            _noGroup.AddTransition(EventId.GroupSelected, () => _registered);
            _noGroup.AddTransition(EventId.RegistrationResponseReceived, () => _noGroup);
            _noGroup.AddTransition(EventId.CallRequest, () => _noGroup);
            _noGroup.AddTransition(EventId.CallStartFailed, () => _noGroup);


            _stateManager.AddState(_noGroup);

            //deregistering
            _deregistering = new RopuState(StateId.Deregistering)
            {
                Entry = async token => await Deregister(token),
            };
            _deregistering.AddTransition(EventId.DeregistrationResponseReceived, () => _unregistered);
            _deregistering.AddTransitions(allEvents.Where(e => e != EventId.DeregistrationResponseReceived), () => _deregistering);
            _deregistering.AddTransition(EventId.GroupSelected, () => _deregistering);
            _stateManager.AddState(_deregistering);

            //starting call
            _startingCall = new RopuState(StateId.StartingCall)
            {
                Entry = async token => await StartCall(token),
                Exit  = newState =>
                {
                    if (newState != _inCallTransmitting && newState != _inCallRequestingFloor)
                    {
                        _mediaClient.StopSendingAudio();
                    }
                }
            };
            _startingCall.AddTransition(EventId.CallStartFailed, () => _registered);
            _startingCall.AddTransition(EventId.PttUp, () => _startingCall);
            _startingCall.AddTransition(EventId.PttDown, () => _startingCall);
            _startingCall.AddTransition(EventId.RegistrationResponseReceived, () => _startingCall);
            _startingCall.AddTransition(EventId.CallRequest, () => _startingCall);
            _startingCall.AddTransition(EventId.GroupSelected, () => _startingCall);

            _stateManager.AddState(_startingCall);

            //in call idle
            _inCallIdle = new RopuState(StateId.InCallIdle);
            _inCallIdle.AddTransition(EventId.PttDown, () => _inCallRequestingFloor !);
            _inCallIdle.AddTransition(EventId.PttUp, () => _inCallIdle);
            _inCallIdle.AddTransition(EventId.RegistrationResponseReceived, () => _inCallIdle);
            _inCallIdle.AddTransition(EventId.CallRequest, () => _inCallIdle);
            _inCallIdle.AddTransition(EventId.CallStartFailed, () => _registered);
            _inCallIdle.AddTransition(EventId.GroupSelected, () => _inCallIdle);
            _stateManager.AddState(_inCallIdle);

            //in call receiving
            _inCallReceiveing = new RopuState(StateId.InCallReceiving);
            _inCallReceiveing.AddTransition(EventId.PttDown, () => _inCallReceiveing);
            _inCallReceiveing.AddTransition(EventId.PttUp, () => _inCallReceiveing);
            _inCallReceiveing.AddTransition(EventId.RegistrationResponseReceived, () => _inCallReceiveing);
            _inCallReceiveing.AddTransition(EventId.CallRequest, () => _inCallReceiveing);
            _inCallReceiveing.AddTransition(EventId.CallStartFailed, () => _registered);
            _inCallReceiveing.AddTransition(EventId.GroupSelected, () => _inCallReceiveing);
            _stateManager.AddState(_inCallReceiveing);

            //in call transmitting
            _inCallTransmitting = new RopuState(StateId.InCallTransmitting)
            {
                Entry = async token =>
                {
                    _beepPlayer.PlayGoAhead();
                    await Task.Run(() => {});
                },
                Exit = newState =>
                {
                    if (newState != _inCallTransmitting && newState != _inCallRequestingFloor)
                    {
                        _mediaClient.StopSendingAudio();
                    }
                }
            };
            _inCallTransmitting.AddTransition(EventId.PttUp, () => _inCallReleasingFloor !);
            _inCallTransmitting.AddTransition(EventId.RegistrationResponseReceived, () => _inCallTransmitting);
            _inCallTransmitting.AddTransition(EventId.CallRequest, () => _inCallTransmitting);
            _inCallTransmitting.AddTransition(EventId.CallStartFailed, () => _inCallTransmitting);
            _inCallTransmitting.AddTransition(EventId.PttDown, () => _inCallTransmitting);
            _inCallTransmitting.AddTransition(EventId.GroupSelected, () => _inCallTransmitting);

            _stateManager.AddState(_inCallTransmitting);

            //in call requesting floor
            _inCallRequestingFloor = new RopuState(StateId.InCallRequestingFloor)
            {
                Entry = token =>
                {
                    if (_callGroup == null)
                    {
                        return(Task.CompletedTask);
                    }
                    if (_clientSettings.UserId == null)
                    {
                        throw new InvalidOperationException("UserId is not set");
                    }
                    _servingNodeClient.SendFloorRequest(_callGroup.Value, _clientSettings.UserId.Value);
                    StartSendingAudio();
                    return(Task.CompletedTask);
                },
                Exit = newState =>
                {
                    if (newState != _inCallTransmitting && newState != _inCallRequestingFloor)
                    {
                        _mediaClient.StopSendingAudio();
                        _beepPlayer.PlayDenied();
                    }
                }
            };
            _inCallRequestingFloor.AddTransition(EventId.RegistrationResponseReceived, () => _inCallReleasingFloor !);
            _inCallRequestingFloor.AddTransition(EventId.CallRequest, () => _inCallReleasingFloor !);
            _inCallRequestingFloor.AddTransition(EventId.CallStartFailed, () => _registered);
            _inCallRequestingFloor.AddTransition(EventId.PttDown, () => _inCallRequestingFloor);
            _inCallRequestingFloor.AddTransition(EventId.PttUp, () => _inCallIdle);
            _inCallRequestingFloor.AddTransition(EventId.GroupSelected, () => _inCallRequestingFloor);
            _stateManager.AddState(_inCallRequestingFloor);

            //in call releasing floor
            _inCallReleasingFloor = new RopuState(StateId.InCallReleasingFloor)
            {
                Entry = async token =>
                {
                    if (_callGroup == null)
                    {
                        throw new InvalidOperationException("No call group");
                    }
                    if (_clientSettings.UserId == null)
                    {
                        throw new InvalidOperationException("UserId is not set");
                    }
                    while (!token.IsCancellationRequested)
                    {
                        _servingNodeClient.SendFloorReleased(_callGroup.Value, _clientSettings.UserId.Value);
                        await Task.Run(() => token.WaitHandle.WaitOne(1000));
                    }
                }
            };
            _inCallReleasingFloor.AddTransition(EventId.FloorGranted, () => _inCallReleasingFloor);
            _inCallReleasingFloor.AddTransition(EventId.RegistrationResponseReceived, () => _inCallReleasingFloor);
            _inCallReleasingFloor.AddTransition(EventId.CallRequest, () => _inCallReleasingFloor);
            _inCallReleasingFloor.AddTransition(EventId.CallStartFailed, () => _registered);
            _inCallReleasingFloor.AddTransition(EventId.PttDown, () => _inCallRequestingFloor);
            _inCallReleasingFloor.AddTransition(EventId.PttUp, () => _inCallReleasingFloor);
            _inCallReleasingFloor.AddTransition(EventId.GroupSelected, () => _inCallReleasingFloor);

            _stateManager.AddState(_inCallReleasingFloor);


            _inCallReleasingFloor.AddTransition(EventId.FloorGranted, () => _inCallReleasingFloor);


            _stateManager.StateChanged += (sender, args) =>
            {
                Console.WriteLine($"State Changed {this._stateManager.CurrentState}");
                StateChanged?.Invoke(this, args);
            };

            _stateManager.AddTransitionToAll(EventId.HeartbeatFailed, () => _unregistered, stateId => true);
            _stateManager.AddTransitionToAll(EventId.NotRegistered, () => _unregistered, stateId => true);
            _stateManager.AddTransitionToAll(EventId.CallEnded, () => _registered, stateId => stateId != StateId.Unregistered && stateId != StateId.Start && stateId != StateId.Deregistering);
            _stateManager.AddTransitionToAll(EventId.FloorIdle, () => _inCallIdle, IsRegistered);
            _stateManager.AddTransitionToAll(EventId.FloorTaken, () => _inCallReceiveing, IsRegistered);
            _stateManager.AddTransitionToAll(EventId.FloorGranted, () => _inCallTransmitting, stateId => stateId != StateId.InCallReleasingFloor);
            _stateManager.AddTransitionToAll(EventId.DeregistrationResponseReceived, () => _unregistered, stateId => true);
            _stateManager.AddTransitionToAll(EventId.GroupDeselected, () => _noGroup, stateId => true);

            _stateManager.CheckEventsAreHandledByAll((EventId[])Enum.GetValues(typeof(EventId)));
        }