/// <summary>
        /// An answer on a blind transfer means the remote end of the dialogue being replaced should be re-invited and then the replaced dialogue
        /// should be hungup.
        /// </summary>
        /// <param name="contentType"></param>
        /// <param name="body"></param>
        /// <param name="toTag"></param>
        /// <param name="answeredDialogue"></param>
        /// <param name="transferMode"></param>
        /// <returns></returns>
        public SIPDialogue Answer(string contentType, string body, string toTag, SIPDialogue answeredDialogue,
                                  SIPDialogueTransferModesEnum transferMode)
        {
            try
            {
                if (m_answered)
                {
                    answeredDialogue.Hangup(m_sipTransport, m_outboundProxy);
                }
                else
                {
                    m_answered = true;

                    UASStateChanged?.Invoke(this, SIPResponseStatusCodesEnum.Ok, null);

                    BlindTransfer_External(m_dialogueToReplace, m_oppositeDialogue, answeredDialogue);
                }

                TransactionComplete.Invoke(this);
                return(null);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransferServerUserAgent Answer. " + excp.Message);
                throw;
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// An answer on a blind transfer means the remote end of the dialogue being replaced should be re-invited and then the replaced dialogue
        /// should be hungup.
        /// </summary>
        /// <param name="contentType"></param>
        /// <param name="body"></param>
        /// <param name="toTag"></param>
        /// <param name="answeredDialogue"></param>
        /// <param name="transferMode"></param>
        /// <returns></returns>
        public SIPDialogue Answer(string contentType, string body, string toTag, SIPDialogue answeredDialogue, SIPDialogueTransferModesEnum transferMode)
        {
            try
            {
                if (m_answered)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A blind transfer received an answer on an already answered call, hanging up dialogue.", m_owner));
                    answeredDialogue.Hangup(m_sipTransport, m_outboundProxy);
                }
                else
                {
                    m_answered = true;
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A blind transfer received an answer.", m_owner));

                    if (UASStateChanged != null)
                    {
                        UASStateChanged(this, SIPResponseStatusCodesEnum.Ok, null);
                    }

                    BlindTransfer_External(m_dialogueToReplace, m_oppositeDialogue, answeredDialogue);
                }

                return(null);
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransferServerUserAgent Answer. " + excp.Message);
                throw;
            }
        }
Exemplo n.º 3
0
        private void HangupDialogue(SIPDialogue dialogue, string hangupCause, bool sendBye)
        {
            if (dialogue.CDRId != Guid.Empty)
            {
                CDR cdr = m_cdrDataLayer.Get(dialogue.CDRId);
                if (cdr != null)
                {
                    //cdr.BridgeID = dialogue.BridgeId;
                    //cdr.Hungup(hangupCause);
                    m_cdrDataLayer.Hangup(cdr.ID, hangupCause);
                }
                else
                {
                    logger.LogWarning("CDR could not be found for remote dialogue in SIPCallManager CallHungup.");
                }
            }
            else
            {
                logger.LogWarning("There was no CDR attached to orphaned dialogue in SIPCallManager CallHungup.");
            }

            if (sendBye)
            {
                dialogue.Hangup(m_sipTransport, m_outboundProxy);
                OnCallHungup?.Invoke(dialogue);
            }

            m_sipCallDataLayer.Delete(dialogue.Id);
        }
Exemplo n.º 4
0
        private void HangupDialogue(SIPDialogue dialogue, string hangupCause, bool sendBye)
        {
            if (dialogue.CDRId != Guid.Empty)
            {
                CDR cdr = m_cdrDataLayer.Get(dialogue.CDRId);
                if (cdr != null)
                {
                    //cdr.BridgeID = dialogue.BridgeId;
                    //cdr.Hungup(hangupCause);
                    m_cdrDataLayer.Hangup(cdr.ID, hangupCause);
                }
                else
                {
                    logger.LogWarning("CDR could not be found for remote dialogue in SIPCallManager CallHungup.");
                }
            }
            else
            {
                logger.LogWarning("There was no CDR attached to orphaned dialogue in SIPCallManager CallHungup.");
            }

            if (sendBye)
            {
                // In order to help cope with IPv4 NAT's apply some logic to determine if the Contact header URI looks likely
                // to fail which in turn would result in any in-dialgoue requests not being delivered.
                //var target = dialogue.RemoteTarget;
                //var mangledTarget = SIPURI.Mangle(target, dialogue.RemoteSIPEndPoint?.GetIPEndPoint());
                //if (mangledTarget != null)
                //{
                //    logger.LogDebug($"SIPCallManager adjusting BYE target from {target} to {mangledTarget}.");
                //    target = mangledTarget;
                //}

                //dialogue.Hangup(m_sipTransport, m_outboundProxy, target);

                dialogue.Hangup(m_sipTransport, dialogue.RemoteSIPEndPoint);

                OnCallHungup?.Invoke(dialogue);
            }

            m_sipCallDataLayer.Delete(dialogue.Id);
        }
Exemplo n.º 5
0
        /// <summary>
        /// Establishes a new call with the client end tied to the proxy. Since the proxy will not be sending any audio the idea is that once
        /// the call is up it should be re-INVITED off somewhere else pronto to avoid the callee sitting their listening to dead air.
        /// </summary>
        /// <param name="dest1">The dial string of the first call to place.</param>
        /// <param name="dest2">The dial string of the second call to place.</param>
        /// <param name="delaySeconds">Delay in seconds before placing the first call. Gives the user a chance to hangup their phone if they are calling themselves back.</param>
        /// <param name="ringTimeoutLeg1">The ring timeout for the first call leg, If 0 the max timeout will be used.</param>
        /// <param name="ringTimeoutLeg1">The ring timeout for the second call leg, If 0 the max timeout will be used.</param>
        /// <param name="customHeadersCallLeg1">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the first call leg.</param>
        /// /// <param name="customHeadersCallLeg2">A | delimited string that contains a list of custom SIP headers to add to the INVITE request sent for the second call leg.</param>
        /// <returns>The result of the call.</returns>
        public void Callback(string dest1, string dest2, int delaySeconds, int ringTimeoutLeg1, int ringTimeoutLeg2, string customHeadersCallLeg1, string customHeadersCallLeg2)
        {
            var ts = new CancellationTokenSource();
            CancellationToken ct = ts.Token;

            try
            {
                if (delaySeconds > 0)
                {
                    delaySeconds = (delaySeconds > MAXCALLBACK_DELAY_SECONDS) ? MAXCALLBACK_DELAY_SECONDS : delaySeconds;
                    Log("Callback app delaying by " + delaySeconds + "s.");
                    Thread.Sleep(delaySeconds * 1000);
                }

                Log("Callback app commencing first leg to " + dest1 + ".");

                SIPEndPoint defaultUDPEP = m_sipTransport.GetDefaultSIPEndPoint(SIPProtocolsEnum.udp);

                SIPRequest firstLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), null);
                ForkCall   firstLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null);
                m_firstLegDialogue = Dial(firstLegCall, dest1, ringTimeoutLeg1, 0, firstLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg1));
                if (m_firstLegDialogue == null)
                {
                    Log("The first call leg to " + dest1 + " was unsuccessful.");
                    return;
                }

                // Persist the dialogue to the database so any hangup can be detected.
                m_sipDialoguePersistor.Add(new SIPDialogueAsset(m_firstLegDialogue));

                SDP    firstLegSDP       = SDP.ParseSDPDescription(m_firstLegDialogue.RemoteSDP);
                string call1SDPIPAddress = firstLegSDP.Connection.ConnectionAddress;
                int    call1SDPPort      = firstLegSDP.Media[0].Port;
                Log("The first call leg to " + dest1 + " was successful, audio socket=" + call1SDPIPAddress + ":" + call1SDPPort + ".");

                Log("Callback app commencing second leg to " + dest2 + ".");

                SIPRequest secondLegDummyInviteRequest = GetCallbackInviteRequest(defaultUDPEP.GetIPEndPoint(), m_firstLegDialogue.RemoteSDP);
                ForkCall   secondLegCall = new ForkCall(m_sipTransport, Log_External, m_callManager.QueueNewCall, null, m_username, m_adminMemberId, m_outboundProxy, m_callManager, null);

                Task.Factory.StartNew(() =>
                {
                    while (true)
                    {
                        Thread.Sleep(CHECK_FIRST_LEG_FOR_HANGUP_PERIOD);

                        Console.WriteLine("Checking if first call leg is still up...");

                        if (ct.IsCancellationRequested)
                        {
                            Console.WriteLine("Checking first call leg task was cancelled.");
                            break;
                        }
                        else
                        {
                            // Check that the first call leg hasn't been hung up.
                            var dialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id);
                            if (dialog == null)
                            {
                                Console.WriteLine("First call leg has been hungup.");

                                // The first call leg has been hungup while waiting for the second call.
                                Log("The first call leg was hungup while the second call leg was waiting for an answer.");
                                secondLegCall.CancelNotRequiredCallLegs(CallCancelCause.ClientCancelled);
                                break;
                            }
                        }
                    }

                    Console.WriteLine("Checking first call leg task finished...");
                }, ct);

                SIPDialogue secondLegDialogue = Dial(secondLegCall, dest2, ringTimeoutLeg2, 0, secondLegDummyInviteRequest, SIPCallDescriptor.ParseCustomHeaders(customHeadersCallLeg2));

                ts.Cancel();

                if (secondLegDialogue == null)
                {
                    Log("The second call leg to " + dest2 + " was unsuccessful.");
                    m_firstLegDialogue.Hangup(m_sipTransport, m_outboundProxy);
                    return;
                }

                // Check that the first call leg hasn't been hung up.
                var firstLegDialog = m_sipDialoguePersistor.Get(m_firstLegDialogue.Id);
                if (firstLegDialog == null)
                {
                    // The first call leg has been hungup while waiting for the second call.
                    Log("The first call leg was hungup while waiting for the second call leg.");
                    secondLegDialogue.Hangup(m_sipTransport, m_outboundProxy);
                    return;
                }

                SDP    secondLegSDP      = SDP.ParseSDPDescription(secondLegDialogue.RemoteSDP);
                string call2SDPIPAddress = secondLegSDP.Connection.ConnectionAddress;
                int    call2SDPPort      = secondLegSDP.Media[0].Port;
                Log("The second call leg to " + dest2 + " was successful, audio socket=" + call2SDPIPAddress + ":" + call2SDPPort + ".");

                // Persist the second leg dialogue and update the bridge ID on the first call leg.
                Guid bridgeId = Guid.NewGuid();
                secondLegDialogue.BridgeId = bridgeId;
                m_sipDialoguePersistor.Add(new SIPDialogueAsset(secondLegDialogue));
                m_sipDialoguePersistor.UpdateProperty(firstLegDialog.Id, "BridgeID", bridgeId.ToString());

                //m_callManager.CreateDialogueBridge(m_firstLegDialogue, secondLegDialogue, m_username);

                Log("Re-inviting Callback dialogues to each other.");

                m_callManager.ReInvite(m_firstLegDialogue, secondLegDialogue);
                //m_callManager.ReInvite(secondLegDialogue, m_firstLegDialogue.RemoteSDP);

                SendRTPPacket(call2SDPIPAddress + ":" + call2SDPPort, call1SDPIPAddress + ":" + call1SDPPort);
                SendRTPPacket(call1SDPIPAddress + ":" + call1SDPPort, call2SDPIPAddress + ":" + call2SDPPort);
            }
            catch (Exception excp)
            {
                logger.Error("Exception CallbackApp. " + excp);
                Log("Exception in Callback. " + excp);
            }
            finally
            {
                if (!ts.IsCancellationRequested)
                {
                    ts.Cancel();
                }
            }
        }
