/// <inheritdoc />
        protected override async Task InternalExecute(Channel incomingCallChannel, StasisStartEventArgs args)
        {
            var callerExtension = incomingCallChannel.Caller.Number;
            var callId          = Guid.NewGuid();

            var mainBridge = await InitializeMainBridge(incomingCallChannel.Id, callerExtension, callId);

            if (mainBridge == null)
            {
                return;
            }

            var channel = new DAL.Entities.Channel
            {
                ChannelId = incomingCallChannel.Id,
                Extension = callerExtension,
                CallId    = callId,
                BridgeId  = mainBridge,
                Role      = ChannelRoleType.ExternalChannel
            };

            var bNumber = incomingCallChannel.Dialplan.Exten;
            await _queueSender.Publish(new IncomingCallIntegrationEvent
            {
                CallId          = callId,
                CallerExtension = callerExtension,
                BNumber         = bNumber,
            });

            Logger.Information($"Sent message to queue about incoming call. Caller: {callerExtension}; ChannelId: {incomingCallChannel.Id}");

            await ChannelRepository.AddChannel(channel);
        }
        /// <summary>
        /// Выполнить команду
        /// </summary>
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            if (!(args is MuteStasisEventArgs model))
            {
                throw new ArgumentException($"Не правильный тип аргумента {nameof(args)}");
            }

            var muteStatusData = model.MuteStatusData;

            try
            {
                var muteChannel = await ChannelRepository.GetChannelByCallId(muteStatusData.CallId);

                if (muteStatusData.Muted)
                {
                    await AriClient.MuteChannel(muteChannel.ChannelId, "in");
                }
                else
                {
                    await AriClient.UnmuteChannel(muteChannel.ChannelId, "in");
                }
            }
            catch (Exception ex)
            {
                Logger.Warning(ex.Message);
                throw new Exception($"Не удалось установить параметр мюте со значением {model.MuteStatusData.Muted}");
            }
        }
        /// <summary>
        /// Создать канал для пользователя, который принимает входящий вызов
        /// </summary>
        public async Task <Result> AcceptIncomingCall(RouteCallDto routeDto)
        {
            if (!routeDto.FromCallId.HasValue)
            {
                _logger.Warning("AcceptIncomingCall. Missing id waiting incoming call");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning("AcceptIncomingCall. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            _logger.Information($"AcceptIncomingCall. Пользователь {routeDto.ToExtension} принимает вызов c Id {routeDto.FromCallId}. CallId: {routeDto.ToCallId}");

            var incomingCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);

            if (incomingCallChannel == null)
            {
                _logger.Warning("AcceptIncomingCall. Incoming call channel not found.");
                return(Result.Failure(ErrorCodes.ChannelNotFound));
            }

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.AcceptIncomingCall,
                ChannelId = incomingCallChannel.ChannelId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, incomingCallChannel.Extension, routeDto.ToExtension);

            return(originateResult);
        }
Beispiel #4
0
        /// <summary>
        /// Выполнить команду
        /// </summary>
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            if (!(args is RecordingEventArgs eventArgs))
            {
                throw new ArgumentException($"RecordingEndedCommand. Incorrect argument type {nameof(args)}");
            }

            try
            {
                var audioRecord = await AudioRecordRepository.GetRecordByName(eventArgs.RecordName);

                if (audioRecord == null || audioRecord.RecordingStartTime.HasValue == false)
                {
                    Logger.Warning($"Record with name {eventArgs.RecordName} not found");
                    return;
                }

                Logger.Information($"Audio record created. RecordName: {eventArgs.RecordName};");
                await _queueSender.Publish(new AudioRecordedIntegrationEvent
                {
                    LineId             = audioRecord.LineId,
                    CallId             = audioRecord.CallId,
                    FileName           = $"{eventArgs.RecordName}.{AsteriskAriClient.RecordingFormat}",
                    RecordingStartTime = audioRecord.RecordingStartTime.Value,
                    RecordingEndTime   = eventArgs.EventTime
                });

                audioRecord.RecordingEndTime = eventArgs.EventTime;
                await AudioRecordRepository.UpdateRecord(audioRecord);
            }
            catch (Exception ex)
            {
                Logger.Warning("RecordingEndedCommand.Error.", ex);
            }
        }
        private string GetEncodedAppArgs(StasisStartEventArgs args)
        {
            var serializedArgs = JsonConvert.SerializeObject(args);
            var encodedArgs    = WebUtility.HtmlEncode(serializedArgs);

            return($"\"{encodedArgs}\"");
        }
