Exemplo n.º 1
0
        /// <summary>
        /// Answers the call request contained in the user agent server parameter. Note the
        /// <see cref="AcceptCall(SIPRequest)"/> method should be used to create the user agent server.
        /// Any existing call will be hungup.
        /// </summary>
        /// <param name="uas">The user agent server holding the pending call to answer.</param>
        /// <param name="mediaSession">The media session used for this call</param>
        /// <param name="customHeaders">Custom SIP-Headers to use in Answer.</param>
        public async Task Answer(SIPServerUserAgent uas, IMediaSession mediaSession, string[] customHeaders)
        {
            // This call is now taking over any existing call.
            if (IsCallActive)
            {
                Hangup();
            }
            else if (uas.IsCancelled)
            {
                logger.LogDebug("The incoming call has been cancelled.");
                mediaSession?.Close("call cancelled");
            }
            else
            {
                m_cts = new CancellationTokenSource();
                var sipRequest = uas.ClientTransaction.TransactionRequest;

                MediaSession             = mediaSession;
                MediaSession.OnRtpEvent += OnRemoteRtpEvent;
                //MediaSession.OnRtpClosed += (reason) => Hangup();
                MediaSession.OnRtpClosed += (reason) =>
                {
                    if (!MediaSession.IsClosed)
                    {
                        logger.LogWarning($"RTP channel was closed with reason {reason}.");
                    }
                };

                SDP remoteSdp = SDP.ParseSDPDescription(sipRequest.Body);
                MediaSession.setRemoteDescription(new RTCSessionDescription {
                    sdp = remoteSdp, type = RTCSdpType.offer
                });;

                var sdpAnswer = await MediaSession.createAnswer(null).ConfigureAwait(false);

                MediaSession.setLocalDescription(new RTCSessionDescription {
                    sdp = sdpAnswer, type = RTCSdpType.answer
                });

                await MediaSession.Start().ConfigureAwait(false);

                m_uas = uas;
                m_uas.Answer(m_sdpContentType, sdpAnswer.ToString(), null, SIPDialogueTransferModesEnum.Default, customHeaders);
                Dialogue.DialogueState = SIPDialogueStateEnum.Confirmed;
            }
        }
Exemplo n.º 2
0
        /// <summary>
        /// Answers the call request contained in the user agent server parameter. Note the
        /// <see cref="AcceptCall(SIPRequest)"/> method should be used to create the user agent server.
        /// Any existing call will be hungup.
        /// </summary>
        /// <param name="uas">The user agent server holding the pending call to answer.</param>
        /// <param name="mediaSession">The media session used for this call</param>
        /// <param name="customHeaders">Custom SIP-Headers to use in Answer.</param>
        public async Task Answer(SIPServerUserAgent uas, IMediaSession mediaSession, string[] customHeaders)
        {
            // This call is now taking over any existing call.
            if (IsCallActive)
            {
                Hangup();
            }
            else if (uas.IsCancelled)
            {
                logger.LogDebug("The incoming call has been cancelled.");
                mediaSession?.Close("call cancelled");
            }
            else
            {
                m_cts = new CancellationTokenSource();
                var sipRequest = uas.ClientTransaction.TransactionRequest;

                MediaSession             = mediaSession;
                MediaSession.OnRtpEvent += OnRemoteRtpEvent;
                //MediaSession.OnRtpClosed += (reason) => Hangup();
                MediaSession.OnRtpClosed += (reason) =>
                {
                    if (!MediaSession.IsClosed)
                    {
                        logger.LogWarning($"RTP channel was closed with reason {reason}.");
                    }
                };

                string sdp = null;

                if (!String.IsNullOrEmpty(sipRequest.Body))
                {
                    // The SDP offer was included in the INVITE request.
                    SDP remoteSdp = SDP.ParseSDPDescription(sipRequest.Body);
                    MediaSession.setRemoteDescription(new RTCSessionDescription {
                        sdp = remoteSdp, type = RTCSdpType.offer
                    });

                    var sdpAnswer = await MediaSession.createAnswer(null).ConfigureAwait(false);

                    if (sdpAnswer == null)
                    {
                        logger.LogWarning($"Could not generate an SDP answer.");
                        m_uas.Reject(SIPResponseStatusCodesEnum.NotAcceptable, null);
                        return;
                    }
                    else
                    {
                        MediaSession.setLocalDescription(new RTCSessionDescription {
                            sdp = sdpAnswer, type = RTCSdpType.answer
                        });
                        sdp = sdpAnswer.ToString();
                    }
                }
                else
                {
                    // No SDP offer was included in the INVITE request need to wait for the ACK.
                    RTCOfferOptions offerOptions = new RTCOfferOptions {
                        RemoteSignallingAddress = sipRequest.RemoteSIPEndPoint.GetIPEndPoint().Address
                    };
                    var sdpOffer = await MediaSession.createOffer(offerOptions).ConfigureAwait(false);

                    if (sdpOffer == null)
                    {
                        // This shouldn't occur unless we're unable to create an audio/video track.
                        logger.LogWarning($"Could not generate an SDP answer.");
                        m_uas.Reject(SIPResponseStatusCodesEnum.NotAcceptable, null);
                        return;
                    }
                    else
                    {
                        MediaSession.setLocalDescription(new RTCSessionDescription {
                            sdp = sdpOffer, type = RTCSdpType.offer
                        });
                        sdp = sdpOffer.ToString();
                    }
                }

                m_uas = uas;

                // In cases where the initial INVITE did not contain an SDP offer the action sequence is:
                // - INVITE with no SDP offer received,
                // - Reply with OK and an SDP offer,
                // - Wait for ACK with SDP answer.
                TaskCompletionSource <SIPDialogue> dialogueCreatedTcs = new TaskCompletionSource <SIPDialogue>(TaskCreationOptions.RunContinuationsAsynchronously);
                m_uas.OnDialogueCreated += (dialogue) => dialogueCreatedTcs.TrySetResult(dialogue);

                m_uas.Answer(m_sdpContentType, sdp, null, SIPDialogueTransferModesEnum.Default, customHeaders);

                await Task.WhenAny(dialogueCreatedTcs.Task, Task.Delay(WAIT_DIALOG_TIMEOUT)).ConfigureAwait(false);

                if (Dialogue != null)
                {
                    if (MediaSession.remoteDescription == null || MediaSession.remoteDescription.sdp == null)
                    {
                        // If the initial INVITE did not contain an offer then the remote description will not yet be set.
                        var remoteSDP = SDP.ParseSDPDescription(Dialogue.RemoteSDP);
                        MediaSession.setRemoteDescription(new RTCSessionDescription {
                            sdp = remoteSDP, type = RTCSdpType.answer
                        });
                    }

                    Dialogue.DialogueState = SIPDialogueStateEnum.Confirmed;

                    await MediaSession.Start().ConfigureAwait(false);
                }
                else
                {
                    logger.LogWarning("The attempt to answer a call failed as the dialog was not created. The likely cause is the ACK not being received in time.");

                    MediaSession.Close("dialog creation failed");
                    Hangup();
                }
            }
        }