Exemplo n.º 6
0
        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);
            }
        }
        /// <summary>
        /// An answer on a blind transfer means the remote end of the dialogue being replaced should be re-invited and then the replaced dialogue 
        /// should be hungup.
        /// </summary>
        /// <param name="contentType"></param>
        /// <param name="body"></param>
        /// <param name="toTag"></param>
        /// <param name="answeredDialogue"></param>
        /// <param name="transferMode"></param>
        /// <returns></returns>
        public SIPDialogue Answer(string contentType, string body, string toTag, SIPDialogue answeredDialogue, SIPDialogueTransferModesEnum transferMode)
        {
            try
            {
                if (m_answered)
                {
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A blind transfer received an answer on an already answered call, hanging up dialogue.", m_owner));
                    answeredDialogue.Hangup(m_sipTransport, m_outboundProxy);
                }
                else
                {
                    m_answered = true;
                    Log_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.AppServer, SIPMonitorEventTypesEnum.DialPlan, "A blind transfer received an answer.", m_owner));

                    if (UASStateChanged != null)
                    {
                        UASStateChanged(this, SIPResponseStatusCodesEnum.Ok, null);
                    }

                    BlindTransfer_External(m_dialogueToReplace, m_oppositeDialogue, answeredDialogue);
                }

                return null;
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPTransferServerUserAgent Answer. " + excp.Message);
                throw;
            }
        }