Beispiel #6
0
        /// <summary>
        /// Создать snoop-копию канала
        /// </summary>
        protected async Task InitializeSnoopChannel(
            string agentChannelId,
            string agentExtension,
            ChannelRoleType agentRole,
            Guid agentCallId,
            string destinationBridgeId,
            StasisStartEventArgs startEventArgs,
            SnoopBridgeType bridgeType,
            bool channelForSpeak = false)
        {
            var whisper        = GetWhisperForSnoop(bridgeType, channelForSpeak);
            var spy            = GetSpyForSnoop(bridgeType, channelForSpeak);
            var snoopChannelId = GetSnoopChannelId(agentRole, agentExtension) + $"_spy-{spy}_whisper-{whisper}";

            startEventArgs.RouteData.ToExtension = agentExtension;
            startEventArgs.RouteData.ToCallId    = agentCallId;

            var snoopArgs = new StasisStartEventArgs
            {
                EventType         = channelForSpeak ? StasisStartEventType.AddToSpeakSnoopBridge : StasisStartEventType.AddToSnoopBridge,
                ChannelId         = snoopChannelId,
                BridgeId          = destinationBridgeId,
                RouteData         = startEventArgs.RouteData,
                OriginalChannelId = agentChannelId
            };

            var encodedArgs = JsonSerializer.EncodeData(snoopArgs);
            await AriClient.SnoopChannel(agentChannelId, spy, whisper, encodedArgs, snoopChannelId);
        }
Beispiel #7
0
        /// <summary>
        /// Выполнить команду
        /// </summary>
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            if (!(args is RecordingEventArgs eventArgs))
            {
                throw new ArgumentException($"RecordingStartedCommand. Incorrect argument type {nameof(args)}");
            }

            try
            {
                var audioRecord = await AudioRecordRepository.GetRecordByName(eventArgs.RecordName);

                if (audioRecord != null)
                {
                    audioRecord.RecordingStartTime = eventArgs.EventTime;
                    await AudioRecordRepository.UpdateRecord(audioRecord);
                }
                else
                {
                    Logger.Warning($"RecordingStartedCommand. AudioRecord not found. RecordName: {eventArgs.RecordName}.");
                }
            }
            catch (Exception ex)
            {
                Logger.Warning("RecordingStartedCommand.Error.", ex);
            }
        }
Beispiel #8
0
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            var lineId = args.RouteData?.LineId;

            if (!lineId.HasValue)
            {
                Logger.Warning("SwitchRolesCommand. Не найден LineId.");
                throw new Exception("Не найден LineId");
            }

            var oldMainChannel = await ChannelRepository.GetChannelForMainUser(lineId.Value);

            if (oldMainChannel == null)
            {
                Logger.Warning("SwitchRolesCommand. Не найден канал главного в разговоре.");
                throw new Exception("Не найден канал главного в разговоре");
            }

            if (oldMainChannel.CallId != args.RouteData.FromCallId)
            {
                Logger.Warning($"SwitchRolesCommand. Пользователь звонка {args.RouteData.FromCallId} не является главным в разговоре. MainUserCallId: {oldMainChannel.CallId}");
                throw new Exception($"Пользователь звонка с Id {args.RouteData.FromCallId} не является главным в разговоре");
            }

            var assistantChannel = await ChannelRepository.GetChannelByCallId(args.RouteData.ToCallId);

            if (assistantChannel == null)
            {
                Logger.Warning($"SwitchRolesCommand. Канал с Id {args.RouteData.ToCallId} не найден.");
                throw new Exception($"Канал с Id {args.RouteData.ToCallId} не найден.");
            }

            await ChangeMainChannel(oldMainChannel, assistantChannel, lineId.Value, args);
        }
