public async Task Stopping_the_listener_does_not_dispose_any_connected_clients() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool disposed = false; listener.Connections.Subscribe((socket) => { connected = true; socket.Disposed += (o, e) => disposed = true; }); var _ = new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => connected); listener.Stop(); Assert.False(disposed); listener.Dispose(); Assert.True(disposed); } }
public async Task Calling_Connect_on_a_new_OutboundSocket_should_populate_the_ChannelData() { using (var listener = new OutboundListener(0)) { listener.Start(); ChannelEvent channelData = null; listener.Connections.Subscribe( async(socket) => { channelData = await socket.Connect(); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); await Wait.Until(() => channelData != null); Assert.NotNull(channelData); Assert.Equal(ChannelState.Execute, channelData.ChannelState); Assert.Equal("RINGING", channelData.Headers["Channel-Call-State"]); } } }
public async Task When_FreeSwitch_disconnects_it_completes_the_message_observables() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool disposed = true; bool messagesObservableCompleted = false; bool eventsObservableCompleted = false; listener.Connections.Subscribe(connection => { connected = true; connection.Messages.Subscribe(_ => { }, () => messagesObservableCompleted = true); connection.Events.Subscribe(_ => { }, () => eventsObservableCompleted = true); connection.Disposed += (o, e) => disposed = true; }); using (var client = new FakeFreeSwitchSocket(listener.Port)) { await Wait.Until(() => connected); client.Dispose(); await Wait.Until(() => messagesObservableCompleted); await Wait.Until(() => eventsObservableCompleted); Assert.True(connected, "Expect a connection to have been made."); Assert.True(disposed, "Expect the socket to have been disposed."); Assert.True(messagesObservableCompleted, "Expect the BasicMessage observable to be completed"); Assert.True(eventsObservableCompleted, "Expect the EventMessage observable to be completed"); } } }
public async Task Calling_Exit_on_a_disconnected_OutboundSocket_should_close_gracefully() { using (var listener = new OutboundListener(0)) { listener.Start(); EventMessage channelData = null; bool exited = false; listener.Connections.Subscribe( async(socket) => { channelData = await socket.Connect(); await socket.Exit(); exited = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => { await freeSwitch.SendChannelDataEvent(); await Task.Delay(500); freeSwitch.Dispose(); }); await Wait.Until(() => channelData != null); await Wait.Until(() => exited); Assert.True(exited); } } }
public async Task IsStarted_is_false_when_initialized() { using (var listener = new OutboundListener(0)) { Assert.False(listener.IsStarted); } }
public async Task Can_restart_the_listener_after_stopping() { using (var listener = new OutboundListener(0)) { listener.Start(); int counter = 0; listener.Connections.Subscribe((socket) => { counter++; }); new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => counter == 1); listener.Stop(); //not listening Assert.Throws <SocketException>(() => new FakeFreeSwitchSocket(listener.Port)); listener.Start(); new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => counter == 2); } }
public async Task IsStarted_is_true_when_started() { using (var listener = new OutboundListener(0)) { listener.Start(); Assert.True(listener.IsStarted); } }
public async Task Starting_should_be_idempotent() { using (var listener = new OutboundListener(0)) { listener.Start(); listener.Start(); Assert.True(listener.IsStarted); } }
public async Task IsStarted_is_false_when_disposed() { using (var listener = new OutboundListener(0)) { listener.Start(); listener.Dispose(); await Wait.Until(() => listener.IsStarted == false); } }
public void Disposing_the_listener_completes_the_connections_observable() { using (var listener = new OutboundListener(0)) { listener.Start(); bool completed = false; listener.Connections.Subscribe(_ => { }, () => completed = true); listener.Dispose(); Assert.True(completed); } }
public void Disposing_the_listener_completes_the_connections_observable() { using (var listener = new OutboundListener(0)) { listener.Start(); bool completed = false; listener.Connections.Subscribe(_ => { }, () => completed = true); listener.Dispose(); Assert.True(completed); } }
public async Task a_new_connection_produces_an_outbound_socket() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; listener.Connections.Subscribe((socket) => connected = true); var client = new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => connected); Assert.True(connected); } }
static void Main(string[] args) { using (var listener = new OutboundListener(8084)) { listener.Connections.Subscribe( async socket => { await socket.Connect(); //after calling .Connect(), socket.ChannelData //is populated with all the headers and variables of the channel var uuid = socket.ChannelData.Headers[HeaderNames.UniqueId]; Console.WriteLine("OutboundSocket connected for channel " + uuid); await socket.SubscribeEvents(EventName.ChannelHangup); socket.ChannelEvents .Where(x => x.EventName == EventName.ChannelHangup && x.UUID == uuid) .Take(1) .Subscribe(async x => { Console.WriteLine("Hangup Detected on " + x.UUID); await socket.Exit(); }); //if we use 'full' in our FS dialplan, we'll get events for ALL channels in FreeSwitch //this is not desirable here - so we'll filter in for our unique id only //cases where this is desirable is in the channel api where we want to catch other channels bridging to us await socket.Filter(HeaderNames.UniqueId, uuid); //tell FreeSwitch not to end the socket on hangup, we'll catch the hangup event and .Exit() ourselves await socket.Linger(); await socket.ExecuteApplication(uuid, "answer"); await socket.Play(uuid, "https://s3-ap-southeast-2.amazonaws.com/talkingtech-voip/Greeting.wav"); await socket.Hangup(uuid, HangupCause.NormalClearing); }); listener.Start(); Console.WriteLine("Press [Enter] to exit."); Console.ReadLine(); } }
public async Task a_new_connection_produces_an_outbound_socket() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; listener.Connections.Subscribe((socket) => connected = true); var client = new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => connected); Assert.True(connected); } }
public async Task can_send_multple_commands() { using (var listener = new OutboundListener(0)) { listener.Start(); bool commandRequestReceived = false; CommandReply commandReply = null; listener.Connections.Subscribe( async(socket) => { await socket.Connect(); commandReply = await socket.Linger(); commandReply = await socket.NoLinger(); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("linger")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyOk(); }); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("nolinger")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyError("FAILED"); commandRequestReceived = true; }); await Wait.Until(() => commandRequestReceived); Assert.True(commandRequestReceived); Assert.NotNull(commandReply); Assert.False(commandReply.Success); } } }
public async Task Channel_connect_errors_should_not_cause_subsequent_connections_to_fail() { using (var listener = new OutboundListener(0)) { listener.Start(); bool channelCallbackCalled = false; bool firstConnectionReceived = false; bool secondConnectionReceived = false; listener.Channels.Subscribe(channel => { channelCallbackCalled = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => { freeSwitch.Dispose(); firstConnectionReceived = true; }); await Wait.Until(() => firstConnectionReceived); Assert.False(channelCallbackCalled); } using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(async _ => { await freeSwitch.SendChannelDataEvent(); secondConnectionReceived = true; }); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("linger") || m.StartsWith("event") || m.StartsWith("filter")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyOk("sending OK for linger, event and filter commands"); }); await Wait.Until(() => secondConnectionReceived); Assert.True(channelCallbackCalled); } } }
public async Task Calling_Connect_on_a_OutboundSocket_that_was_disconnected_should_throw_OperationCanceledException() { using (var listener = new OutboundListener(0)) { listener.Start(); Exception ex = null; listener.Connections.Subscribe((socket) => ex = Record.Exception(() => socket.Connect().Wait())); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => freeSwitch.Dispose()); await Wait.Until(() => ex != null); Assert.IsType <TaskCanceledException>(ex.InnerException); } } }
private static void OutboundSocketTest() { var listener = new OutboundListener(8084); listener.Connections.Subscribe( async connection => { await connection.Connect(); Console.WriteLine("New Socket connected"); connection.Events.Where(x => x.EventName == EventName.ChannelHangup).Take(1).Subscribe( e => { ColorConsole.WriteLine("Hangup Detected on A-Leg ".Red(), e.Headers[HeaderNames.CallerUniqueId], " ", e.Headers[HeaderNames.HangupCause]); connection.Exit(); }); var uuid = connection.ChannelData.Headers[HeaderNames.UniqueId]; await connection.SubscribeEvents( EventName.Dtmf); await connection.Linger(); await connection.ExecuteApplication(uuid, "answer", null, true, false); var result = await connection.Play( uuid, "$${base_dir}/sounds/en/us/callie/misc/8000/misc-freeswitch_is_state_of_the_art.wav"); //await connection.ExecuteAppAsync(uuid, "conference", "test+1234"); //if (result.ChannelData.AnswerState != AnswerState.Hangup) await connection.Hangup(uuid, "NORMAL_CLEARING"); }); listener.Start(); }
public Task Run(CancellationToken cancellationToken) { listener = new OutboundListener(8084); listener.Connections.Subscribe( async connection => { await connection.Connect(); Console.WriteLine("New Socket connected"); connection.ChannelEvents.Where(x => x.UUID == connection.ChannelData.UUID && x.EventName == EventName.ChannelHangup) .Take(1) .Subscribe( e => { ColorConsole.WriteLine( "Hangup Detected on A-Leg ".Red(), e.Headers[HeaderNames.CallerUniqueId], " ", e.Headers[HeaderNames.HangupCause]); connection.Exit(); }); var uuid = connection.ChannelData.Headers[HeaderNames.UniqueId]; await connection.SubscribeEvents(EventName.Dtmf, EventName.ChannelHangup); await connection.Linger(); await connection.ExecuteApplication(uuid, "answer", null, true, false); var result = await connection.Play(uuid, "$${base_dir}/sounds/en/us/callie/misc/8000/misc-freeswitch_is_state_of_the_art.wav"); }); listener.Start(); Console.WriteLine("Listener started on 8084. Press [Enter] to exit"); Console.ReadLine(); return(Task.FromResult(0)); }
public async Task Disposing_the_listener_completes_the_message_observables() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool messagesObservableCompleted = false; bool eventsObservableCompleted = false; bool channelDataReceived = false; listener.Connections.Subscribe(async(connection) => { connected = true; connection.Messages.Subscribe(_ => { }, () => messagesObservableCompleted = true); connection.Events.Subscribe(_ => { }, () => eventsObservableCompleted = true); await connection.Connect(); channelDataReceived = connection.ChannelData != null; Assert.True(channelDataReceived); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); await Wait.Until(() => channelDataReceived); listener.Dispose(); // will dispose the socket await Wait.Until(() => messagesObservableCompleted); await Wait.Until(() => eventsObservableCompleted); Assert.True(connected, "Expect a connection to have been made."); Assert.True(messagesObservableCompleted, "Expect the BasicMessage observable to be completed"); Assert.True(eventsObservableCompleted, "Expect the EventMessage observable to be completed"); } } }
public async Task each_new_connection_produces_a_new_outbound_socket_from_the_Connections_observable() { const int NumberOfConnections = 3; using (var listener = new OutboundListener(0)) { listener.Start(); var connected = 0; listener.Connections.Subscribe((socket) => connected++); for (int i = 0; i < NumberOfConnections; i++) { var client = new FakeFreeSwitchSocket(listener.Port); } await Wait.Until(() => connected == NumberOfConnections); Assert.Equal(NumberOfConnections, connected); } }
public async Task can_send_api() { using (var listener = new OutboundListener(0)) { listener.Start(); bool apiRequestReceived = false; ApiResponse apiResponse = null; listener.Connections.Subscribe( async(socket) => { await socket.Connect(); apiResponse = await socket.SendApi("status"); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("api")).Subscribe( async _ => { apiRequestReceived = true; await freeSwitch.SendApiResponseOk(); }); await Wait.Until(() => apiRequestReceived); await Wait.Until(() => apiResponse != null); Assert.True(apiRequestReceived); Assert.NotNull(apiResponse); Assert.True(apiResponse.Success); } } }
public async Task Disposing_the_listener_completes_the_message_observables() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool messagesObservableCompleted = false; bool eventsObservableCompleted = false; bool channelDataReceived = false; listener.Connections.Subscribe(async (connection) => { connected = true; connection.Messages.Subscribe(_ => { }, () => messagesObservableCompleted = true); connection.Events.Subscribe(_ => { }, () => eventsObservableCompleted = true); await connection.Connect(); channelDataReceived = connection.ChannelData != null; Assert.True(channelDataReceived); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); await Wait.Until(() => channelDataReceived); listener.Dispose(); // will dispose the socket await Wait.Until(() => messagesObservableCompleted); await Wait.Until(() => eventsObservableCompleted); Assert.True(connected, "Expect a connection to have been made."); Assert.True(messagesObservableCompleted, "Expect the BasicMessage observable to be completed"); Assert.True(eventsObservableCompleted, "Expect the EventMessage observable to be completed"); } } }
public async Task Disposing_the_listener_disposes_any_connected_clients() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool disposed = false; listener.Connections.Subscribe((socket) => { connected = true; socket.Disposed += (o, e) => disposed = true; }); var client = new FakeFreeSwitchSocket(listener.Port); await Wait.Until(() => connected); listener.Dispose(); Assert.True(disposed); } }
public async Task When_FreeSwitch_disconnects_it_completes_the_message_observables() { using (var listener = new OutboundListener(0)) { listener.Start(); bool connected = false; bool disposed = true; bool messagesObservableCompleted = false; bool eventsObservableCompleted = false; listener.Connections.Subscribe(connection => { connected = true; connection.Messages.Subscribe(_ => { }, () => messagesObservableCompleted = true); connection.Events.Subscribe(_ => { }, () => eventsObservableCompleted = true); connection.Disposed += (o, e) => disposed = true; }); using (var client = new FakeFreeSwitchSocket(listener.Port)) { await Wait.Until(() => connected); client.Dispose(); await Wait.Until(() => messagesObservableCompleted); await Wait.Until(() => eventsObservableCompleted); Assert.True(connected, "Expect a connection to have been made."); Assert.True(disposed, "Expect the socket to have been disposed."); Assert.True(messagesObservableCompleted, "Expect the BasicMessage observable to be completed"); Assert.True(eventsObservableCompleted, "Expect the EventMessage observable to be completed"); } } }
public async Task Channel_listener_should_handle_where_FS_disconnects_before_channelData_event_received() { using (var listener = new OutboundListener(0)) { listener.Start(); bool channelCallbackCalled = false; bool firstConnectionReceived = false; listener.Channels.Subscribe(channel => { channelCallbackCalled = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => { firstConnectionReceived = true; freeSwitch.Dispose(); }); await Wait.Until(() => firstConnectionReceived); Assert.False(channelCallbackCalled); } } }
public async Task Calling_Exit_on_a_disconnected_OutboundSocket_should_close_gracefully() { using (var listener = new OutboundListener(0)) { listener.Start(); EventMessage channelData = null; bool exited = false; listener.Connections.Subscribe( async (socket) => { channelData = await socket.Connect(); await socket.Exit(); exited = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => { await freeSwitch.SendChannelDataEvent(); await Task.Delay(500); freeSwitch.Dispose(); }); await Wait.Until(() => channelData != null); await Wait.Until(() => exited); Assert.True(exited); } } }
public async Task Calling_Connect_on_a_OutboundSocket_that_was_disconnected_should_throw_OperationCanceledException() { using (var listener = new OutboundListener(0)) { listener.Start(); Exception ex = null; listener.Connections.Subscribe((socket) => ex = Record.Exception(() => socket.Connect().Wait())); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => freeSwitch.Dispose()); await Wait.Until(() => ex != null); Assert.IsType<TaskCanceledException>(ex.InnerException); } } }
public async Task Channel_listener_should_handle_where_FS_disconnects_before_channelData_event_received() { using (var listener = new OutboundListener(0)) { listener.Start(); bool channelCallbackCalled = false; bool firstConnectionReceived = false; listener.Channels.Subscribe(channel => { channelCallbackCalled = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => { firstConnectionReceived = true; freeSwitch.Dispose(); }); await Wait.Until(() => firstConnectionReceived); Assert.False(channelCallbackCalled); } } }
public async Task can_send_api() { using (var listener = new OutboundListener(0)) { listener.Start(); bool apiRequestReceived = false; ApiResponse apiResponse = null; listener.Connections.Subscribe( async (socket) => { await socket.Connect(); apiResponse = await socket.SendApi("status"); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("api")).Subscribe( async _ => { apiRequestReceived = true; await freeSwitch.SendApiResponseOk(); }); await Wait.Until(() => apiRequestReceived); Assert.True(apiRequestReceived); Assert.NotNull(apiResponse); Assert.True(apiResponse.Success); } } }
public async Task Channel_connect_errors_should_not_cause_subsequent_connections_to_fail() { using (var listener = new OutboundListener(0)) { listener.Start(); bool channelCallbackCalled = false; bool firstConnectionReceived = false; bool secondConnectionReceived = false; listener.Channels.Subscribe(channel => { channelCallbackCalled = true; }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(_ => { freeSwitch.Dispose(); firstConnectionReceived = true; }); await Wait.Until(() => firstConnectionReceived); Assert.False(channelCallbackCalled); } using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")).Subscribe(async _ => { await freeSwitch.SendChannelDataEvent(); secondConnectionReceived = true; }); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("linger") || m.StartsWith("event") || m.StartsWith("filter")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyOk("sending OK for linger, event and filter commands"); }); await Wait.Until(() => secondConnectionReceived); Assert.True(channelCallbackCalled); } } }
private static void OutboundSocketTest() { var listener = new OutboundListener(8084); listener.Connections.Subscribe( async connection => { await connection.Connect(); Console.WriteLine("New Socket connected"); connection.Events.Where(x => x.EventName == EventName.ChannelHangup).Take(1).Subscribe( e => { ColorConsole.WriteLine("Hangup Detected on A-Leg ".Red(), e.Headers[HeaderNames.CallerUniqueId], " ", e.Headers[HeaderNames.HangupCause]); connection.Exit(); }); var uuid = connection.ChannelData.Headers[HeaderNames.UniqueId]; await connection.SubscribeEvents( EventName.Dtmf); await connection.Linger(); await connection.ExecuteApplication(uuid, "answer", null, true, false); var result = await connection.Play( uuid, "$${base_dir}/sounds/en/us/callie/misc/8000/misc-freeswitch_is_state_of_the_art.wav"); //await connection.ExecuteAppAsync(uuid, "conference", "test+1234"); //if (result.ChannelData.AnswerState != AnswerState.Hangup) await connection.Hangup(uuid, "NORMAL_CLEARING"); }); listener.Start(); }
public void Run() { var listener = new OutboundListener(8084); listener.Channels.Subscribe( async channel => { try { channel.HangupCallBack = (e) => { ColorConsole.WriteLine("Hangup Detected on A-Leg {0} {1}".Fmt(e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Aleg bridge {0}".Fmt(channel.Bridge.HangupCause).OnRed()); ColorConsole.WriteLine(e.ToString().DarkGreen()); }; await channel.Answer(); await channel.StartDetectingInbandDtmf(); var bridgeOptions = new BridgeOptions() { UUID = Guid.NewGuid().ToString(), IgnoreEarlyMedia = true, RingBack = "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1", ContinueOnFail = true, HangupAfterBridge = true, TimeoutSeconds = 60, CallerIdName = channel["effective_caller_id_name"], CallerIdNumber = channel["effective_caller_id_number"], }; bridgeOptions.ChannelVariables.Add("bridge_filter_dtmf", "true"); await channel.BridgeTo("user/1003", bridgeOptions, (e) => ColorConsole.WriteLine("Bridge Progress Ringing...".DarkGreen())); if (!channel.Bridge.IsBridged) { ColorConsole.WriteLine("Bridge Failed - {0}".Fmt(channel.Bridge.HangupCause).Red()); await channel.PlayFile("ivr/8000/ivr-call_rejected.wav"); await channel.Hangup(HangupCause.NormalTemporaryFailure); } else { ColorConsole.WriteLine("Bridge success - {0}".Fmt(channel.Bridge.ResponseText).DarkGreen()); channel.Bridge.Channel.HangupCallBack = (e) => ColorConsole.WriteLine("Hangup Detected on B-Leg {0} {1}".Fmt(e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Enabling feature codes on the B-Leg: ".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#7".Yellow(), " to Start Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#8".Yellow(), " to Stop Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#4".Yellow(), " to Pause Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#5".Yellow(), " to Resume Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#9".Yellow(), " for attended transfer".DarkGreen()); await channel.SetChannelVariable("RECORD_STEREO", "true"); var recordingPath = "{0}.wav".Fmt(channel.UUID); channel.Bridge.Channel.FeatureCodes("#").Subscribe( async x => { try { ColorConsole.WriteLine("Detected Feature Code: ".DarkYellow(), x); switch (x) { case "#4": ColorConsole.WriteLine("Mask recording".Yellow()); await channel.MaskRecording(); await channel.PlayFile("ivr/8000/ivr-recording_paused.wav", Leg.BLeg); break; case "#5": ColorConsole.WriteLine("Unmask recording".Yellow()); await channel.UnmaskRecording(); await channel.PlayFile("ivr/8000/ivr-begin_recording.wav", Leg.BLeg); break; case "#8": ColorConsole.WriteLine("Stop recording".Yellow()); await channel.StopRecording(); await channel.PlayFile( "ivr/8000/ivr-recording_stopped.wav", Leg.Both); break; case "#7": ColorConsole.WriteLine("Start recording".Yellow()); await channel.StartRecording(recordingPath); await channel.PlayFile("ivr/8000/ivr-begin_recording.wav", Leg.Both); break; case "#9": ColorConsole.WriteLine("Attended x-fer".Yellow()); await Task.WhenAll( channel.PlayFile("ivr/8000/ivr-call_being_transferred.wav"), channel.Bridge.Channel.PlayFile("misc/8000/transfer1.wav")); var digits = await channel.Bridge.Channel.Read(new ReadOptions { MinDigits = 3, MaxDigits = 4, Prompt = "tone_stream://%(10000,0,350,440)", TimeoutMs = 30000, Terminators = "#" }); if (digits.Result == ReadResultStatus.Success && digits.Digits.Length == 4) { await channel.Bridge.Channel.SetChannelVariable("recording_follow_attxfer", "true"); await channel.Bridge.Channel.SetChannelVariable("origination_cancel_key", "#"); await channel.Bridge.Channel.SetChannelVariable("transfer_ringback", "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1"); await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-please_hold_while_party_contacted.wav"); //todo: push this logic into the channel itself? channel.ExitOnHangup = false; //we might want to notify b+c parties if the transfer failed var xfer = await channel.Bridge.Channel.AttendedTransfer("user/{0}".Fmt(digits)); channel.ExitOnHangup = true; //re enable exit on hangup ColorConsole.WriteLine("XFER: {0} {1}".Fmt(xfer.Status, xfer.HangupCause).Yellow()); if (xfer.Status != AttendedTransferResultStatus.Failed) { await channel.PlayFile("misc/8000/transfer2.wav", Leg.Both); } else { if (!channel.IsAnswered && channel.Bridge.Channel.IsAnswered) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-call_attempt_aborted.wav", Leg.Both); //as a-leg has disconnected, we'll close the socket when b-leg hangs up //todo: what if it's a three-way?! channel.Bridge.Channel.HangupCallBack = async _ => await channel.Exit(); return; } if (xfer.HangupCause == HangupCause.CallRejected) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-call_rejected.wav"); } else if (xfer.HangupCause == HangupCause.NoUserResponse || xfer.HangupCause == HangupCause.NoAnswer) { await channel.Bridge.Channel.PlayFile( "ivr/8000/ivr-no_user_response.wav"); } else if (xfer.HangupCause == HangupCause.UserBusy) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-user_busy.wav"); } else { await channel.Bridge.Channel.PlayFile( "ivr/8000/ivr-call_cannot_be_completed_as_dialed.wav"); } } } break; } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); listener.Start(); }
public void Run() { const string TempFolder = "C:/temp/"; const string ConferenceId = "my-test-conference"; const string ConferencePin = "1234"; const string ConferenceArgs = ConferenceId;// +"+" + ConferencePin; var listener = new OutboundListener(8084); string conferenceServerIp = null; bool conferenceIsStarted = false; listener.Channels.Subscribe( async channel => { try { var serverIpAddress = channel.Advanced.GetHeader("FreeSWITCH-IPv4"); var destinationNumber = channel.Advanced.GetHeader("Channel-Destination-Number"); ColorConsole.WriteLine("Connection from server ", serverIpAddress.Blue(), " for number", destinationNumber.Blue()); if (conferenceServerIp != null && conferenceServerIp != serverIpAddress) { //the conference has started on a different server, redirect to that server await channel.Execute("redirect", "sip:" + destinationNumber + "@" + conferenceServerIp); } else { //either conference has not started yet or it has started on this server await channel.Answer(); await channel.Sleep(400); await channel.PlayFile("ivr/ivr-welcome_to_freeswitch.wav"); if (conferenceIsStarted) { //prompt user for their name var nameFile = string.Concat(TempFolder, channel.UUID, ".wav"); ColorConsole.WriteLine("Recording name file to ", nameFile.Blue()); await channel.PlayFile("ivr/ivr-say_name.wav"); await channel.PlayFile("tone_stream://%(500,0,500)"); await channel.Advanced.Socket.ExecuteApplication(channel.UUID, "record", nameFile + " 10 200 1"); //when this member enters the conference, play the announcement channel.Advanced.Socket.ConferenceEvents.FirstAsync(x => x.Action == ConferenceAction.AddMember) .Subscribe( _ => channel.Advanced.Socket.Api("conference {0} play file_string://{1}!conference/conf-has_joined.wav" .Fmt(ConferenceId, nameFile))); } else { //first person in the conference, no need to record their name conferenceIsStarted = true; conferenceServerIp = serverIpAddress; } channel.Advanced.Socket.ConferenceEvents .Subscribe(x => { ColorConsole.WriteLine("Got conf event ".DarkYellow(), x.Action.ToString().Yellow()); switch (x.Action) { case ConferenceAction.StartTalking: ColorConsole.WriteLine( "Channel ".DarkGreen(), x.UUID.Green(), " started talking".DarkGreen()); break; case ConferenceAction.StopTalking: ColorConsole.WriteLine("Channel ".DarkRed(), x.UUID.Red(), " stopped talking".DarkRed()); break; } }); //if we await the result of this, we'll get OperationCanceledException on hangup await channel.Advanced.Socket.ExecuteApplication(channel.UUID, "conference", ConferenceArgs); } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); listener.Start(); }
public void Run() { const string TempFolder = "C:/temp/"; const string ConferenceId = "my-test-conference"; const string ConferencePin = "1234"; const string ConferenceArgs = ConferenceId;// +"+" + ConferencePin; var listener = new OutboundListener(8084); string conferenceServerIp = null; bool conferenceIsStarted = false; listener.Channels.Subscribe( async channel => { try { var serverIpAddress = channel.Advanced.GetHeader("FreeSWITCH-IPv4"); var destinationNumber = channel.Advanced.GetHeader("Channel-Destination-Number"); ColorConsole.WriteLine("Connection from server ", serverIpAddress.Blue(), " for number", destinationNumber.Blue()); if (conferenceServerIp != null && conferenceServerIp != serverIpAddress) { //the conference has started on a different server, redirect to that server await channel.Execute("redirect", "sip:" + destinationNumber + "@" + conferenceServerIp); } else { //either conference has not started yet or it has started on this server await channel.Answer(); await channel.Sleep(400); await channel.PlayFile("ivr/ivr-welcome_to_freeswitch.wav"); if (conferenceIsStarted) { //prompt user for their name var nameFile = string.Concat(TempFolder, channel.UUID, ".wav"); ColorConsole.WriteLine("Recording name file to ", nameFile.Blue()); await channel.PlayFile("ivr/ivr-say_name.wav"); await channel.PlayFile("tone_stream://%(500,0,500)"); await channel.Advanced.Socket.ExecuteApplication(channel.UUID, "record", nameFile + " 10 200 1"); //when this member enters the conference, play the announcement channel.Advanced.Socket.ConferenceEvents.FirstAsync(x => x.Action == ConferenceAction.AddMember) .Subscribe( _ => channel.Advanced.Socket.Api("conference {0} play file_string://{1}!conference/conf-has_joined.wav" .Fmt(ConferenceId, nameFile))); } else { //first person in the conference, no need to record their name conferenceIsStarted = true; conferenceServerIp = serverIpAddress; } channel.Advanced.Socket.ConferenceEvents .Subscribe(x => { ColorConsole.WriteLine("Got conf event ".DarkYellow(), x.Action.ToString().Yellow()); switch (x.Action) { case ConferenceAction.StartTalking: ColorConsole.WriteLine( "Channel ".DarkGreen(), x.UUID.Green(), " started talking".DarkGreen()); break; case ConferenceAction.StopTalking: ColorConsole.WriteLine("Channel ".DarkRed(), x.UUID.Red(), " stopped talking".DarkRed()); break; } }); //if we await the result of this, we'll get OperationCanceledException on hangup await channel.Advanced.Socket.ExecuteApplication(channel.UUID, "conference", ConferenceArgs); } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); listener.Start(); }
public void Run() { var listener = new OutboundListener(8084); listener.Channels.Subscribe( async channel => { try { channel.HangupCallBack = (e) => { ColorConsole.WriteLine("Hangup Detected on A-Leg {0} {1}".Fmt(e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Aleg bridge {0}".Fmt(channel.Bridge.HangupCause).OnRed()); ColorConsole.WriteLine(e.ToString().DarkGreen()); }; await channel.Answer(); await channel.StartDetectingInbandDtmf(); var bridgeOptions = new BridgeOptions() { UUID = Guid.NewGuid().ToString(), IgnoreEarlyMedia = true, RingBack = "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1", ContinueOnFail = true, HangupAfterBridge = true, TimeoutSeconds = 60, CallerIdName = channel.Advanced.GetVariable("effective_caller_id_name"), CallerIdNumber = channel.Advanced.GetVariable("effective_caller_id_number"), }; bridgeOptions.ChannelVariables.Add("bridge_filter_dtmf", "true"); await channel.BridgeTo("user/1003", bridgeOptions, (e) => ColorConsole.WriteLine("Bridge Progress Ringing...".DarkGreen())); if (!channel.Bridge.IsBridged) { ColorConsole.WriteLine("Bridge Failed - {0}".Fmt(channel.Bridge.HangupCause).Red()); await channel.PlayFile("ivr/8000/ivr-call_rejected.wav"); await channel.Hangup(HangupCause.NormalTemporaryFailure); } else { ColorConsole.WriteLine("Bridge success - {0}".Fmt(channel.Bridge.ResponseText).DarkGreen()); channel.Bridge.Channel.HangupCallBack = (e) => ColorConsole.WriteLine("Hangup Detected on B-Leg {0} {1}".Fmt(e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Enabling feature codes on the B-Leg: ".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#7".Yellow(), " to Start Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#8".Yellow(), " to Stop Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#4".Yellow(), " to Pause Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#5".Yellow(), " to Resume Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#9".Yellow(), " for attended transfer".DarkGreen()); await channel.SetChannelVariable("RECORD_STEREO", "true"); var recordingPath = "{0}.wav".Fmt(channel.UUID); channel.Bridge.Channel.FeatureCodes("#").Subscribe( async x => { try { ColorConsole.WriteLine("Detected Feature Code: ".DarkYellow(), x); switch (x) { case "#4": ColorConsole.WriteLine("Mask recording".Yellow()); await channel.MaskRecording(); await channel.PlayFile("ivr/8000/ivr-recording_paused.wav", Leg.BLeg); break; case "#5": ColorConsole.WriteLine("Unmask recording".Yellow()); await channel.UnmaskRecording(); await channel.PlayFile("ivr/8000/ivr-begin_recording.wav", Leg.BLeg); break; case "#8": ColorConsole.WriteLine("Stop recording".Yellow()); await channel.StopRecording(); await channel.PlayFile( "ivr/8000/ivr-recording_stopped.wav", Leg.Both); break; case "#7": ColorConsole.WriteLine("Start recording".Yellow()); await channel.StartRecording(recordingPath); await channel.PlayFile("ivr/8000/ivr-begin_recording.wav", Leg.Both); break; case "#9": ColorConsole.WriteLine("Attended x-fer".Yellow()); await Task.WhenAll( channel.PlayFile("ivr/8000/ivr-call_being_transferred.wav"), channel.Bridge.Channel.PlayFile("misc/8000/transfer1.wav")); var digits = await channel.Bridge.Channel.Read(new ReadOptions { MinDigits = 3, MaxDigits = 4, Prompt = "tone_stream://%(10000,0,350,440)", TimeoutMs = 30000, Terminators = "#" }); if (digits.Result == ReadResultStatus.Success && digits.Digits.Length == 4) { await channel.Bridge.Channel.SetChannelVariable("recording_follow_attxfer", "true"); await channel.Bridge.Channel.SetChannelVariable("origination_cancel_key", "#"); await channel.Bridge.Channel.SetChannelVariable("transfer_ringback", "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1"); await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-please_hold_while_party_contacted.wav"); //todo: push this logic into the channel itself? channel.ExitOnHangup = false; //we might want to notify b+c parties if the transfer failed var xfer = await channel.Bridge.Channel.AttendedTransfer("user/{0}".Fmt(digits)); channel.ExitOnHangup = true; //re enable exit on hangup ColorConsole.WriteLine("XFER: {0} {1}".Fmt(xfer.Status, xfer.HangupCause).Yellow()); if (xfer.Status != AttendedTransferResultStatus.Failed) { await channel.PlayFile("misc/8000/transfer2.wav", Leg.Both); } else { if (!channel.IsAnswered && channel.Bridge.Channel.IsAnswered) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-call_attempt_aborted.wav", Leg.Both); //as a-leg has disconnected, we'll close the socket when b-leg hangs up //todo: what if it's a three-way?! channel.Bridge.Channel.HangupCallBack = async _ => await channel.Exit(); return; } if (xfer.HangupCause == HangupCause.CallRejected) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-call_rejected.wav"); } else if (xfer.HangupCause == HangupCause.NoUserResponse || xfer.HangupCause == HangupCause.NoAnswer) { await channel.Bridge.Channel.PlayFile( "ivr/8000/ivr-no_user_response.wav"); } else if (xfer.HangupCause == HangupCause.UserBusy) { await channel.Bridge.Channel.PlayFile("ivr/8000/ivr-user_busy.wav"); } else { await channel.Bridge.Channel.PlayFile( "ivr/8000/ivr-call_cannot_be_completed_as_dialed.wav"); } } } break; } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.UUID, channel.Answered).OnRed()); } }); listener.Start(); }
public async Task each_new_connection_produces_a_new_outbound_socket_from_the_Connections_observable() { const int NumberOfConnections = 3; using (var listener = new OutboundListener(0)) { listener.Start(); var connected = 0; listener.Connections.Subscribe((socket) => connected++); for (int i = 0; i < NumberOfConnections; i++) { var client = new FakeFreeSwitchSocket(listener.Port); } await Wait.Until(() => connected == NumberOfConnections); Assert.Equal(NumberOfConnections, connected); } }
public Task Run(CancellationToken cancellationToken) { const string MusicOnHold = "local_stream://moh"; const string AgentEndPoint = "user/1003"; const string RingTone = "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1"; // uk ring const string DialTone = "tone_stream://%(10000,0,350,440)"; const string RecordingPath = "/var/tmp/"; listener = new OutboundListener(8084); listener.Channels.Subscribe( async channel => { try { channel.BridgedChannels.Subscribe( async bridgedChannel => { ColorConsole.WriteLine("New Bridged Channel [{0}]".Fmt(bridgedChannel.Uuid).DarkGreen()); bridgedChannel.HangupCallBack = (e) => ColorConsole.WriteLine( "Hangup Detected on B-Leg {0} {1}".Fmt( e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Enabling feature codes on the B-Leg: ".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#1".Yellow(), " to Play to both Legs".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#2".Yellow(), " to Play to A Leg".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#3".Yellow(), " to Play to B Leg".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#7".Yellow(), " to Start Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#8".Yellow(), " to Stop Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#4".Yellow(), " to Pause Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#5".Yellow(), " to Resume Recording".DarkGreen()); ColorConsole.WriteLine("Press ".DarkGreen(), "#9".Yellow(), " for attended transfer".DarkGreen()); await channel.SetChannelVariable("RECORD_STEREO", "true"); var recordingPath = RecordingPath + channel.Uuid + ".wav"; bridgedChannel.FeatureCodes("#").Subscribe( async x => { try { ColorConsole.WriteLine("Detected Feature Code: ".DarkYellow(), x); switch (x) { case "#1": await channel.Play("ivr/ivr-welcome_to_freeswitch.wav", Leg.Both); break; case "#2": await channel.Play("ivr/ivr-welcome_to_freeswitch.wav", Leg.ALeg); break; case "#3": await channel.Play("ivr/ivr-welcome_to_freeswitch.wav", Leg.BLeg); break; case "#4": ColorConsole.WriteLine("Mask recording".Yellow()); await channel.MaskRecording(); await channel.Play("ivr/ivr-recording_paused.wav", Leg.BLeg); break; case "#5": ColorConsole.WriteLine("Unmask recording".Yellow()); await channel.UnmaskRecording(); await channel.Play("ivr/ivr-begin_recording.wav", Leg.BLeg); break; case "#8": ColorConsole.WriteLine("Stop recording".Yellow()); await channel.StopRecording(); await channel.Play("ivr/ivr-recording_stopped.wav", Leg.Both); break; case "#7": ColorConsole.WriteLine("Start recording".Yellow()); await channel.StartRecording(recordingPath); await channel.Play("ivr/ivr-begin_recording.wav", Leg.Both); break; case "#9": ColorConsole.WriteLine("Attended x-fer".Yellow()); await Task.WhenAll( channel.Play("ivr/ivr-call_being_transferred.wav"), bridgedChannel.Play("misc/transfer1.wav")); var holdMusic = await channel.PlayUntilCancelled(MusicOnHold); var digits = await bridgedChannel.Read( new ReadOptions { MinDigits = 3, MaxDigits = 4, Prompt = DialTone, TimeoutMs = 30000, Terminators = "#" }); if (digits.Result != ReadResultStatus.Success || digits.Digits.Length != 4) { holdMusic.Dispose(); } else { await bridgedChannel.SetChannelVariable("recording_follow_attxfer", "true"); await bridgedChannel.SetChannelVariable("origination_cancel_key", "#"); await bridgedChannel.SetChannelVariable("transfer_ringback", RingTone); var xfer = await bridgedChannel.AttendedTransfer("user/{0}".Fmt(digits)); holdMusic.Dispose(); ColorConsole.WriteLine( "Xfer ".Yellow(), xfer.Status.ToString().DarkYellow(), " ", xfer.HangupCause.GetValueOrDefault().ToString()); if (xfer.Status != AttendedTransferResultStatus.Failed) { await channel.Play("misc/transfer2.wav", Leg.Both); } else { if (xfer.HangupCause == HangupCause.CallRejected) { await bridgedChannel.Play("ivr/ivr-call_rejected.wav"); } else if (xfer.HangupCause == HangupCause.NoUserResponse || xfer.HangupCause == HangupCause.NoAnswer) { await bridgedChannel.Play("ivr/ivr-no_user_response.wav"); } else if (xfer.HangupCause == HangupCause.UserBusy) { await bridgedChannel.Play("ivr/ivr-user_busy.wav"); } else { await bridgedChannel.Play( "ivr/ivr-call_cannot_be_completed_as_dialed.wav"); } } } break; } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.Uuid, channel.Answered).OnRed()); } }); }); channel.HangupCallBack = (e) => { ColorConsole.WriteLine("Hangup Detected on A-Leg {0} {1}".Fmt(e.Headers[HeaderNames.CallerUniqueId], e.Headers[HeaderNames.HangupCause]).Red()); ColorConsole.WriteLine("Aleg bridge {0}".Fmt(channel.GetVariable("last_bridge_hangup_cause")).OnRed()); }; await channel.Answer(); var queueHoldMusic = await channel.PlayUntilCancelled(MusicOnHold); await Task.Delay(5000); await channel.Play(new[] { "ivr/ivr-you_are_number.wav", 123456.ToFileString(), "ivr/ivr-in_line.wav" }); await Task.Delay(5000); queueHoldMusic.Dispose(); var bridgeOptions = new BridgeOptions() { UUID = Guid.NewGuid().ToString(), IgnoreEarlyMedia = true, RingBack = RingTone, ContinueOnFail = true, HangupAfterBridge = true, TimeoutSeconds = 10, CallerIdName = channel.GetVariable("effective_caller_id_name"), CallerIdNumber = channel.GetVariable("effective_caller_id_number"), }; await channel.SetChannelVariable( "transfer_ringback", "tone_stream://%(400,200,400,450);%(400,2000,400,450);loops=-1"); await channel.BridgeTo(AgentEndPoint, bridgeOptions, (e) => ColorConsole.WriteLine("Bridge Progress Ringing...".DarkGreen())); if (!channel.IsBridged) { ColorConsole.WriteLine("Bridge Failed - {0}".Fmt(channel.Variables.BridgeHangupCause).Red()); await channel.Play("ivr/ivr-call_rejected.wav"); await channel.Hangup(HangupCause.NormalTemporaryFailure); } } catch (OperationCanceledException ex) { ColorConsole.WriteLine("TaskCancelled - shutting down\r\n{0}".Fmt(ex.ToString()).OnRed()); ColorConsole.WriteLine("Channel {0} is {1}".Fmt(channel.Uuid, channel.Answered).OnRed()); } }); listener.Start(); Console.WriteLine("Listener started. Press [Enter] to stop"); Console.ReadLine(); return(Task.FromResult(0)); }
public async Task Calling_Connect_on_a_new_OutboundSocket_should_populate_the_ChannelData() { using (var listener = new OutboundListener(0)) { listener.Start(); EventMessage channelData = null; listener.Connections.Subscribe( async (socket) => { channelData = await socket.Connect(); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); await Wait.Until(() => channelData != null); Assert.NotNull(channelData); Assert.Equal(ChannelState.Execute, channelData.ChannelState); Assert.Equal("RINGING", channelData.Headers["Channel-Call-State"]); } } }
public async Task can_send_multple_commands() { using (var listener = new OutboundListener(0)) { listener.Start(); bool commandRequestReceived = false; CommandReply commandReply = null; listener.Connections.Subscribe( async (socket) => { await socket.Connect(); commandReply = await socket.Linger(); commandReply = await socket.NoLinger(); }); using (var freeSwitch = new FakeFreeSwitchSocket(listener.Port)) { freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("connect")) .Subscribe(async _ => await freeSwitch.SendChannelDataEvent()); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("linger")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyOk(); }); freeSwitch.MessagesReceived.FirstAsync(m => m.StartsWith("nolinger")) .Subscribe(async _ => { await freeSwitch.SendCommandReplyError("FAILED"); commandRequestReceived = true; }); await Wait.Until(() => commandRequestReceived); Assert.True(commandRequestReceived); Assert.NotNull(commandReply); Assert.False(commandReply.Success); } } }
public Task Run(CancellationToken cancellationToken) { listener = new OutboundListener(8084); listener2 = new OutboundListener(8085); /* this example demonstrates forwarding an outbound connection from one listener to another. * FS Dialplan is configured to hit localhost:8084 * By parking the call then using sched_api to schedule a transfer, we can disconnect the socket on localhost:8084 * and allow transfer the call to localhost:8085 without hanging up the call when the first socket disconnects. */ listener.Connections.Subscribe( async connection => { try { await connection.Connect(); await connection.ExecuteApplication(connection.ChannelData.UUID, "pre_answer"); //let's pretend we did a database or service registry lookup to find the socket server we want to route to - localhost:8085 in this example await connection.Api("uuid_park", connection.ChannelData.UUID); await connection.Api("sched_api +0.01 none uuid_transfer {0} 'socket:127.0.0.1:8085 async full' inline".Fmt(connection.ChannelData.UUID)); await connection.Exit(); } catch (OperationCanceledException) { } }); listener2.Connections.Subscribe( async connection => { try { await connection.Connect(); Console.WriteLine("New Socket connected"); await connection.ExecuteApplication(connection.ChannelData.UUID, "answer"); connection.Events.Where(x => x.UUID == connection.ChannelData.UUID && x.EventName == EventName.ChannelHangup) .Take(1) .Subscribe( async e => { ColorConsole.WriteLine( "Hangup Detected on A-Leg ".Red(), e.Headers[HeaderNames.CallerUniqueId], " ", e.Headers[HeaderNames.HangupCause]); await connection.Exit(); }); connection.Events.Where(x => x.UUID == connection.ChannelData.UUID && x.EventName == EventName.Dtmf) .Subscribe( async e => { ColorConsole.WriteLine( "DTMF Detected on A-Leg ".Red(), e.Headers[HeaderNames.CallerUniqueId].Yellow(), " ", e.Headers[HeaderNames.DtmfDigit].Red()); await connection.Play(connection.ChannelData.UUID, "ivr/ivr-you_entered.wav"); await connection.Say( connection.ChannelData.UUID, new SayOptions() { Gender = SayGender.Feminine, Method = SayMethod.Iterated, Text = e.Headers[HeaderNames.DtmfDigit], Type = SayType.Number }); }); var uuid = connection.ChannelData.Headers[HeaderNames.UniqueId]; await connection.SubscribeEvents(EventName.Dtmf, EventName.ChannelHangup); await connection.Linger(); await connection.ExecuteApplication(uuid, "answer", null, true, false); await connection.Play(uuid, "misc/misc-freeswitch_is_state_of_the_art.wav"); } catch (OperationCanceledException) { } }); listener.Start(); listener2.Start(); Console.WriteLine("Listener started on 8084 and 8085. Press [Enter] to exit"); Console.ReadLine(); return(Task.FromResult(0)); }
public async Task Run(CancellationToken cancellationToken) { //cancellationToken is cancelled when Ctrl+C is pressed //we'll use our own inner cancellationToken in our business logic //and link it to the outer one that is provided. var ourCancellationToken = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); using (var client = await InboundSocket.Connect()) { Console.WriteLine("Authenticated!"); await client.SubscribeEvents(EventName.ChannelHangup, EventName.BackgroundJob); client.ChannelEvents.Where(x => x.EventName == EventName.ChannelHangup && x.HangupCause != HangupCause.NormalClearing) .Subscribe(x => { Console.WriteLine("Hangup Detected : {0} {1}", x.GetVariable("mobile_no"), x.HangupCause); }); using (var listener = new OutboundListener(8084)) { listener.Connections.Subscribe( async socket => { try { await socket.Connect(); await socket.Filter(HeaderNames.UniqueId, socket.ChannelData.UUID); var uuid = socket.ChannelData.Headers[HeaderNames.UniqueId]; Console.WriteLine( "OutboundSocket connected for channel {0} {1}", uuid, socket.ChannelData.GetVariable("mobile_no")); await socket.Play(uuid, "misc/8000/misc-learn_more_about_freeswitch_solutions.wav"); await socket.Play(uuid, "misc/8000/misc-freeswitch_is_state_of_the_art.wav"); await socket.ExecuteApplication(uuid, "sleep", "1000"); //wait for audio to go out to the network await socket.Hangup(uuid, HangupCause.NormalClearing); } catch (OperationCanceledException) { //hangup - freeswitch disconnected from us } }); listener.Start(); var checkCallCount = new Task( async() => { try { while (!ourCancellationToken.IsCancellationRequested) { var res = await client.SendApi("show calls count"); Console.WriteLine("Current Calls Count " + Convert.ToInt32(res.BodyText.Split(' ')[0])); currentCallCount = Convert.ToInt32(res.BodyText.Split(' ')[0]); await Task.Delay(2000); } } catch (OperationCanceledException) { //shutdown } }); checkCallCount.Start(); Task.Run( async() => { try { await Dialler(client, ourCancellationToken.Token); } catch (OperationCanceledException) { //shutdown } }); ColorConsole.WriteLine("Press [Enter] to exit.".Green()); await Util.WaitForEnterKeyPress(cancellationToken); ourCancellationToken.Cancel(); listener.Dispose(); } } }