/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage(this, "Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { if (sipResponse.Header.ContentType != _sdpMimeContentType) { // Payload not SDP, I don't understand :(. StatusMessage(this, "Call was hungup as the answer response content type was not recognized: " + sipResponse.Header.ContentType + ". :("); Hangup(); } else if (sipResponse.Body.IsNullOrBlank()) { // They said SDP but didn't give us any :(. StatusMessage(this, "Call was hungup as the answer response had an empty SDP payload. :("); Hangup(); } else { CallAnswer?.Invoke(this); } } else { CallFinished(); } }
private void DispatcherCallFailed(ISIPClientUserAgent uac, string errorMessage) { try { string workerSocket = SIPURI.ParseSIPURI(uac.CallDescriptor.Uri).Host; dispatcherLogger.Debug("Dispatcher call to " + workerSocket + " failed " + errorMessage + "."); // Find the worker for the failed end point. SIPCallDispatcherWorker failedWorker = null; lock (m_callDispatcherWorkers) { foreach (SIPCallDispatcherWorker worker in m_callDispatcherWorkers) { if (worker.AppServerEndpoint.SocketEndPoint.ToString() == workerSocket) { failedWorker = worker; break; } } } if (failedWorker != null) { dispatcherLogger.Debug("Scheduling immediate restart on worker process pid=" + failedWorker.WorkerProcess.Id + " due to failed probe."); failedWorker.RestartTime = DateTime.Now; } } catch (Exception excp) { dispatcherLogger.Error("Exception DispatcherCallFailed. " + excp.Message); } }
private void ForwardCallAnswered(ISIPClientUserAgent uac, SIPB2BUserAgent b2bua) { if (uac.SIPDialogue != null) { _sipCallManager.BridgeDialogues(uac.SIPDialogue, b2bua.SIPDialogue); } }
/// <summary> /// Event handler for a failed probe response. /// </summary> private void AppServerCallFailed(ISIPClientUserAgent uac, string errorMessage, int workerProcessID, DateTime probeSentAt, bool isInitialProbe) { try { string workerSocket = SIPURI.ParseSIPURI(uac.CallDescriptor.Uri).Host; logger.Warn("SIPAppServerManager call to " + workerSocket + " for PID " + workerProcessID + " failed, initial probe " + isInitialProbe + " , sent at " + probeSentAt.ToString("dd MMM yyyy HH:mm:ss") + ", " + errorMessage); // Find the worker for the failed end point. SIPAppServerWorker failedWorker = GetWorkerForEndPoint(workerSocket); // Make sure the worker process hasn't changed in the meantime and don't restart for initial probes. if (failedWorker != null && failedWorker.WorkerProcess != null && failedWorker.WorkerProcess.Id == workerProcessID) { if (!isInitialProbe) { failedWorker.InitialProbeResponseReceived = true; logger.Debug("Scheduling immediate restart on app server worker process pid=" + failedWorker.WorkerProcess.Id + ", " + workerSocket + " due to failed probe."); failedWorker.ScheduleRestart(DateTime.Now); } else if (failedWorker.InitialProbeCount >= INITIAL_PROBE_RETRANSMIT_LIMIT) { failedWorker.InitialProbeResponseReceived = true; logger.Debug("Initial probe retransmit limit reached, scheduling immediate restart on app server worker process pid=" + failedWorker.WorkerProcess.Id + ", " + workerSocket + " due to failed probe."); failedWorker.ScheduleRestart(DateTime.Now); } } } catch (Exception excp) { logger.Error("Exception AppServerCallFailed. " + excp.Message); } }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage("Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { if (sipResponse.Header.ContentType != _sdpMimeContentType) { // Payload not SDP, I don't understand :(. StatusMessage("Call was hungup as the answer response content type was not recognised: " + sipResponse.Header.ContentType + ". :("); Hangup(); } else if (sipResponse.Body.IsNullOrBlank()) { // They said SDP but didn't give me any :(. StatusMessage("Call was hungup as the answer response had an empty SDP payload. :("); Hangup(); } SDP sdpAnswer = SDP.ParseSDPDescription(sipResponse.Body); System.Diagnostics.Debug.WriteLine(sipResponse.Body); _mediaManager.SetRemoteSDP(sdpAnswer); CallAnswer(); } else { CallFinished(); } }
public void CancelNotRequiredCallLegs(CallCancelCause cancelCause) { try { m_commandCancelled = true; FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Cancelling all call legs for ForkCall app.", m_username)); // Cancel all forwarded call legs. if (m_switchCalls.Count > 0) { ISIPClientUserAgent[] inProgressCalls = (from ua in m_switchCalls where !ua.IsUACAnswered select ua).ToArray(); for (int index = 0; index < inProgressCalls.Length; index++) { ISIPClientUserAgent uac = inProgressCalls[index]; uac.Cancel(); } } // Signal any delayed calls that they are no longer required. foreach (SIPCallDescriptor callDescriptor in m_delayedCalls) { callDescriptor.DelayMRE.Set(); } CallLegCompleted(); } catch (Exception excp) { logger.Error("Exception ForkCall CancelAllCallLegs. " + excp); } }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private async void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage(this, "Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); // This call will allow the session source to be adjusted depending on whether the underlying // session has support for audio or video. await MediaSession.SetSources(null, null).ConfigureAwait(false); CallAnswer?.Invoke(this); }
/// <summary> /// Event handler for a client call (one initiated by us) failing. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="errorMessage">An error message indicating the reason for the failure.</param> private void ClientCallFailedHandler(ISIPClientUserAgent uac, string errorMessage) { if (ClientCallFailed != null) { ClientCallFailed(uac, errorMessage); } else { logger.LogWarning($"Call attempt to {m_uac.CallDescriptor.Uri} failed with {errorMessage}."); } }
/// <summary> /// Event handler for a client call (one initiated by us) receiving an in progress response. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="sipResponse">The INVITE ringing response.</param> private void ClientCallRingingHandler(ISIPClientUserAgent uac, SIPResponse sipResponse) { if (ClientCallRinging != null) { ClientCallRinging(uac, sipResponse); } else { logger.LogInformation($"Call attempt to {m_uac.CallDescriptor.Uri} received a ringing response {sipResponse.ShortDescription}."); } }
/// <summary> /// Event handler for a client call (one initiated by us) being answered. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="sipResponse">The INVITE success response.</param> private void ClientCallAnsweredHandler(ISIPClientUserAgent uac, SIPResponse sipResponse) { if (ClientCallAnswered != null) { ClientCallAnswered(uac, sipResponse); } else { logger.LogDebug($"Call attempt to {m_uac.CallDescriptor.Uri} was answered."); } }
private void ClientCallFailed(ISIPClientUserAgent uac, string error, SIPResponse errResponse) { if (!base.IsCancelled) { logger.LogDebug($"B2BUserAgent client call failed {error}."); var status = (errResponse != null) ? errResponse.Status : SIPResponseStatusCodesEnum.Decline; var errResp = SIPResponse.GetResponse(m_uasTransaction.TransactionRequest, status, errResponse?.ReasonPhrase); m_uasTransaction.SendFinalResponse(errResp); CallFailed?.Invoke(uac, error, errResponse); } }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage("Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { IPEndPoint remoteSDPEndPoint = SDP.GetSDPRTPEndPoint(sipResponse.Body); _audioChannel.SetRemoteRTPEndPoint(remoteSDPEndPoint); CallAnswer(); } else { CallFinished(); } }
/// <summary> /// Event handler for a successful probe response. /// </summary> private void AppServerCallSucceeded(ISIPClientUserAgent uac) { try { string workerSocket = SIPURI.ParseSIPURI(uac.CallDescriptor.Uri).Host; SIPAppServerWorker worker = GetWorkerForEndPoint(workerSocket); if (!worker.InitialProbeResponseReceived) { logger.Debug("Initial probe received for " + workerSocket + "."); worker.InitialCallSuccessful(); } } catch (Exception excp) { logger.Error("Exception AppServerCallSucceeded. " + excp.Message); } }
private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { logger.Debug("AppServerDispatcher CallAnswered with " + (int)sipResponse.Status + " " + sipResponse.ReasonPhrase + "."); SIPHeader okHeader = uac.ServerTransaction.TransactionFinalResponse.Header; int executionCount = 0; foreach (string unknownHeader in okHeader.UnknownHeaders) { if (unknownHeader.StartsWith("DialPlanEngine-ExecutionCount")) { executionCount = Convert.ToInt32(Regex.Match(unknownHeader, @"\S: (?<count>\d+)").Result("${count}")); break; } } m_startCheckTime.Stop(); logger.Debug("AppServerDispatcher execution count for " + m_activeAppServerEntry.AppServerURI.ToString() + " is " + executionCount + "."); logger.Debug("AppServerDispatcher response took " + m_startCheckTime.ElapsedMilliseconds + "ms."); }
private void ClientCallAnswered(ISIPClientUserAgent uac, SIPResponse resp) { logger.LogDebug($"B2BUserAgent client call answered {resp.ShortDescription}."); if (resp.Status == SIPResponseStatusCodesEnum.Ok) { base.Answer(resp.Header.ContentType, resp.Body, SIPDialogueTransferModesEnum.NotAllowed); CallAnswered?.Invoke(uac, resp); } else { var failureResponse = SIPResponse.GetResponse(m_uasTransaction.TransactionRequest, resp.Status, resp.ReasonPhrase); m_uasTransaction.SendFinalResponse(failureResponse); CallFailed?.Invoke(uac, failureResponse.ReasonPhrase, failureResponse); } }
private void UACCallProgress(ISIPClientUserAgent uac, SIPResponse progressResponse) { try { if (m_commandCancelled) { //logger.Debug("Call " + uac.CallDescriptor.Uri + " should not be in a progress state after a cancel. Cancel again."); uac.Cancel(); } else { CallProgress(progressResponse.Status, progressResponse.ReasonPhrase, null, progressResponse.Header.ContentType, progressResponse.Body, uac); } } catch (Exception excp) { logger.Error("Exception ForkCall UACCallProgress. " + excp); } }
/// <summary> /// Event handler for a client call (one initiated by us) being answered. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="sipResponse">The INVITE success response.</param> private async Task ClientCallAnsweredHandlerAsync(ISIPClientUserAgent uac, SIPResponse sipResponse) { if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { // Only set the remote RTP end point if there hasn't already been a packet received on it. await MediaSession.OfferAnswered(sipResponse.Body).ConfigureAwait(false); Dialogue.DialogueState = SIPDialogueStateEnum.Confirmed; logger.LogInformation($"Call attempt to {m_uac.CallDescriptor.Uri} was answered."); ClientCallAnswered?.Invoke(uac, sipResponse); } else { logger.LogDebug($"Call attempt was answered with failure response {sipResponse.ShortDescription}."); ClientCallFailed?.Invoke(uac, sipResponse.ReasonPhrase); CallEnded(); } }
/*private void UACCallTrying(ISIPClientUserAgent uac, SIPResponse sipResponse) * { * try * { * // Test for the custom multiple redirect response. * if (sipResponse.Status == SIPResponseStatusCodesEnum.MultipleRedirect) * { * ProcessRedirect(uac, sipResponse); * } * } * catch (Exception excp) * { * logger.Error("Exception ForkCall UACCallTrying. " + excp.Message); * } * }*/ /// <summary> /// This event occurs if it was not possible to initiate a call to the destination specified in the forwarded call. An example /// would be an unresolvable hostname in the destination URI. /// </summary> /// <param name="sipSwitchCall"></param> /// <param name="errorMessage"></param> private void UACCallFailed(ISIPClientUserAgent uac, string errorMessage) { lock (m_switchCalls) { m_switchCalls.Remove(uac); } m_lastFailureStatus = SIPResponseStatusCodesEnum.TemporarilyUnavailable; m_lastFailureReason = errorMessage; if (m_switchCallTransactions != null && uac.ServerTransaction != null) { m_switchCallTransactions.Add(uac.ServerTransaction); } uac.CallAnswered -= UACCallAnswered; uac.CallFailed -= UACCallFailed; uac.CallRinging -= UACCallProgress; CallLegCompleted(); }
private void Uac_CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { logger.Debug($"{ prefix } Call answered; { sipResponse.StatusCode } { sipResponse.Status }"); switch (sipResponse.StatusCode) { case 404: logger.Error($"{ prefix } Received 404 Not Found from remote endpoint"); break; case 486: // Busy logger.Error($"{ prefix } Received 486 Remote endpoint is busy; try again later"); break; case 488: // Possible audio format issue logger.Error($"{ prefix } Received 488 Not Acceptable from remote endpoint; check audio format"); break; case 503: // Check Twilio service and geo-permissions logger.Error($"{ prefix } Received 503 Service Unavailable from remote endpoint; check service permissions"); break; case 200: if (sipResponse.Header.ContentType != SDP.SDP_MIME_CONTENTTYPE) { logger.Error($"{ prefix } Received incorrect content type"); Stop(); return; } if (sipResponse.Body.IsNullOrBlank()) { logger.Error($"{ prefix } Received an empty SDP payload"); Stop(); return; } var sdp = SDP.ParseSDPDescription(sipResponse.Body); var ip = IPAddress.Parse(sdp.Connection.ConnectionAddress); var announcement = sdp.Media.Where(x => x.Media == SDPMediaTypesEnum.audio).FirstOrDefault(); if (announcement != null) { if (announcement.Port != 0) { rtpChannel.OnControlDataReceived += (b) => { logger.Debug($"{prefix} Control Data Received; {b.Length} bytes"); }; rtpChannel.OnControlSocketDisconnected += () => { logger.Debug($"{prefix} Control Socket Disconnected"); }; rtpChannel.RemoteEndPoint = new IPEndPoint(ip, announcement.Port); rtpChannel.Start(); // Send some setup parameters to punch a hole in the firewall/router rtpChannel.SendRTPRaw(new byte[] { 80, 95, 198, 88, 55, 96, 225, 141, 215, 205, 185, 242, 00 }); } else { logger.Error($"{ prefix } Remote endpoint did not specify a port number"); return; } } else { logger.Error($"{ prefix } Remote endpoint has not valid audio announcement"); return; } break; } }
/// <summary> /// An outgoing call was rejected by the remote SIP UAS on an outgoing call. /// </summary> private void CallFailed(ISIPClientUserAgent uac, string errorMessage) { StatusMessage(this, "Call failed: " + errorMessage + "."); CallFinished(); }
private void CallFailed(ISIPClientUserAgent uac, string errorMessage) { AppendTraceMessage("Call failed: " + errorMessage + "\n"); ResetToCallStartState(); }
private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { AppendTraceMessage("Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".\n"); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { SetVisibility(m_callButton, Visibility.Collapsed); SetVisibility(m_cancelButton, Visibility.Collapsed); SetVisibility(m_byeButton, Visibility.Visible); } else { ResetToCallStartState(); } }
private void CallProgress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody, ISIPClientUserAgent uac) { SIPResponse progressResponse = new SIPResponse(progressStatus, reasonPhrase, null); CallRinging(this, progressResponse); }
/// <summary> /// An outgoing call was rejected by the remote SIP UAS on an outgoing call. /// </summary> private void CallFailed(ISIPClientUserAgent uac, string errorMessage, SIPResponse failureResponse) { StatusMessage(this, "Call failed: " + errorMessage + "."); CallFinished(null); }
private void CallFailed(ISIPClientUserAgent uac, string errorMessage) { logger.Debug("AppServerDispatcher CallFailed with " + errorMessage + "."); m_activeAppServerEntry.HasFailed = true; m_activeAppServerEntry = GetActiveAppServer(); }
/*private void UACCallTrying(ISIPClientUserAgent uac, SIPResponse sipResponse) { try { // Test for the custom multiple redirect response. if (sipResponse.Status == SIPResponseStatusCodesEnum.MultipleRedirect) { ProcessRedirect(uac, sipResponse); } } catch (Exception excp) { logger.Error("Exception ForkCall UACCallTrying. " + excp.Message); } }*/ /// <summary> /// This event occurs if it was not possible to initiate a call to the destination specified in the forwarded call. An example /// would be an unresolvable hostname in the destination URI. /// </summary> /// <param name="sipSwitchCall"></param> /// <param name="errorMessage"></param> private void UACCallFailed(ISIPClientUserAgent uac, string errorMessage) { lock (m_switchCalls) { m_switchCalls.Remove(uac); } m_lastFailureStatus = SIPResponseStatusCodesEnum.TemporarilyUnavailable; m_lastFailureReason = errorMessage; if (m_switchCallTransactions != null && uac.ServerTransaction != null) { m_switchCallTransactions.Add(uac.ServerTransaction); } uac.CallAnswered -= UACCallAnswered; uac.CallFailed -= UACCallFailed; uac.CallRinging -= UACCallProgress; CallLegCompleted(); }
private void ProcessRedirect(ISIPClientUserAgent answeredUAC, SIPResponse answeredResponse) { try { SIPURI redirectURI = answeredResponse.Header.Contact[0].ContactURI; if (redirectURI == null) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect target could not be determined from redirect response, ignoring.", m_username)); } else { //string canincalDomain = m_dialPlanContext.GetCanonicalDomain_External(redirectURI.Host, false); if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.NewDialPlan) { m_dialPlanContext.ExecuteDialPlanForRedirect(answeredResponse); } else if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.Manual) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response with URI " + redirectURI.ToString() + " was not acted on as redirect mode set to manual in dial string.", m_username)); CallLegCompleted(); } else { // The redirect was not explicitly allowed so will be processed as an anonymous call. FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response to " + redirectURI.ToString() + " accepted.", m_username)); var redirectCalls = m_dialStringParser.GetForwardsForRedirect(redirectURI, answeredUAC.CallDescriptor); //SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf(); //redirectCallDescriptor.Uri = redirectURI.ToString(); //StartNewCallAsync(redirectCallDescriptor); if (redirectCalls != null && redirectCalls.Count > 0) { foreach (var redirectCall in redirectCalls) { StartNewCallAsync(redirectCall); } } } //else if (answeredUAC.CallDescriptor.RedirectMode == SIPCallRedirectModesEnum.Replace) //{ // // In the Replace redirect mode the existing dialplan execution needs to be cancelled and the single redirect call be used to replace it. // FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response rejected as Replace mode not yet implemented.", m_username)); // CallLegCompleted(); //} //else //{ // FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response with URI " + redirectURI.ToString() + " was not acted on as not enabled in dial string.", m_username)); // CallLegCompleted(); //} // A redirect response was received. Create a new call leg(s) using the SIP URIs in the contact header of the response. //if (m_dialStringParser != null) //{ // // If there is a dial string parser available it will be used to generate a list of call destination from the redirect URI. // SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf(); // Queue<List<SIPCallDescriptor>> redirectQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, null, redirectURI.ToString(), redirectCallDescriptor.CustomHeaders, // redirectCallDescriptor.ContentType, redirectCallDescriptor.Content, null, redirectCallDescriptor.FromDisplayName, redirectCallDescriptor.FromURIUsername, redirectCallDescriptor.FromURIHost, null, CustomerServiceLevels.None); // if (redirectQueue != null && redirectQueue.Count > 0) // { // // Only the first list in the queue is used (and there should only be a single list since it's generated from a redirect SIP URI and not // // a full dial string). // List<SIPCallDescriptor> callDescriptors = redirectQueue.Dequeue(); // for (int index = 0; index < callDescriptors.Count; index++) // { // callDescriptors[index].MangleIPAddress = redirectCallDescriptor.MangleIPAddress; // callDescriptors[index].MangleResponseSDP = redirectCallDescriptor.MangleResponseSDP; // callDescriptors[index].TransferMode = redirectCallDescriptor.TransferMode; // } // Start(callDescriptors); // } // else // { // FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A redirect response to " + redirectURI.ToString() + " did not generate any new call leg destinations.", m_username)); // } //} //else //{ // FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response to " + redirectURI.ToString() + " accepted.", m_username)); // SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf(); // redirectCallDescriptor.Uri = redirectURI.ToString(); // StartNewCallAsync(redirectCallDescriptor); //} } } catch (Exception excp) { logger.Error("Exception ForkCall ProcessRedirect. " + excp.Message); } }
/// <summary> /// Event handler for a client call (one initiated by us) being answered. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="sipResponse">The INVITE success response.</param> private void ClientCallAnsweredHandler(ISIPClientUserAgent uac, SIPResponse sipResponse) => _ = ClientCallAnsweredHandlerAsync(uac, sipResponse);
private void ProcessRedirect(ISIPClientUserAgent answeredUAC, SIPResponse answeredResponse) { try { SIPURI redirectURI = answeredResponse.Header.Contact[0].ContactURI; if (redirectURI == null) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect target could not be determined from redirect response, ignoring.", m_username)); } else { // A redirect response was received. Create a new call leg(s) using the SIP URIs in the contact header of the response. if (m_dialStringParser != null) { // If there is a dial string parser available it will be used to generate a list of call destination from the redirect URI. SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf(); Queue<List<SIPCallDescriptor>> redirectQueue = m_dialStringParser.ParseDialString(DialPlanContextsEnum.Script, null, redirectURI.ToString(), redirectCallDescriptor.CustomHeaders, redirectCallDescriptor.ContentType, redirectCallDescriptor.Content, null, redirectCallDescriptor.FromDisplayName, redirectCallDescriptor.FromURIUsername, redirectCallDescriptor.FromURIHost, null); if (redirectQueue != null && redirectQueue.Count > 0) { // Only the first list in the queue is used (and there should only be a single list since it's generated from a redirect SIP URI and not // a full dial string). List<SIPCallDescriptor> callDescriptors = redirectQueue.Dequeue(); for (int index = 0; index < callDescriptors.Count; index++) { callDescriptors[index].MangleIPAddress = redirectCallDescriptor.MangleIPAddress; callDescriptors[index].MangleResponseSDP = redirectCallDescriptor.MangleResponseSDP; callDescriptors[index].TransferMode = redirectCallDescriptor.TransferMode; } Start(callDescriptors); } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A redirect response to " + redirectURI.ToString() + " did not generate any new call leg destinations.", m_username)); } } else { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Redirect response to " + redirectURI.ToString() + " accepted.", m_username)); SIPCallDescriptor redirectCallDescriptor = answeredUAC.CallDescriptor.CopyOf(); redirectCallDescriptor.Uri = redirectURI.ToString(); StartNewCallAsync(redirectCallDescriptor); } } } catch (Exception excp) { logger.Error("Exception ForkCall ProcessRedirect. " + excp.Message); } }
private void CallProgress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody, ISIPClientUserAgent uac) { try { Log("Progress response of " + progressStatus + " received on CallBack Dial" + "."); if (m_firstLegDialogue != null && !progressBody.IsNullOrBlank() && !m_firstLegEarlyMediaSet) { m_firstLegEarlyMediaSet = true; // The first leg is up and a call on the second leg has some early media that can be passed on. //m_callManager.ReInvite(m_firstLegDialogue, progressBody); } } catch (Exception excp) { logger.Error("Exception CallbackApp. " + excp.Message); } }
private void Uac_CallFailed(ISIPClientUserAgent uac, string errorMessage) { logger.Debug($"{ prefix } Call to { endpoint } failed"); uac.Cancel(); }
/// <summary> /// An outgoing call was rejected by the remote SIP UAS on an outgoing call. /// </summary> private void CallFailed(ISIPClientUserAgent uac, string errorMessage) { StatusMessage("Call failed: " + errorMessage + "."); CallFinished(); }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage(this, "Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); CallAnswer?.Invoke(this); }
/// <summary> /// A trying response has been received from the remote SIP UAS on an outgoing call. /// </summary> private void CallTrying(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage("Call trying: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); }
private void CallRinging(ISIPClientUserAgent uac, SIPResponse sipResponse) { AppendTraceMessage("Call ringing: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + ".\n"); }
private void DispatcherCallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { //logger.Debug("Dispatcher call answered, execution count = " + sipResponse.Header.UnknownHeaders[0] + "."); }
/// <summary> /// Event handler for a client call (one initiated by us) failing. /// </summary> /// <param name="uac">The client user agent used to initiate the call.</param> /// <param name="errorMessage">An error message indicating the reason for the failure.</param> private void ClientCallFailedHandler(ISIPClientUserAgent uac, string errorMessage) { logger.LogWarning($"Call attempt to {m_uac.CallDescriptor.Uri} failed with {errorMessage}."); ClientCallFailed?.Invoke(uac, errorMessage); }
public void CallProgress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody, ISIPClientUserAgent uac) { if (m_sipServerUserAgent != null && !m_isAnswered) { m_sipServerUserAgent.Progress(progressStatus, reasonPhrase, customHeaders, progressContentType, progressBody); if (uac != null && uac.CallDescriptor.RequestCallerDetails && CallerCRMDetails != null) { if (CallerCRMDetails.Pending && !m_uacWaitingForCallDetails.Contains(uac) && !m_uacCallDetailsSent.Contains(uac)) { m_uacWaitingForCallDetails.Add(uac); } else if (!CallerCRMDetails.Pending && !m_uacCallDetailsSent.Contains(uac)) { // Send the call details to the client user agent. uac.Update(CallerCRMDetails); } } } }
/// <summary> /// A ringing response has been received from the remote SIP UAS on an outgoing call. /// </summary> private void CallRinging(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage(this, "Call ringing: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); }
private void Uac_CallRinging(ISIPClientUserAgent uac, SIPResponse sipResponse) { logger.Debug($"{ prefix } Ringing ..."); }
private void UACCallAnswered(ISIPClientUserAgent answeredUAC, SIPResponse answeredResponse) { try { // Remove the current call from the pending list. lock (m_switchCalls) { m_switchCalls.Remove(answeredUAC); } if (m_switchCallTransactions != null && answeredUAC.ServerTransaction != null) { m_switchCallTransactions.Add(answeredUAC.ServerTransaction); } if (answeredResponse != null && answeredResponse.StatusCode >= 200 && answeredResponse.StatusCode <= 299) { #region 2xx final response. if (!m_callAnswered && !m_commandCancelled) { // This is the first call we've got an answer on. m_callAnswered = true; m_answeredUAC = answeredUAC; AnsweredSIPResponse = answeredResponse; SIPDialogueTransferModesEnum uasTransferMode = SIPDialogueTransferModesEnum.Default; if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.NotAllowed) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.NotAllowed; uasTransferMode = SIPDialogueTransferModesEnum.NotAllowed; } else if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.BlindPlaceCall) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.BlindPlaceCall; uasTransferMode = SIPDialogueTransferModesEnum.BlindPlaceCall; } else if (m_answeredUAC.CallDescriptor.TransferMode == SIPDialogueTransferModesEnum.PassThru) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.PassThru; uasTransferMode = SIPDialogueTransferModesEnum.PassThru; } /*else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Caller) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.NotAllowed; uasTransferMode = SIPDialogueTransferModesEnum.Allowed; } else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Callee) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.Allowed; uasTransferMode = SIPDialogueTransferModesEnum.NotAllowed; } else if (m_answeredUAC.CallDescriptor.TransferMode == SIPCallTransferModesEnum.Both) { answeredUAC.SIPDialogue.TransferMode = SIPDialogueTransferModesEnum.Allowed; uasTransferMode = SIPDialogueTransferModesEnum.Allowed; }*/ if (CallAnswered != null) { logger.Debug("Transfer mode=" + m_answeredUAC.CallDescriptor.TransferMode + "."); CallAnswered(answeredResponse.Status, answeredResponse.ReasonPhrase, null, null, answeredResponse.Header.ContentType, answeredResponse.Body, answeredUAC.SIPDialogue, uasTransferMode); } // Cancel/hangup and other calls on this leg that are still around. CancelNotRequiredCallLegs(CallCancelCause.NormalClearing); } else { // Call already answered or cancelled, hangup (send BYE). FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg " + answeredUAC.CallDescriptor.Uri + " answered but call was already answered or cancelled, hanging up.", m_username)); SIPDialogue sipDialogue = new SIPDialogue(answeredUAC.ServerTransaction, m_username, m_adminMemberId); sipDialogue.Hangup(m_sipTransport, m_outboundProxySocket); } #endregion CallLegCompleted(); } else if (answeredUAC.SIPDialogue != null) { // Google Voice calls create the dialogue without using a SIP response. if (!m_callAnswered && !m_commandCancelled) { FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg for Google Voice call to " + answeredUAC.CallDescriptor.Uri + " answered.", m_username)); // This is the first call we've got an answer on. m_callAnswered = true; m_answeredUAC = answeredUAC; if (CallAnswered != null) { CallAnswered(SIPResponseStatusCodesEnum.Ok, null, null, null, answeredUAC.SIPDialogue.ContentType, answeredUAC.SIPDialogue.RemoteSDP, answeredUAC.SIPDialogue, SIPDialogueTransferModesEnum.NotAllowed); } // Cancel/hangup and other calls on this leg that are still around. CancelNotRequiredCallLegs(CallCancelCause.NormalClearing); } else { // Call already answered or cancelled, hangup (send BYE). FireProxyLogEvent(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "Call leg for Google Voice call to " + answeredUAC.CallDescriptor.Uri + " answered but call was already answered or cancelled, hanging up.", m_username)); answeredUAC.SIPDialogue.Hangup(m_sipTransport, m_outboundProxySocket); } } else if (answeredResponse != null && answeredResponse.StatusCode >= 300 && answeredResponse.StatusCode <= 399) { ProcessRedirect(answeredUAC, answeredResponse); } else if (answeredResponse != null) { // This call leg failed, record the failure status and reason. m_lastFailureStatus = answeredResponse.Status; m_lastFailureReason = answeredResponse.ReasonPhrase; if (m_switchCallTransactions != null && answeredUAC.ServerTransaction != null) { m_switchCallTransactions.Add(answeredUAC.ServerTransaction); } CallLegCompleted(); } } catch (Exception excp) { logger.Error("Exception ForkCall UACCallAnswered. " + excp); } }
public void CallProgress(SIPResponseStatusCodesEnum progressStatus, string reasonPhrase, string[] customHeaders, string progressContentType, string progressBody, ISIPClientUserAgent uac) { if (!m_isAnswered) { m_sipServerUserAgent.Progress(progressStatus, reasonPhrase, customHeaders, progressContentType, progressBody); if (uac != null && uac.CallDescriptor.RequestCallerDetails && CallerCRMDetails != null) { if (CallerCRMDetails.Pending && !m_uacWaitingForCallDetails.Contains(uac) && !m_uacCallDetailsSent.Contains(uac)) { m_uacWaitingForCallDetails.Add(uac); } else if (!CallerCRMDetails.Pending && !m_uacCallDetailsSent.Contains(uac)) { // Send the call details to the client user agent. uac.Update(CallerCRMDetails); } } } }
/// <summary> /// An outgoing call was successfully answered. /// </summary> /// <param name="uac">The local SIP user agent client that initiated the call.</param> /// <param name="sipResponse">The SIP answer response received from the remote party.</param> private void CallAnswered(ISIPClientUserAgent uac, SIPResponse sipResponse) { StatusMessage("Call answered: " + sipResponse.StatusCode + " " + sipResponse.ReasonPhrase + "."); if (sipResponse.StatusCode >= 200 && sipResponse.StatusCode <= 299) { if(sipResponse.Header.ContentType != _sdpMimeContentType) { // Payload not SDP, I don't understand :(. StatusMessage("Call was hungup as the answer response content type was not recognised: " + sipResponse.Header.ContentType + ". :("); Hangup(); } else if(sipResponse.Body.IsNullOrBlank()) { // They said SDP but didn't give me any :(. StatusMessage("Call was hungup as the answer response had an empty SDP payload. :("); Hangup(); } SDP sdpAnswer = SDP.ParseSDPDescription(sipResponse.Body); System.Diagnostics.Debug.WriteLine(sipResponse.Body); _mediaManager.SetRemoteSDP(sdpAnswer); CallAnswer(); } else { CallFinished(); } }