Beispiel #9
0
        /// <summary>
        /// Добавить snoop-копию канала во все бриджи ассистентов и в бридж для частичных ассистентов
        /// </summary>
        protected async Task SnoopChannelByAllAssistantsChannels(
            string channelId,
            string channelExtension,
            ChannelRoleType channelRole,
            Guid callId,
            StasisStartEventArgs args,
            string excludedChannelId = null)
        {
            if (args.RouteData.LineId.HasValue)
            {
                var channelsInLine = (await ChannelRepository.GetChannelsByLineId(args.RouteData.LineId.Value))
                                     .Where(t => excludedChannelId == null || t.ChannelId != excludedChannelId)
                                     .ToList();

                await SnoopChannelByAssistantChannels(channelId, channelExtension, channelRole, callId, channelsInLine, args);

                var partialAssistantChannels = channelsInLine.Where(t => t.Role == ChannelRoleType.PartialAssistant);
                foreach (var channel in partialAssistantChannels)
                {
                    await InitializeSnoopChannel(channelId, channelExtension, channelRole, callId, channel.BridgeId, args, SnoopBridgeType.Listen);

                    var speakChannel = channelsInLine.SingleOrDefault(t => t.OriginalChannelId == channel.ChannelId && t.Role == ChannelRoleType.SpeakSnoopChannel);
                    if (speakChannel != null)
                    {
                        await InitializeSnoopChannel(channelId, channelExtension, channelRole, callId, speakChannel.BridgeId, args, SnoopBridgeType.Speak);
                    }
                }
            }
        }
        /// <summary>
        /// Выполнить команду
        /// </summary>
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            if (!(args is IsolationStasisStartEventArgs model))
            {
                return;
            }

            var isolationData = model.IsolationStatusData;

            try
            {
                var isolationChannel = await ChannelRepository.GetChannelByCallId(isolationData.CallId);

                if (isolationData.Isolated)
                {
                    await AriClient.MuteChannel(isolationChannel.ChannelId);
                }
                else
                {
                    await AriClient.UnmuteChannel(isolationChannel.ChannelId);
                }
            }
            catch (Exception ex)
            {
                Logger.Warning(ex.Message);
                throw new Exception($"Не удалось установить параметр изоляции со значением {isolationData.Isolated}");
            }
        }
Beispiel #11
0
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel userChannel, StasisStartEventArgs args)
        {
            var routeData = args.RouteData;

            if (!routeData.FromCallId.HasValue)
            {
                Logger.Warning($"Id вызова пользователя не задан. ChannelId: {userChannel.Id}");
                return;
            }

            var userExtension        = routeData.FromExtension;
            var destinationExtension = routeData.ToExtension;
            var destinationChannelId = AriClient.CreateChannelId(ChannelRoleType.ExternalChannel, destinationExtension);

            var bridge = await AriClient.CreateBridge();

            await AriClient.AddChannelToBridge(bridge.Id, userChannel.Id);

            var playBackId = await AriClient.PlayBeeps(userChannel.Id);

            var destinationCallArgs = new StasisStartEventArgs
            {
                BridgeId   = bridge.Id,
                EventType  = StasisStartEventType.CallToDestination,
                RouteData  = routeData,
                PlaybackId = playBackId
            };

            var encodedArgs     = JsonSerializer.EncodeData(destinationCallArgs);
            var originateResult = await AriClient.Originate(encodedArgs, "Служба 112", destinationExtension, destinationChannelId);

            if (!originateResult)
            {
                throw new Exception("Ошибка создания канала для участника разговора, которому звонит пользователь.");
            }

            var userChannelEntity = new DAL.Entities.Channel
            {
                ChannelId = userChannel.Id,
                Extension = userExtension,
                CallId    = routeData.FromCallId.Value,
                BridgeId  = bridge.Id,
                Role      = ChannelRoleType.Conference,
                LineId    = routeData.LineId
            };
            await ChannelRepository.AddChannel(userChannelEntity);

            var destinationChannelEntity = new DAL.Entities.Channel
            {
                ChannelId = destinationChannelId,
                Extension = destinationExtension,
                CallId    = routeData.ToCallId,
                BridgeId  = bridge.Id,
                Role      = ChannelRoleType.RingingFromUser,
                LineId    = routeData.LineId
            };
            await ChannelRepository.AddChannel(destinationChannelEntity);
        }
        /// <summary>
        /// Принудительное удаление канала из звонка
        /// </summary>>
        public async Task ForceHangUp(RouteCallDto model)
        {
            var args = new StasisStartEventArgs
            {
                RouteData = model
            };

            await _commandFactory.GetCommand(StasisStartEventType.ForceHangUpCommand).Execute(null, args);
        }
        private StasisStartEventArgs CreateStasisArgs(string channelId, string bridgeId, StasisStartEventType eventType,
                                                      RouteCallDto dto)
        {
            var args = new StasisStartEventArgs
            {
                EventType = eventType,
                ChannelId = channelId,
                RouteData = dto,
                BridgeId  = bridgeId
            };

            return(args);
        }
        private async Task <Result> OriginateAsync(StasisStartEventArgs args, string fromExtension, string toExtension)
        {
            _logger.Debug($"AsteriskAriApiService.OriginateAsync. From: {fromExtension}, To: {toExtension}");
            var encodedArgs     = JsonSerializer.EncodeData(args);
            var originateResult = await _ariWebSocketService.OriginateChannel(encodedArgs, fromExtension, toExtension);

            if (!originateResult)
            {
                _logger.Warning("OriginateAsync. Error creating a new channel when answering a call.");
                return(Result.Failure(ErrorCodes.UnableToSaveChannel));
            }

            return(Result.Success());
        }
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel destinationChannel, StasisStartEventArgs args)
        {
            var routeData = args.RouteData;

            Logger.Information($"AcceptedCallFromUserCommand. DestinationChannelId: {destinationChannel.Id}, UserChannelId: {args.ChannelId}");

            try
            {
                var destinationExtension     = routeData.ToExtension;
                var destinationChannelEntity = await ChannelRepository.GetByChannelId(destinationChannel.Id);

                if (destinationChannelEntity == null)
                {
                    Logger.Warning($"Канал вызываемого участника не найден. ChannelId: {destinationChannel.Id}");
                    return;
                }

                var channelsInBridge = await ChannelRepository.GetByBridgeId(destinationChannelEntity.BridgeId);

                var userChannel = channelsInBridge.SingleOrDefault(x => x.Role == ChannelRoleType.Conference);
                if (userChannel == null)
                {
                    Logger.Warning($"Канал пользователя не найден. LineId: {routeData.LineId}");
                    return;
                }

                var callId = destinationChannelEntity.CallId;

                await StartCallRecording(userChannel.ChannelId, userChannel.CallId, userChannel.Extension, userChannel.Role, userChannel.BridgeId, routeData.LineId);
                await InitializeRecordingChannel(destinationChannel.Id, destinationExtension, destinationChannelEntity.Role, userChannel.BridgeId, callId, routeData.LineId);

                destinationChannelEntity.Role = ChannelRoleType.ExternalChannel;
                await ChannelRepository.UpdateChannel(destinationChannelEntity);

                await AriClient.StopBeeps(args.PlaybackId);

                await AriClient.AddChannelToBridge(userChannel.BridgeId, destinationChannel.Id);

                Logger.Information($"Участник разговора {destinationExtension} принял вызов от пользователя {userChannel.Extension}");
                await _queueSender.Publish(new AcceptCallFromUserIntegrationEvent
                {
                    CallId = callId
                });
            }
            catch (Exception ex)
            {
                Logger.Warning("AcceptedCallFromUserCommand Error", ex);
            }
        }
        /// <summary>
        /// Инициализировать прямой вызов от пользователя на номер <see cref="RouteCallDto.ToExtension"/>
        /// </summary>
        /// <remarks>
        /// При вызове Originate создается только канал для пользователя, который звонит на номер назначения.
        /// Канал для участника, которому звонит пользователь, будет создан после создания канала оператора при обработке события StasisStartEvent
        /// </remarks>
        public async Task <Result> CallFromUser(RouteCallDto routeDto)
        {
            var logMessage = $"Call from {routeDto.FromExtension} to {routeDto.ToExtension}. CallId: {routeDto.ToCallId} LineId: {routeDto.LineId}";

            _logger.Information($"CallFromUser. {logMessage}");

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.CallFromUser,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, "Служба 112", args.RouteData.FromExtension);

            return(originateResult);
        }
