/// <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); }
/// <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}\""); }
/// <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); }
/// <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); } }
/// <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); }
/// <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}"); } }
/// <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); }
/// <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); }
/// <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); }
/// <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); } }
/// <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); }
/// <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); }
/// <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); } } } }
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); }
/// <summary> /// Реализация команды /// </summary> protected abstract Task InternalExecute(Channel channel, StasisStartEventArgs args);
/// <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); }