private static Task <bool> PlaceCall(CancellationToken cancel) { // Set up a default SIP transport. var sipTransport = new SIPTransport(); //EnableTraceLogs(sipTransport); var targetUri = SIPURI.ParseSIPURI(TARGET_DST); int requestedDtmfCode = Crypto.GetRandomInt(4); targetUri.User = requestedDtmfCode.ToString(); SIPUserAgent ua = new SIPUserAgent(sipTransport, null, true); CallRecord cr = new CallRecord { UA = ua, RequestedDtmfCode = requestedDtmfCode, ReceivedDtmfCode = "" }; TaskCompletionSource <bool> dtmfComplete = new TaskCompletionSource <bool>(TaskCreationOptions.RunContinuationsAsynchronously); // Place an outgoing call. ua.ClientCallTrying += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}."); ua.ClientCallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}."); ua.ClientCallFailed += (uac, err, resp) => Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}, Status code: {resp?.StatusCode}"); ua.ClientCallAnswered += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}."); ua.OnDtmfTone += (key, duration) => { cr.ReceivedDtmfCode = cr.ReceivedDtmfCode.Insert(0, key.ToString()); Log.LogInformation($"Received DTMF tone {key} {cr.ReceivedDtmfCode}."); if (cr.ReceivedDtmfCode == cr.RequestedDtmfCode.ToString()) { dtmfComplete.SetResult(true); } }; //ua.OnRtpEvent += (evt, hdr) => Log.LogDebug($"transferee rtp event {evt.EventID}, ssrc {hdr.SyncSource}, duration {evt.Duration}, end of event {evt.EndOfEvent}, timestamp {hdr.Timestamp}, marker {hdr.MarkerBit}."); ua.OnCallHungup += (dialog) => Log.LogDebug("Call hungup by remote party."); var rtpSession = CreateRtpSession(); var callTask = ua.Call(targetUri.ToString(), null, null, rtpSession); bool dtmfResult = false; bool didComplete = Task.WaitAll(new Task[] { callTask }, TIMEOUT_MILLISECONDS, cancel); if (!didComplete || !callTask.Result) { Log.LogWarning($"Call to {targetUri} failed."); } else { Log.LogInformation($"Call to {targetUri} was successful."); _calls.TryAdd(ua.Dialogue.CallId, cr); if (Task.WaitAll(new Task[] { dtmfComplete.Task }, TIMEOUT_MILLISECONDS, cancel)) { dtmfResult = dtmfComplete.Task.Result; } else { Log.LogWarning("Timeout waiting for DTMF task to complete."); } ua.Hangup(); } return(Task.FromResult(dtmfResult)); //return Task.FromResult(true); }
/// <summary> /// Process user key presses. /// </summary> /// <param name="exit">The cancellation token to set if the user requests to quit the application.</param> private static void OnKeyPress(CancellationTokenSource exitCts) { try { while (!exitCts.IsCancellationRequested) { var keyProps = Console.ReadKey(); if (keyProps.KeyChar == 'c') { // Set up a default SIP transport. var sipTransport = new SIPTransport(); //EnableTraceLogs(sipTransport); var targetUri = SIPURI.ParseSIPURI(TARGET_DST); int requestedDtmfCode = Crypto.GetRandomInt(4); targetUri.User = requestedDtmfCode.ToString(); SIPUserAgent ua = new SIPUserAgent(sipTransport, null, true); CallRecord cr = new CallRecord { UA = ua, RequestedDtmfCode = requestedDtmfCode, ReceivedDtmfCode = "" }; // Place an outgoing call. ua.ClientCallTrying += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Trying: {resp.StatusCode} {resp.ReasonPhrase}."); ua.ClientCallRinging += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Ringing: {resp.StatusCode} {resp.ReasonPhrase}."); ua.ClientCallFailed += (uac, err, resp) => Log.LogWarning($"{uac.CallDescriptor.To} Failed: {err}, Status code: {resp?.StatusCode}"); ua.ClientCallAnswered += (uac, resp) => Log.LogInformation($"{uac.CallDescriptor.To} Answered: {resp.StatusCode} {resp.ReasonPhrase}."); ua.OnDtmfTone += (key, duration) => { cr.ReceivedDtmfCode = cr.ReceivedDtmfCode.Insert(0, key.ToString()); Log.LogInformation($"Received DTMF tone {key} {cr.ReceivedDtmfCode}."); }; //ua.OnRtpEvent += (evt, hdr) => Log.LogDebug($"transferee rtp event {evt.EventID}, ssrc {hdr.SyncSource}, duration {evt.Duration}, end of event {evt.EndOfEvent}, timestamp {hdr.Timestamp}, marker {hdr.MarkerBit}."); ua.OnCallHungup += (dialog) => Log.LogDebug("Call hungup by remote party."); Task.Run(async() => { var rtpSession = CreateRtpSession(); var callResult = await ua.Call(targetUri.ToString(), null, null, rtpSession); if (!callResult) { Log.LogWarning($"Call to {targetUri} failed."); } else { Log.LogInformation($"Call to {targetUri} was successful."); _calls.TryAdd(ua.Dialogue.CallId, cr); } }); } else if (keyProps.KeyChar == 'h') { if (_calls.Count == 0) { Log.LogWarning("There are no active calls."); } else { var oldestCall = _calls.OrderBy(x => x.Value.UA.Dialogue.Inserted).First(); Log.LogInformation($"Hanging up call {oldestCall.Key}."); oldestCall.Value.UA.OnCallHungup -= OnHangup; oldestCall.Value.UA.Hangup(); _calls.TryRemove(oldestCall.Key, out _); } } else if (keyProps.KeyChar == 'H') { if (_calls.Count == 0) { Log.LogWarning("There are no active calls."); } else { foreach (var call in _calls) { Log.LogInformation($"Hanging up call {call.Key}."); call.Value.UA.OnCallHungup -= OnHangup; call.Value.UA.Hangup(); } _calls.Clear(); } } else if (keyProps.KeyChar == 'l') { if (_calls.Count == 0) { Log.LogInformation("There are no active calls."); } else { Log.LogInformation("Current call list:"); foreach (var call in _calls) { int duration = Convert.ToInt32(DateTimeOffset.Now.Subtract(call.Value.UA.Dialogue.Inserted).TotalSeconds); uint rtpSent = (call.Value.UA.MediaSession as RtpAudioSession).RtpPacketsSent; uint rtpRecv = (call.Value.UA.MediaSession as RtpAudioSession).RtpPacketsReceived; Log.LogInformation($"{call.Key}: {call.Value.UA.Dialogue.RemoteTarget}, req code {call.Value.RequestedDtmfCode}, recvd code {call.Value.ReceivedDtmfCode}, dur {duration}s, rtp sent/recvd {rtpSent}/{rtpRecv}"); } } } else if (keyProps.KeyChar == 'q') { // Quit application. Log.LogInformation("Quitting"); exitCts.Cancel(); break; } } } catch (Exception excp) { Log.LogError($"Exception OnKeyPress. {excp.Message}."); } }