Beispiel #17
0
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel userChannel, StasisStartEventArgs args)
        {
            Logger.Information($"AcceptIncomingCallCommand. UserChannelId: {userChannel.Id}, IncomingChannelId: {args.ChannelId}");

            try
            {
                var incomingCallChannel = await ChannelRepository.GetByChannelId(args.ChannelId);

                if (incomingCallChannel == null)
                {
                    Logger.Warning($"Канал входящего вызова не найден. UserChannelId: {userChannel.Id}");
                    return;
                }

                var routeData = args.RouteData;
                var lineId    = routeData.LineId;

                await InitializeRecordingChannel(userChannel.Id, routeData.ToExtension, ChannelRoleType.Conference, incomingCallChannel.BridgeId, routeData.ToCallId, lineId);

                await AriClient.UnholdAsync(incomingCallChannel.ChannelId);

                await AriClient.StopMohInBridgeAsync(incomingCallChannel.BridgeId);

                await AriClient.AddChannelToBridge(incomingCallChannel.BridgeId, userChannel.Id);

                incomingCallChannel.Interrupted = false;
                incomingCallChannel.LineId      = lineId;
                await ChannelRepository.UpdateChannel(incomingCallChannel);

                await UpdateAudioRecords(incomingCallChannel.BridgeId, incomingCallChannel.CallId, lineId);

                var userChannelEntity = new DAL.Entities.Channel
                {
                    ChannelId = userChannel.Id,
                    BridgeId  = incomingCallChannel.BridgeId,
                    CallId    = routeData.ToCallId,
                    Extension = routeData.ToExtension,
                    Role      = ChannelRoleType.Conference,
                    LineId    = lineId
                };
                await ChannelRepository.AddChannel(userChannelEntity);
            }
            catch (Exception ex)
            {
                Logger.Warning("AcceptIncomingCallCommand Error", ex);
            }
        }
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            Logger.Information($"DeleteChannel. Id: {channel.Id}");

            var channelEntity = await ChannelRepository.GetByChannelId(channel.Id);

            if (channelEntity == null)
            {
                Logger.Warning($"Канал не найден или был удален ранее. ChannelId: {channel.Id}");
                return;
            }

            await NotifyIfIncomingCallEnded(channelEntity);

            await DeleteChannel(channelEntity);
            await DestroyBridge(channelEntity.BridgeId);
        }
Beispiel #19
0
        /// <summary>
        /// Создать snoop-копию канала для записи
        /// </summary>
        /// <param name="channelId">Идентификатор исходного канала</param>
        /// <param name="extension">Номер</param>
        /// <param name="role">Роль канала</param>
        /// <param name="forCommonRecord">Признак того, что копия канала создана для записи разговора всех участников в один файл</param>
        /// <param name="callId">Идентификатор звонка</param>
        /// <param name="lineId">Идентификатор линии</param>
        /// <returns>SnoopChannelId</returns>
        private async Task <Result <string> > CreateSnoopChannelForRecording(
            string channelId,
            string extension,
            ChannelRoleType role,
            bool forCommonRecord,
            Guid callId,
            Guid?lineId)
        {
            if (!_asteriskOptions.RecordingEnabled)
            {
                return(Result.Failure(ErrorCodes.RecordingError));
            }

            var routeData = new RouteCallDto
            {
                ToCallId = callId,
                LineId   = lineId
            };

            var snoopChannelId = GetSnoopChannelIdForRecord(role, extension);
            var snoopArgs      = new StasisStartEventArgs
            {
                EventType         = StasisStartEventType.IgnoreStasisEvent,
                ChannelId         = snoopChannelId,
                OriginalChannelId = channelId,
                RouteData         = routeData
            };

            var encodedArgs = JsonSerializer.EncodeData(snoopArgs);
            await AriClient.SnoopChannel(channelId, "in", "none", encodedArgs, snoopChannelId);

            if (forCommonRecord)
            {
                return(Result.Success(snoopChannelId));
            }

            var recordingResult = await StartRecordingChannel(snoopChannelId, callId, lineId);

            if (recordingResult.IsFailure)
            {
                Logger.Information($"CreateSnoopChannelForRecording. StartRecordingChannelError: {recordingResult.ErrorMessage}");
                return(Result.Failure(ErrorCodes.RecordingError));
            }

            return(Result.Success(snoopChannelId));
        }
        /// <summary>
        /// Поменяться ролями между главным в разговоре и ассистентом
        /// </summary>
        public async Task <Result> SwitchMainUser(RouteCallDto routeDto)
        {
            try
            {
                var args = new StasisStartEventArgs
                {
                    RouteData = routeDto
                };

                await _commandFactory.GetCommand(StasisStartEventType.SwitchRolesCommand).Execute(null, args);

                return(Result.Success());
            }
            catch (Exception e)
            {
                _logger.Warning(e.Message);
                return(Result.Failure(ErrorCodes.UnableToSwitchMainUser));
            }
        }
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            Logger.Information($"AddToSnoopBridge. Bridge: {args.BridgeId}. Channel: {args.ChannelId}");

            await AriClient.AddChannelToBridge(args.BridgeId, args.ChannelId);

            var channelEntity = new DAL.Entities.Channel
            {
                ChannelId         = args.ChannelId,
                BridgeId          = args.BridgeId,
                Role              = args.EventType == StasisStartEventType.AddToSpeakSnoopBridge ? ChannelRoleType.SpeakSnoopChannel : ChannelRoleType.SnoopChannel,
                LineId            = args.RouteData.LineId,
                CallId            = args.RouteData.ToCallId,
                OriginalChannelId = args.OriginalChannelId,
                Extension         = args.RouteData.ToExtension
            };

            await ChannelRepository.AddChannel(channelEntity);
        }
        private async Task <Result> AddAssistantSpecificType(RouteCallDto routeDto, StasisStartEventType eventType)
        {
            _logger.WithTag("to_call_id", routeDto.ToCallId)
            .WithTag("from_call_id", routeDto.FromCallId)
            .WithTag("assistant_extension", routeDto.ToExtension)
            .Information($"Add {eventType}. FromCallId: {routeDto.FromCallId}. Assistant: {routeDto.ToExtension}. CallId: {routeDto.ToCallId}");

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning($"Add{eventType}. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            if (!routeDto.FromCallId.HasValue)
            {
                _logger.Warning($"Add{eventType}. FromCallId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            var setMainChannelResult = await SetMainUser(routeDto.LineId.Value, routeDto.FromCallId.Value);

            if (setMainChannelResult.IsFailure)
            {
                _logger.Warning($"Add{eventType}. {setMainChannelResult.ErrorMessage}");
                return(Result.Failure(setMainChannelResult.ErrorCode));
            }

            var fromCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);

            var args = new StasisStartEventArgs
            {
                EventType = eventType,
                BridgeId  = setMainChannelResult.Value.BridgeId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, fromCallChannel.Extension, args.RouteData.ToExtension);

            return(originateResult);
        }
Beispiel #23
0
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            var channelId = channel.Id;

            Logger.Information($"RejectedCallFromUserCommand. DestinationChannelId: {channel.Id}");

            try
            {
                var destinationChannel = await ChannelRepository.GetByChannelId(channelId);

                if (destinationChannel == null || destinationChannel.Role != ChannelRoleType.RingingFromUser)
                {
                    Logger.Debug($"RejectedCallFromUserCommand. Канал участника уничтожен. CallId: {destinationChannel?.CallId}. {destinationChannel?.Role}");
                    return;
                }

                await ChannelRepository.DeleteChannel(destinationChannel.ChannelId);

                var channelsInBridge = await ChannelRepository.GetByBridgeId(destinationChannel.BridgeId);

                var userChannel = channelsInBridge.SingleOrDefault(x => x.Role == ChannelRoleType.Conference);
                if (userChannel == null)
                {
                    Logger.Warning("RejectedCallFromUserCommand. Канал пользователя не найден.");
                    return;
                }

                await AriClient.HangupChannel(userChannel.ChannelId);

                Logger.Information($"Отправка информации о том, что участник не принял или отклонил вызов от пользователя. Destination: {destinationChannel.Extension}");
                await _queueSender.Publish(new RejectCallIntegrationEvent
                {
                    CallId = destinationChannel.CallId
                });
            }
            catch (Exception ex)
            {
                Logger.Warning("RejectedCallFromUserCommand Error", ex);
            }
        }
Beispiel #24
0
        /// <inheritdoc />
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            var routeData = args.RouteData;

            if (!routeData.LineId.HasValue)
            {
                return;
            }

            await AriClient.Answer(channel.Id);

            await InitializeRecordingChannel(channel.Id, routeData.ToExtension, ChannelRoleType.Conference, args.BridgeId, routeData.ToCallId, routeData.LineId);

            var bridge = await AriClient.GetBridge(args.BridgeId);

            await AriClient.AddChannelToBridge(bridge.Id, channel.Id);

            await SnoopChannelByAllAssistantsChannels(channel.Id, routeData.ToExtension, ChannelRoleType.Conference, routeData.ToCallId, args);

            Logger.Information($"Channel added to call in conference mode. ChannelId: {channel.Id}. CallId: {routeData.ToCallId}");

            var channelForIncomingCall = await ChannelRepository.GetChannelForIncomingCall(routeData.LineId.Value);

            if (channelForIncomingCall != null && channelForIncomingCall.Interrupted)
            {
                channelForIncomingCall.Interrupted = false;
                await ChannelRepository.UpdateChannel(channelForIncomingCall);
            }

            var channelEntity = new DAL.Entities.Channel
            {
                ChannelId = channel.Id,
                BridgeId  = args.BridgeId,
                CallId    = routeData.ToCallId,
                Extension = routeData.ToExtension,
                Role      = ChannelRoleType.Conference,
                LineId    = routeData.LineId
            };
            await ChannelRepository.AddChannel(channelEntity);
        }
Beispiel #25
0
        /// <summary>
        /// Выполнить команду
        /// </summary>
        protected override async Task InternalExecute(Channel channel, StasisStartEventArgs args)
        {
            var routeData = args.RouteData;

            if (routeData.FromCallId.HasValue)
            {
                var incomingCallChannel = await ChannelRepository.GetChannelByCallId(routeData.FromCallId.Value);

                if (incomingCallChannel != null)
                {
                    incomingCallChannel.Interrupted = true;
                    await ChannelRepository.UpdateChannel(incomingCallChannel);
                }
            }

            var channelForDelete = await ChannelRepository.GetChannelByCallId(routeData.ToCallId);

            if (channelForDelete != null)
            {
                await AriClient.HangupChannel(channelForDelete.ChannelId);
            }
        }
        /// <summary>
        /// Добавить участника в разговор в режиме конференции
        /// </summary>
        public async Task <Result> AddToConference(RouteCallDto routeDto)
        {
            _logger.Information($"Add {routeDto.ToExtension} in conference mode. CallId: {routeDto.ToCallId}, LineId: {routeDto.LineId}");

            if (!routeDto.LineId.HasValue)
            {
                _logger.Warning("AddToConference. LineId not found.");
                return(Result.Failure(ErrorCodes.ValidationError));
            }

            var lineId   = routeDto.LineId.Value;
            var bridgeId = await _channelRepository.GetMainBridgeId(lineId);

            if (bridgeId == null)
            {
                _logger.Warning($"AddToConference. Main Bridge not found. LineId: {lineId}");
                return(Result.Failure(ErrorCodes.BridgeNotFound));
            }

            Channel fromCallChannel = null;

            if (routeDto.FromCallId.HasValue)
            {
                fromCallChannel = await _channelRepository.GetChannelByCallId(routeDto.FromCallId.Value);
            }

            var args = new StasisStartEventArgs
            {
                EventType = StasisStartEventType.Conference,
                BridgeId  = bridgeId,
                RouteData = routeDto
            };

            var originateResult = await OriginateAsync(args, fromCallChannel?.Extension, args.RouteData.ToExtension);

            return(originateResult);
        }
Beispiel #27
0
        /// <summary>
        /// Добавить snoop-копию канала во все бриджи ассистентов
        /// </summary>
        protected async Task SnoopChannelByAssistantChannels(
            string agentChannelId,
            string agentExtension,
            ChannelRoleType agentRole,
            Guid agentCallId,
            IList <DAL.Entities.Channel> channelsInLine,
            StasisStartEventArgs args)
        {
            var assistanceChannels = channelsInLine.Where(t => t.Role == ChannelRoleType.Assistant);

            foreach (var channel in assistanceChannels)
            {
                await InitializeSnoopChannel(agentChannelId, agentExtension, agentRole, agentCallId, channel.BridgeId, args, SnoopBridgeType.Listen);

                if (NeedAddChannelToSpeakBridge(agentRole, ChannelRoleType.Assistant))
                {
                    var speakChannel = channelsInLine.SingleOrDefault(t => t.OriginalChannelId == channel.ChannelId && t.Role == ChannelRoleType.SpeakSnoopChannel);
                    if (speakChannel != null)
                    {
                        await InitializeSnoopChannel(agentChannelId, agentExtension, agentRole, agentCallId, speakChannel.BridgeId, args, SnoopBridgeType.Speak);
                    }
                }
            }
        }
Beispiel #28
0
        private async Task ChangeMainChannel(DAL.Entities.Channel oldMainChannel, DAL.Entities.Channel assistantChannel, Guid lineId, StasisStartEventArgs args)
        {
            var channelsInLine = await ChannelRepository.GetChannelsByLineId(lineId);

            var assistantRole           = assistantChannel.Role;
            var assistantBridgeId       = assistantChannel.BridgeId;
            var mainBridgeId            = oldMainChannel.BridgeId;
            var newMainChannelId        = assistantChannel.ChannelId;
            var newMainChannelExtension = assistantChannel.Extension;

            await AriClient.AddChannelToBridge(mainBridgeId, newMainChannelId);

            await AriClient.AddChannelToBridge(assistantBridgeId, oldMainChannel.ChannelId);

            var assistantSpeakChannel = channelsInLine.SingleOrDefault(t => t.OriginalChannelId == assistantChannel.ChannelId && t.Role == ChannelRoleType.SpeakSnoopChannel);

            if (assistantSpeakChannel != null)
            {
                await InitializeSnoopChannel(oldMainChannel.ChannelId, oldMainChannel.Extension, assistantRole, oldMainChannel.CallId,
                                             assistantSpeakChannel.BridgeId, args, SnoopBridgeType.Speak, true);
            }

            await SnoopChannelByAllAssistantsChannels(newMainChannelId, newMainChannelExtension, ChannelRoleType.MainUser, assistantChannel.CallId, args);

            if (assistantRole == ChannelRoleType.PartialAssistant)
            {
                await SnoopChannelByAllAssistantsChannels(oldMainChannel.ChannelId, oldMainChannel.Extension, assistantRole, oldMainChannel.CallId, args, assistantChannel.ChannelId);
            }

            oldMainChannel.Role       = assistantRole;
            oldMainChannel.BridgeId   = assistantBridgeId;
            assistantChannel.Role     = ChannelRoleType.MainUser;
            assistantChannel.BridgeId = mainBridgeId;
            await ChannelRepository.UpdateChannel(oldMainChannel);

            await ChannelRepository.UpdateChannel(assistantChannel);

            await HangUpOldSnoopChannels(oldMainChannel.ChannelId, channelsInLine);
            await HangUpOldSnoopChannels(newMainChannelId, channelsInLine);
        }
Beispiel #29
0
 /// <summary>
 /// Реализация команды
 /// </summary>
 protected abstract Task InternalExecute(Channel channel, StasisStartEventArgs args);
Beispiel #30
0
        /// <summary>
        /// Создать новую пару бриджей (LISTEN/SPEAK) для ассистента/частичного ассистента и добавить туда каналы для прослушивания/разговора
        /// </summary>
        protected async Task <DAL.Entities.Channel> CreateNewAssistantBridgesAndSnoop(Channel assistantChannel,
                                                                                      StasisStartEventArgs args, ChannelRoleType assistantRole)
        {
            var lineId = args.RouteData?.LineId;

            if (!lineId.HasValue)
            {
                Logger.Warning($"CallTo{assistantRole}. LineId не найден AssistantChannelId: {assistantChannel.Id}.");
                return(null);
            }

            var mainChannel = await ChannelRepository.GetChannelForMainUser(lineId.Value);

            if (mainChannel == null)
            {
                Logger.Warning($"CallTo{assistantRole}. MainChannel не найден.");
                return(null);
            }

            var assistantExtension = args.RouteData.ToExtension;
            var assistantCallId    = args.RouteData.ToCallId;
            var prefix             = assistantRole == ChannelRoleType.PartialAssistant ? "PASSISTANT" : "ASSISTANT";
            var assistantBridgeId  = $"{prefix}_{assistantExtension}_{assistantChannel.Id}";
            var speakBridgeId      = $"{assistantBridgeId}_SPEAK";
            var listenBridgeId     = $"{assistantBridgeId}_LISTEN";

            await InitializeRecordingChannel(assistantChannel.Id, args.RouteData.ToExtension, assistantRole, mainChannel.BridgeId, assistantCallId, lineId.Value);

            await AriClient.CreateBridge(speakBridgeId);

            await AriClient.CreateBridge(listenBridgeId);

            await AriClient.AddChannelToBridge(listenBridgeId, assistantChannel.Id);

            await InitializeSnoopChannel(assistantChannel.Id, assistantExtension, assistantRole, assistantCallId, speakBridgeId, args, SnoopBridgeType.Speak, true);

            var channelsInLine = await ChannelRepository.GetChannelsByLineId(lineId.Value);

            var channelsInMainBridge     = channelsInLine.Where(t => t.BridgeId == mainChannel.BridgeId).ToList();
            var partialAssistantChannels = channelsInLine.Where(t => t.Role == ChannelRoleType.PartialAssistant).ToList();

            foreach (var channel in channelsInMainBridge)
            {
                await InitializeSnoopChannel(channel.ChannelId, channel.Extension, channel.Role, channel.CallId, listenBridgeId, args, SnoopBridgeType.Listen);

                if (NeedAddChannelToSpeakBridge(channel.Role, assistantRole))
                {
                    await InitializeSnoopChannel(channel.ChannelId, channel.Extension, channel.Role, channel.CallId, speakBridgeId, args, SnoopBridgeType.Speak);
                }
            }

            foreach (var channel in partialAssistantChannels)
            {
                await InitializeSnoopChannel(channel.ChannelId, channel.Extension, channel.Role, channel.CallId, listenBridgeId, args, SnoopBridgeType.Listen);

                if (assistantRole == ChannelRoleType.PartialAssistant)
                {
                    await InitializeSnoopChannel(channel.ChannelId, channel.Extension, channel.Role, channel.CallId, speakBridgeId, args, SnoopBridgeType.Speak);
                }
            }

            if (assistantRole == ChannelRoleType.PartialAssistant)
            {
                await SnoopChannelByAllAssistantsChannels(assistantChannel.Id, assistantExtension, assistantRole, assistantCallId, args);
            }

            var assistantChannelEntity = new DAL.Entities.Channel
            {
                ChannelId = assistantChannel.Id,
                Extension = assistantExtension,
                CallId    = assistantCallId,
                BridgeId  = listenBridgeId,
                Role      = assistantRole,
                LineId    = lineId.Value
            };
            await ChannelRepository.AddChannel(assistantChannelEntity);

            return(assistantChannelEntity);
        }